Esempio n. 1
0
    def construct_circuit(self,
                          k: int,
                          measurement: bool = False) -> QuantumCircuit:
        r"""Construct the circuit Q^k A \|0>.

        The A operator is the unitary specifying the QAE problem and Q the associated Grover
        operator.

        Args:
            k: The power of the Q operator.
            measurement: Boolean flag to indicate if measurements should be included in the
                circuits.

        Returns:
            The circuit Q^k A \|0>.
        """
        if self.state_preparation is not None:  # using circuits, not CircuitFactory
            num_qubits = max(self.state_preparation.num_qubits,
                             self.grover_operator.num_qubits)
            circuit = QuantumCircuit(num_qubits, name='circuit')

            if self._initial_state is not None:
                circuit.compose(self._initial_state, inplace=True)

            # add classical register if needed
            if measurement:
                c = ClassicalRegister(len(self.objective_qubits))
                circuit.add_register(c)

            # add A operator
            circuit.compose(self.state_preparation, inplace=True)

            # add Q^k
            if k != 0:
                circuit.compose(self.grover_operator.power(k), inplace=True)
        else:  # deprecated CircuitFactory
            q = QuantumRegister(self.a_factory.num_target_qubits, 'q')
            circuit = QuantumCircuit(q, name='circuit')

            # get number of ancillas and add register if needed
            num_ancillas = np.maximum(self.a_factory.required_ancillas(),
                                      self.q_factory.required_ancillas())

            q_aux = None
            # pylint: disable=comparison-with-callable
            if num_ancillas > 0:
                q_aux = QuantumRegister(num_ancillas, 'aux')
                circuit.add_register(q_aux)

            # add classical register if needed
            if measurement:
                c = ClassicalRegister(1)
                circuit.add_register(c)

            # add A operator
            self.a_factory.build(circuit, q, q_aux)

            # add Q^k
            if k != 0:
                self.q_factory.build_power(circuit, q, k, q_aux)

            # add optional measurement
        if measurement:
            # real hardware can currently not handle operations after measurements, which might
            # happen if the circuit gets transpiled, hence we're adding a safeguard-barrier
            circuit.barrier()
            circuit.measure(self.objective_qubits, *c)

        return circuit
Esempio n. 2
0
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, execute, Aer
""" 
"""

q = QuantumRegister(12)
c = ClassicalRegister(12)
cmp_ancilla = QuantumRegister(1)
cmp_res = QuantumRegister(1)
sc = ClassicalRegister(1)
circ = QuantumCircuit()
circ.add_register(q)
circ.add_register(cmp_ancilla)
circ.add_register(cmp_res)
circ.add_register(c)
circ.add_register(sc)

mem_ancilla = QuantumRegister(1)  # anclia
mem_output = QuantumRegister(1)  # output
mem_output_c = ClassicalRegister(1)
circ.add_register(mem_ancilla, mem_output, mem_output_c)

oracle_q = QuantumRegister(1)
oracle_c = ClassicalRegister(1)
circ.add_register(oracle_q, oracle_c)


def mem(mem_input):
    circ.barrier()
    # cmp_res OR previous_output > ancila
    circ.cx(mem_input, mem_ancilla)
    circ.cx(mem_output, mem_ancilla)
Esempio n. 3
0
def Root(Pass, Input):
    m = len(Pass)
    output = 0

    if m >= n:

        qc = QuantumCircuit()

        q = QuantumRegister(3 + 2 * m, 'q')
        c = ClassicalRegister(1, 'c')

        qc.add_register(q)
        qc.add_register(c)

        qc.u3(np.pi * Input, 0, 0, q[0])
        qc.u3(np.pi / Rand, 0, 0, q[1])
        for i in range(n):
            qc.u3(np.pi - Pass_R[i], 0, 0, q[3 + i])

        for i in range(m):
            qc.u3(Pass[i], 0, 0, q[3 + i])

        qc.mct(q[3:3 + m], q[2], q[3 + m:3 + 2 * m])
        qc.cswap(q[2], q[0], q[1])
        qc.measure(q[1], c[0])

        Shots = 1
        backend = Aer.get_backend('qasm_simulator')
        job = execute(qc, backend=backend, shots=Shots)
        job_result = job.result()
        output = (list(job_result.get_counts(qc).keys())[0])

        #print(job_result.get_counts(qc))
    if m < n:

        qc = QuantumCircuit()

        q = QuantumRegister(3 + 2 * n, 'q')
        c = ClassicalRegister(1, 'c')

        qc.add_register(q)
        qc.add_register(c)

        qc.x(q[0])
        qc.u3(np.pi / Rand, 0, 0, q[1])
        for i in range(n):
            qc.u3(np.pi - Pass_R[i], 0, 0, q[3 + i])

        for i in range(m):
            qc.u3(Pass[i], 0, 0, q[3 + i])

        qc.mct(q[3:3 + n], q[2], q[3 + n:3 + 2 * n])
        qc.cswap(q[2], q[0], q[1])
        qc.measure(q[1], c[0])

        Shots = 1
        backend = Aer.get_backend('qasm_simulator')
        job = execute(qc, backend=backend, shots=Shots)
        job_result = job.result()
        output = (list(job_result.get_counts(qc).keys())[0])

        #print(job_result.get_counts(qc))

    return output
Esempio n. 4
0
def get_controlled_circuit(circuit,
                           ctl_qubit,
                           tgt_circuit=None,
                           use_basis_gates=True):
    """
    Construct the controlled version of a given circuit.

    Args:
        circuit (QuantumCircuit) : the base circuit
        ctl_qubit (indexed QuantumRegister) : the control qubit to use
        tgt_circuit (QuantumCircuit) : the target controlled circuit to be modified in-place
        use_basis_gates (bool) : boolean flag to indicate whether or not only basis gates should be used

    Return:
        a QuantumCircuit object with the base circuit being controlled by ctl_qubit
    """
    if tgt_circuit is not None:
        qc = tgt_circuit
    else:
        qc = QuantumCircuit()

    # get all the qubits and clbits
    qregs = circuit.qregs
    qubits = []
    for qreg in qregs:
        if not qc.has_register(qreg):
            qc.add_register(qreg)
        qubits.extend(qreg)
    cregs = circuit.cregs
    clbits = []
    for creg in cregs:
        if not qc.has_register(creg):
            qc.add_register(creg)
        clbits.extend(creg)

    # get all operations from compiled circuit
    unroller = Unroller(basis=['u1', 'u2', 'u3', 'cx', 'id'])
    pm = PassManager(passes=[unroller])
    ops = compiler.transpile(circuit,
                             BasicAer.get_backend('qasm_simulator'),
                             pass_manager=pm).data

    # process all basis gates to add control
    if not qc.has_register(ctl_qubit[0]):
        qc.add(ctl_qubit[0])
    for op in ops:
        if op[0].name == 'id':
            apply_cu3(qc,
                      0,
                      0,
                      0,
                      ctl_qubit,
                      op[1][0],
                      use_basis_gates=use_basis_gates)
        elif op[0].name == 'u1':
            apply_cu1(qc,
                      *op[0].params,
                      ctl_qubit,
                      op[1][0],
                      use_basis_gates=use_basis_gates)
        elif op[0].name == 'u2':
            apply_cu3(qc,
                      np.pi / 2,
                      *op[0].params,
                      ctl_qubit,
                      op[1][0],
                      use_basis_gates=use_basis_gates)
        elif op[0].name == 'u3':
            apply_cu3(qc,
                      *op[0].params,
                      ctl_qubit,
                      op[1][0],
                      use_basis_gates=use_basis_gates)
        elif op[0].name == 'cx':
            apply_ccx(qc, ctl_qubit, *op[1], use_basis_gates=use_basis_gates)
        elif op[0].name == 'measure':
            qc.measure(op[1], op[2])
        else:
            raise RuntimeError('Unexpected operation {}.'.format(op['name']))

    return qc
Esempio n. 5
0
    def construct_circuits(self,
                           measurement: bool = False) -> List[QuantumCircuit]:
        """Construct the Amplitude Estimation w/o QPE quantum circuits.

        Args:
            measurement: Boolean flag to indicate if measurement should be included in the circuits.

        Returns:
            A list with the QuantumCircuit objects for the algorithm.
        """
        # keep track of the Q-oracle queries
        self._ret['num_oracle_queries'] = 0
        self._circuits = []

        if self.state_preparation is not None:  # using circuits, not CircuitFactory
            num_qubits = max(self.state_preparation.num_qubits,
                             self.grover_operator.num_qubits)
            q = QuantumRegister(num_qubits, 'q')
            qc_0 = QuantumCircuit(
                q,
                name='qc_a')  # 0 applications of Q, only a single A operator

            # add classical register if needed
            if measurement:
                c = ClassicalRegister(len(self.objective_qubits))
                qc_0.add_register(c)

            qc_0.compose(self.state_preparation, inplace=True)

            for k in self._evaluation_schedule:
                qc_k = qc_0.copy(name='qc_a_q_%s' % k)

                if k != 0:
                    qc_k.compose(self.grover_operator.power(k), inplace=True)

                if measurement:
                    # real hardware can currently not handle operations after measurements,
                    # which might happen if the circuit gets transpiled, hence we're adding
                    # a safeguard-barrier
                    qc_k.barrier()
                    qc_k.measure(self.objective_qubits, *c)

                self._circuits += [qc_k]
        else:  # using deprecated CircuitFactory
            # construct first part of circuit
            q = QuantumRegister(self.a_factory.num_target_qubits, 'q')
            qc_0 = QuantumCircuit(
                q,
                name='qc_a')  # 0 applications of Q, only a single A operator

            # get number of ancillas
            num_ancillas = np.maximum(self.a_factory.required_ancillas(),
                                      self.q_factory.required_ancillas())

            q_aux = None
            # pylint: disable=comparison-with-callable
            if num_ancillas > 0:
                q_aux = QuantumRegister(num_ancillas, 'aux')
                qc_0.add_register(q_aux)

            # add classical register if needed
            if measurement:
                c = ClassicalRegister(1)
                qc_0.add_register(c)

            self.a_factory.build(qc_0, q, q_aux)

            for k in self._evaluation_schedule:
                qc_k = qc_0.copy(name='qc_a_q_%s' % k)

                if k != 0:
                    self.q_factory.build_power(qc_k, q, k, q_aux)

                if measurement:
                    # real hardware can currently not handle operations after measurements,
                    # which might happen if the circuit gets transpiled, hence we're adding
                    # a safeguard-barrier
                    qc_k.barrier()
                    qc_k.measure(q[self.i_objective], c[0])

                self._circuits += [qc_k]

        return self._circuits
class TruthTableOracle(Oracle):
    """ Truth Table Oracle """
    def __init__(self,
                 bitmaps: Union[str, List[str]],
                 optimization: bool = False,
                 mct_mode: str = 'basic'):
        """
        Constructor for Truth Table-based Oracle

        Args:
            bitmaps: A single binary string or a list of binary strings
                representing the desired single- and multi-value truth table.
            optimization: Boolean flag for attempting circuit optimization.
                When set, the Quine-McCluskey algorithm is used to compute the prime
                implicants of the truth table,
                and then its exact cover is computed to try to reduce the circuit.
            mct_mode: The mode to use when constructing multiple-control Toffoli.
        Raises:
            AquaError: invalid input
        """
        if isinstance(bitmaps, str):
            bitmaps = [bitmaps]

        validate_in_set(
            'mct_mode', mct_mode,
            {'basic', 'basic-dirty-ancilla', 'advanced', 'noancilla'})
        super().__init__()

        self._mct_mode = mct_mode.strip().lower()
        self._optimization = optimization

        self._bitmaps = bitmaps

        # check that the input bitmaps length is a power of 2
        if not is_power_of_2(len(bitmaps[0])):
            raise AquaError('Length of any bitmap must be a power of 2.')
        for bitmap in bitmaps[1:]:
            if not len(bitmap) == len(bitmaps[0]):
                raise AquaError('Length of all bitmaps must be the same.')
        self._nbits = int(math.log(len(bitmaps[0]), 2))
        self._num_outputs = len(bitmaps)

        self._lit_to_var = None
        self._var_to_lit = None

        esop_exprs = []
        for bitmap in bitmaps:
            esop_expr = self._get_esop_ast(bitmap)
            esop_exprs.append(esop_expr)

        self._esops = [
            ESOP(esop_expr, num_vars=self._nbits) for esop_expr in esop_exprs
        ] if esop_exprs else None

        self.construct_circuit()

    def _get_esop_ast(self, bitmap):
        v = symbols('v:{}'.format(self._nbits))
        if self._lit_to_var is None:
            self._lit_to_var = [None] + sorted(v, key=str)
        if self._var_to_lit is None:
            self._var_to_lit = dict(
                zip(self._lit_to_var[1:], range(1, self._nbits + 1)))

        def binstr_to_vars(binstr):
            return [(~v[x[1] - 1] if x[0] == '0' else v[x[1] - 1])
                    for x in zip(binstr, reversed(range(1, self._nbits + 1)))
                    ][::-1]

        if not self._optimization:
            expression = Xor(*[
                And(*binstr_to_vars(term)) for term in [
                    np.binary_repr(idx, self._nbits)
                    for idx, v in enumerate(bitmap) if v == '1'
                ]
            ])
        else:
            ones = [i for i, v in enumerate(bitmap) if v == '1']
            if not ones:
                return 'const', 0
            dcs = [
                i for i, v in enumerate(bitmap)
                if v == '*' or v == '-' or v.lower() == 'x'
            ]
            pis = get_prime_implicants(ones=ones, dcs=dcs)
            cover = get_exact_covers(ones, pis)[-1]
            clauses = []
            for c in cover:
                if len(c) == 1:
                    term = np.binary_repr(c[0], self._nbits)
                    clause = And(
                        *[v for i, v in enumerate(binstr_to_vars(term))])
                elif len(c) > 1:
                    c_or = reduce(operator.or_, c)
                    c_and = reduce(operator.and_, c)
                    _ = np.binary_repr(c_and ^ c_or, self._nbits)[::-1]
                    clause = And(*[
                        v for i, v in enumerate(
                            binstr_to_vars(np.binary_repr(c_and, self._nbits)))
                        if _[i] == '0'
                    ])
                else:
                    raise AquaError('Unexpected cover term size {}.'.format(
                        len(c)))
                if clause:
                    clauses.append(clause)
            expression = Xor(*clauses)

        ast = get_ast(self._var_to_lit, expression)
        if ast is not None:
            return ast
        else:
            return 'const', 0

    @property
    def variable_register(self):
        """ returns variable register """
        return self._variable_register

    @property
    def ancillary_register(self):
        """ returns ancillary register """
        return self._ancillary_register

    @property
    def output_register(self):
        """ returns output register """
        return self._output_register

    def construct_circuit(self):
        """ construct circuit """
        if self._circuit is not None:
            return self._circuit
        self._circuit = QuantumCircuit()
        self._output_register = QuantumRegister(self._num_outputs, name='o')
        if self._esops:
            for i, e in enumerate(self._esops):
                if e is not None:
                    ci = e.construct_circuit(
                        output_register=self._output_register,
                        output_idx=i,
                        mct_mode=self._mct_mode)
                    self._circuit += ci
            self._variable_register = self._ancillary_register = None
            for qreg in self._circuit.qregs:
                if qreg.name == 'v':
                    self._variable_register = qreg
                elif qreg.name == 'a':
                    self._ancillary_register = qreg
        else:
            self._variable_register = QuantumRegister(self._nbits, name='v')
            self._ancillary_register = None
            self._circuit.add_register(self._variable_register,
                                       self._output_register)
        return self._circuit

    def evaluate_classically(self, measurement):
        """ evaluate classical """
        assignment = [
            (var + 1) * (int(tf) * 2 - 1)
            for tf, var in zip(measurement[::-1], range(len(measurement)))
        ]
        ret = [bitmap[int(measurement, 2)] == '1' for bitmap in self._bitmaps]
        if self._num_outputs == 1:
            return ret[0], assignment
        else:
            return ret, assignment
    def construct_circuit(self):
        """Construct circuit.
            It is an implementation of Sequantial Fourier transform with only one qubit. 
        Returns:
            Dict: a dictionary with binary numbers such that are the best estimate of j/r.
            See report page 2
        """

        # Get n value used in Shor's algorithm, to know how many qubits are used
        self._n = math.ceil(math.log(self._N, 2))

        # quantum register where every gate is applied to
        self._up_qreg = QuantumRegister(1, name='up')
        # quantum register where the multiplications are made
        self._down_qreg = QuantumRegister(self._n, name='down')
        # auxiliary quantum register used in addition and multiplication
        self._aux_qreg = QuantumRegister(self._n + 2, name='aux')
        # classical register that hosts qubit's state
        self._up_cqreg = ClassicalRegister(1, name='m')

        # Create Quantum Circuit
        circuit = QuantumCircuit(self._up_qreg, self._down_qreg,
                                 self._aux_qreg, self._up_cqreg)

        # Initialize down register to 1.
        circuit.u3(np.pi, 0, np.pi, self._down_qreg[0])

        # a list that hosts the result of each measurement (0 or 1)
        # These elements are used for calculating the R'j gates
        m = []

        # a list with all the binary numbers with 2*n digits.
        # After every measurement elements are deleted
        binary_list = [
            list(i) for i in itertools.product([0, 1], repeat=2 * self._n)
        ]

        # Apply the multiplication gates as showed in
        # the report in order to create the exponentiation
        for i in range(2 * self._n - 1, -1, -1):
            print(i)
            self._controlled_multiple_mod_N(circuit, self._up_qreg[0],
                                            self._down_qreg, self._aux_qreg,
                                            int(pow(self._a, pow(2, i))))

            # Apply the Hadamard gate
            circuit.u2(0, np.pi, self._up_qreg)

            # Calculate the φ'j angle as it is written at the report
            angle = 0
            iter_j = 2 * self._n - i

            for k in range(2, iter_j + 1):
                if m[iter_j - k] == '1':
                    angle += math.pow(2, -k)

            # Apply the R'j gate.
            circuit.u1(np.pi * angle, self._up_qreg[0])

            # Add measurement
            circuit.measure(self._up_qreg, self._up_cqreg)

            # Run the circuit with a classical computer
            backend = Aer.get_backend('qasm_simulator')
            results = execute(circuit, backend=backend).result()
            counts = results.get_counts()
            #print(counts)

            # Every measurement returns a dictionary. In this case "counts"
            # e.g. counts = {'1': 512, '0':512}
            # 1 and 0 will be always the keys.
            # The following numbers depend on the measurment.
            v = list(counts.values())
            k = list(counts.keys())

            # Decide which state will be add in m[] list
            if len(counts) > 1:
                if v[0] > v[1]:
                    zero_wins = False
                    m.append(k[0])
                else:
                    zero_wins = True
                    m.append(k[1])

                # Simulations and Quantum Computers are not perfect.
                # We keep the binary numbers that they have 1 at position i
                # if state 1 is measured 128 times more than state 0, and vice versa.
                # 128 is a reference number when executing the circuit 1024 times.
                if abs(v[0] - v[1]) > 128:
                    if zero_wins:
                        binary_list = [x for x in binary_list if x[i] == 0]
                    else:
                        binary_list = [x for x in binary_list if x[i] == 1]
            else:
                # in case that the dictionary has just one element.
                # e.g. counts = {'1': 1024}
                m.append(k[0])
                binary_list = [x for x in binary_list if x[i] == int(k[0])]

            # Remove measurement and add classical register back to the circuit.
            # Quantum Computers cannot run circuits when they have measuments gates before other gates.
            circuit.remove_final_measurements()
            circuit.add_register(self._up_cqreg)

        # A dictionary that holds all the possible binary numbers for the continuing fractions.
        # Keys (Binary numbers) are in string format and their value is always 1.
        # Value is useless
        # e.g. answer = {'01001010': 1}
        answer = {}

        for x in binary_list:
            answer["".join(map(str, x))] = 1

        return answer
class RCAdder:
    """
    An n-bit ripple-carry adder can be generated using an instance of the
    RCAdder class by calling the gen_circuit() method.

    This adder circuit uses 1 ancilla qubit to add together two values
        a = a_(n-1)...a_0    and   b = b_(n-1)...a_0
    and store their sum
        s = s_n...s_0
    in the registers which initially held the b value.

    The adder circuit uses 2 + binary_len(a) + binary_len(b) qubits.
    The initial carry value is stored in the qubit at index = 0.
    The binary value of a_i is stored in the qubit at index = 2*i + 2
    The binary value of b_i is stored in the qubit at index = 2*i + 1
    The high bit, s_n, is stored in the last qubit at index = num_qubits - 1

    Attributes
    ----------
    nbits : int
        size, in bits, of the numbers the adder can handle
    nq : int
        number of qubits needed to construct the adder circuit
    a, b : int
        optional parameters to specify the numbers the adder should add.
        Will throw an exception if the length of the bitstring representations
        of a or b are greater than nbits.
    use_toffoli : bool
        Should the toffoli gate be used in the generated circuit or should it
        first be decomposed
    barriers : bool
        should barriers be included in the generated circuit
    regname : str
        optional string to name the quantum and classical registers. This
        allows for the easy concatenation of multiple QuantumCircuits.
    qr : QuantumRegister
        Qiskit QuantumRegister holding all of the quantum bits
    circ : QuantumCircuit
        Qiskit QuantumCircuit that represents the uccsd circuit
    """
    def __init__(self,
                 nbits=None,
                 a=0,
                 b=0,
                 use_toffoli=False,
                 barriers=False,
                 measure=False,
                 regname=None):

        # number of bits the adder can handle
        if nbits is None:
            raise Exception('Number of bits must be specified')
        else:
            self.nbits = nbits

        # given nbits, compute the number of qubits the adder will need
        # number of qubits = 1 ancilla for the initial carry value
        #                    + 2*nbits to hold both a and b
        #                    + 1 more qubit to hold the high bit, s_n
        self.nq = 1 + 2 * nbits + 1

        # set flags for circuit generation
        if len('{0:b}'.format(a)) > nbits or len('{0:b}'.format(b)) > nbits:
            raise Exception(
                'Binary representations of a and b must be less than or equal to nbits'
            )

        self.a = a
        self.b = b
        self.use_toffoli = use_toffoli
        self.barriers = barriers
        self.measure = measure

        # create a QuantumCircuit object
        if regname is None:
            self.qr = QuantumRegister(self.nq)
        else:
            self.qr = QuantumRegister(self.nq, name=regname)
        self.circ = QuantumCircuit(self.qr)

        # add ClassicalRegister if measure is True
        if self.measure:
            self.cr = ClassicalRegister(self.nq)
            self.circ.add_register(self.cr)

    def _initialize_value(self, indices, value):
        """
        Initialize the qubits at indices to the given value

        Parameters
        ----------
        indices : List[int]
            List of qubit indices
        value : int
            The desired initial value
        """
        binstr = '{0:b}'.format(value)
        for index, val in enumerate(reversed(binstr)):
            if val is '1':
                self.circ.x(indices[index])

    def _toffoli(self, x, y, z):
        """
        Implement the toffoli gate using 1 and 2 qubit gates
        """
        self.circ.h(z)
        self.circ.cx(y, z)
        self.circ.tdg(z)
        self.circ.cx(x, z)
        self.circ.t(z)
        self.circ.cx(y, z)
        self.circ.t(y)
        self.circ.tdg(z)
        self.circ.cx(x, z)
        self.circ.cx(x, y)
        self.circ.t(z)
        self.circ.h(z)
        self.circ.t(x)
        self.circ.tdg(y)
        self.circ.cx(x, y)

    def _MAJ(self, x, y, z):
        """
        Implement the MAJ (Majority) gate described in Cuccaro, Draper, Kutin,
        Moulton.
        """
        self.circ.cx(z, y)
        self.circ.cx(z, x)

        if self.use_toffoli:
            self.circ.ccx(x, y, z)
        else:
            # use a decomposed version of toffoli
            self._toffoli(x, y, z)

    def _UMA(self, x, y, z):
        """
        Implement the UMA (UnMajority and Add) gate described in Cuccaro,
        Draper, Kutin, Moulton.
        """
        self.circ.x(y)
        self.circ.cx(x, y)
        if self.use_toffoli:
            self.circ.ccx(x, y, z)
        else:
            # use a decomposed version of toffoli
            self._toffoli(x, y, z)
        self.circ.x(y)
        self.circ.cx(z, x)
        self.circ.cx(z, y)

    def gen_circuit(self):
        """
        Create a circuit implementing the ripple-carry adder

        Returns
        -------
        QuantumCircuit
            QuantumCircuit object of size self.nq
        """
        high_bit_index = self.nq - 1

        # initialize the a and b registers
        a_indices = [2 * i + 2 for i in range(self.nbits)]
        b_indices = [2 * i + 1 for i in range(self.nbits)]
        for index_list, value in zip([a_indices, b_indices], [self.a, self.b]):
            self._initialize_value(index_list, value)

        # compute the carry bits, c_i, in order using the MAJ ladder
        for a_i in a_indices:
            self._MAJ(a_i - 2, a_i - 1, a_i)

        # write the final carry bit value to the high bit register
        self.circ.cx(a_indices[-1], high_bit_index)

        # erase the carry bits in reverse order using the UMA ladder
        for a_i in reversed(a_indices):
            self._UMA(a_i - 2, a_i - 1, a_i)

        if self.measure:
            # measure the circuit
            self.circ.measure_all()

        return self.circ
Esempio n. 9
0
    def test_mcmt(self, num_controls, num_targets,
                  single_control_gate_function):

        if num_controls + num_targets > 10:
            return

        c = QuantumRegister(num_controls, name='c')
        o = QuantumRegister(num_targets, name='o')

        subsets = [tuple(range(i)) for i in range(num_controls + 1)]
        for subset in subsets:
            # Expecting some other modes
            for mode in ['basic']:
                self.log.debug("Subset is {0}".format(subset))
                self.log.debug("Num controls = {0}".format(num_controls))
                self.log.debug("Num targets = {0}".format(num_targets))
                self.log.debug("Gate function is {0}".format(
                    single_control_gate_function.__name__))
                self.log.debug("Mode is {0}".format(mode))
                qc = QuantumCircuit(o, c)
                # Initialize all targets to 1, just to be sure that
                # the generic gate has some effect (f.e. Z gate has no effect
                # on a 0 state)
                qc.x(o)

                if mode == 'basic':
                    if num_controls <= 1:
                        num_ancillae = 0
                    else:
                        num_ancillae = num_controls - 1
                    self.log.debug("Num ancillae is {0} ".format(num_ancillae))

                if num_ancillae > 0:
                    a = QuantumRegister(num_ancillae, name='a')
                    qc.add_register(a)

                for idx in subset:
                    qc.x(c[idx])
                qc.mcmt([c[i] for i in range(num_controls)],
                        [a[i] for i in range(num_ancillae)],
                        single_control_gate_function,
                        o,
                        mode=mode)
                for idx in subset:
                    qc.x(c[idx])

                vec = np.asarray(
                    q_execute(qc, BasicAer.get_backend(
                        'statevector_simulator')).result().get_statevector(
                            qc, decimals=16))
                # target register is initially |11...1>, with length equal to 2**(n_targets)
                vec_exp = np.array([0] * (2**(num_targets) - 1) + [1])
                if (single_control_gate_function.__name__ == "cz"):
                    # Z gate flips the last qubit only if it's applied an odd
                    # number of times
                    if (len(subset) == num_controls
                            and (num_controls % 2) == 1):
                        vec_exp[-1] = -1
                elif (single_control_gate_function.__name__ == "ch"):
                    # if all the control qubits have been activated,
                    # we repeatedly apply the kronecker product of the Hadamard
                    # with itself and then multiply the results for the original
                    # state of the target qubits
                    if (len(subset) == num_controls):
                        h = 1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])
                        h_tot = np.array([1])
                        for i in range(num_targets):
                            h_tot = np.kron(h_tot, h)
                        vec_exp = np.dot(h_tot, vec_exp)
                else:
                    raise ValueError("Gate {0} not implementend yet".format(
                        single_control_gate_function.__name__))
                # append the remaining part of the state
                vec_exp = np.concatenate(
                    (vec_exp,
                     [0] * (2**(num_controls + num_ancillae + num_targets) -
                            vec_exp.size)))
                f = state_fidelity(vec, vec_exp)
                self.assertAlmostEqual(f, 1)
Esempio n. 10
0
class Simon(QuantumAlgorithm):
    r"""
    The Simon algorithm.

    The Simon algorithm finds a hidden integer :math:`s \in \{0,1\}^n` from an oracle :math:`f_s`
    that satisfies :math:`f_s(x) = f_s(y)` if and only if :math:`y=x \oplus s` for all
    :math:`x \in \{0,1\}^n`. Thus, if :math:`s = 0\ldots 0`, i.e., the all-zero bitstring,
    then :math:`f_s` is a 1-to-1 (or, permutation) function. Otherwise, if
    :math:`s \neq 0\ldots 0`, then :math:`f_s` is a 2-to-1 function.

    Note: the :class:`~qiskit.aqua.components.oracles.TruthTableOracle` may be the easiest to use
    to create one that can be used with the Simon algorithm.
    """

    def __init__(self,
                 oracle: Oracle,
                 quantum_instance: Optional[
                     Union[QuantumInstance, BaseBackend, Backend]] = None) -> None:
        """
        Args:
            oracle: The oracle component
            quantum_instance: Quantum Instance or Backend
        """
        super().__init__(quantum_instance)

        self._oracle = oracle
        self._circuit = None
        self._ret = {}  # type: Dict[str, Any]

    def construct_circuit(self, measurement=False):
        """
        Construct the quantum circuit

        Args:
            measurement (bool): Boolean flag to indicate if
                measurement should be included in the circuit.

        Returns:
            QuantumCircuit: the QuantumCircuit object for the constructed circuit
        """

        if self._circuit is not None:
            return self._circuit

        oracle = self._oracle.construct_circuit()
        self._circuit = QuantumCircuit(*oracle.qregs)

        # preoracle hadamard gates
        self._circuit.h(self._oracle.variable_register)

        # apply oracle
        self._circuit.compose(oracle, inplace=True)

        # postoracle hadamard gates
        self._circuit.h(self._oracle.variable_register)

        # measurement circuit
        if measurement:
            measurement_cr = ClassicalRegister(len(self._oracle.variable_register), name='m')
            self._circuit.add_register(measurement_cr)
            self._circuit.measure(self._oracle.variable_register, measurement_cr)

        return self._circuit

    def _interpret_measurement(self, measurements):
        # reverse measurement bitstrings and remove all zero entry
        linear = [(k[::-1], v) for k, v in measurements.items()
                  if k != "0" * len(self._oracle.variable_register)]
        # sort bitstrings by their probabilities
        linear.sort(key=lambda x: x[1], reverse=True)

        # construct matrix
        equations = []
        for k, _ in linear:
            equations.append([int(c) for c in k])
        y = Matrix(equations)

        # perform gaussian elimination
        y_transformed = y.rref(iszerofunc=lambda x: x % 2 == 0)

        def mod(x, modulus):
            numer, denom = x.as_numer_denom()
            return numer * mod_inverse(denom, modulus) % modulus
        y_new = y_transformed[0].applyfunc(lambda x: mod(x, 2))

        # determine hidden string from final matrix
        rows, _ = y_new.shape
        hidden = [0] * len(self._oracle.variable_register)
        for r in range(rows):
            yi = [i for i, v in enumerate(list(y_new[r, :])) if v == 1]
            if len(yi) == 2:
                hidden[yi[0]] = '1'
                hidden[yi[1]] = '1'
        return "".join(str(x) for x in hidden)[::-1]

    def _run(self):
        if self._quantum_instance.is_statevector:
            qc = self.construct_circuit(measurement=False)
            result = self._quantum_instance.execute(qc)
            complete_state_vec = result.get_statevector(qc)
            variable_register_density_matrix = get_subsystem_density_matrix(
                complete_state_vec,
                range(len(self._oracle.variable_register), qc.width())
            )
            variable_register_density_matrix_diag = np.diag(variable_register_density_matrix)
            measurements = {
                np.binary_repr(idx, width=len(self._oracle.variable_register)):
                    abs(variable_register_density_matrix_diag[idx]) ** 2
                for idx in range(len(variable_register_density_matrix_diag))
                if not variable_register_density_matrix_diag[idx] == 0
            }
        else:
            qc = self.construct_circuit(measurement=True)
            measurements = self._quantum_instance.execute(qc).get_counts(qc)

        self._ret['result'] = self._interpret_measurement(measurements)
        return self._ret
    def circuits(self):

        sub_circuits = []
        sub_qubits = []
        sub_maps = []
        sub_size = []
        num_qubits = 0

        # Generate data for combination
        for sub_exp in self._experiments:

            # Generate transpiled subcircuits
            circuits = sub_exp._transpiled_circuits()

            # Add subcircuits
            sub_circuits.append(circuits)
            sub_size.append(len(circuits))

            # Sub experiment logical qubits in the combined circuits full qubits
            qubits = list(range(num_qubits, num_qubits + sub_exp.num_qubits))
            sub_qubits.append(qubits)
            # Construct mapping for the sub-experiments logical qubits to physical qubits
            # in the full combined circuits
            sub_maps.append(
                {q: qubits[i]
                 for i, q in enumerate(sub_exp.physical_qubits)})
            num_qubits += sub_exp.num_qubits

        # Generate empty joint circuits
        num_circuits = max(sub_size)
        joint_circuits = []
        for circ_idx in range(num_circuits):
            # Create joint circuit
            circuit = QuantumCircuit(self.num_qubits,
                                     name=f"parallel_exp_{circ_idx}")
            circuit.metadata = {
                "experiment_type": self._type,
                "composite_index": [],
                "composite_metadata": [],
                "composite_qubits": [],
                "composite_clbits": [],
            }
            for exp_idx in range(self._num_experiments):
                if circ_idx < sub_size[exp_idx]:
                    # Add subcircuits to joint circuit
                    sub_circ = sub_circuits[exp_idx][circ_idx]
                    num_clbits = circuit.num_clbits
                    qubits = sub_qubits[exp_idx]
                    qargs_map = sub_maps[exp_idx]
                    clbits = list(
                        range(num_clbits, num_clbits + sub_circ.num_clbits))
                    circuit.add_register(ClassicalRegister(
                        sub_circ.num_clbits))

                    # Apply transpiled subcircuit
                    # Note that this assumes the circuit was not expanded to use
                    # any qubits outside the specified physical qubits
                    for inst, qargs, cargs in sub_circ.data:
                        try:
                            mapped_qargs = [
                                circuit.qubits[qargs_map[sub_circ.find_bit(
                                    i).index]] for i in qargs
                            ]
                        except KeyError as ex:
                            # Instruction is outside physical qubits for the component
                            # experiment.
                            # This could legitimately happen if the subcircuit was
                            # explicitly scheduled during transpilation which would
                            # insert delays on all auxillary device qubits.
                            # We skip delay instructions to allow for this.
                            if inst.name == "delay":
                                continue
                            raise QiskitError(
                                "Component experiment has been transpiled outside of the "
                                "allowed physical qubits for that component. Check the "
                                "experiment is valid on the backends coupling map."
                            ) from ex
                        mapped_cargs = [
                            circuit.clbits[clbits[sub_circ.find_bit(i).index]]
                            for i in cargs
                        ]
                        circuit._append(inst, mapped_qargs, mapped_cargs)

                    # Add subcircuit metadata
                    circuit.metadata["composite_index"].append(exp_idx)
                    circuit.metadata["composite_metadata"].append(
                        sub_circ.metadata)
                    circuit.metadata["composite_qubits"].append(qubits)
                    circuit.metadata["composite_clbits"].append(clbits)

                    # Add the calibrations
                    for gate, cals in sub_circ.calibrations.items():
                        for key, sched in cals.items():
                            circuit.add_calibration(gate,
                                                    qubits=key[0],
                                                    schedule=sched,
                                                    params=key[1])

            # Add joint circuit to returned list
            joint_circuits.append(circuit)

        return joint_circuits
Esempio n. 12
0
def detailedPresentation(bit_size, tem_eve, reveal_size, com_erro, computador_real):
    global BITSIZE
    BITSIZE = bit_size

    clear_data()
    circ = QuantumCircuit()
    q = QuantumRegister(bit_size, 'q')
    c = ClassicalRegister(bit_size, 'c')
    circ.add_register(q)
    circ.add_register(c)

    print("Bem Vindo!")
    print("Esse programa ira mostrar a você o passo a passo para criar um hash seguro com o BB-84!")
    input("Pressione Enter para avançar para o Passo 1...\n")
    
    print("Passo 1: Alice prepara uma série de qubits e seleciona aleatoriamente sua polarização e base")
    step1(circ, q, c, bit_size)
    print("Qubits e bases de Alice:")
    print(Alice['generatedBits'])
    print(Alice['chosenBases'])

    input("Pressione Enter para ir para o Passo 2...\n")
    print("Passo 2: Alice envia cada Qubit para Bob (Que pode ser interceptado por Eve)")
    print("Passo 3: Bob lê os qubits enviados e guarda os resultados")

    step2_3(circ, q, c, bit_size, com_erro, computador_real, tem_eve)
    print("Bits e Bases da Eve:")
    print(Eve['measuredBits'])
    print(Eve['chosenBases'], "\n")
    print("Bits e Bases do Bob:")
    print(Bob['measuredBits'])
    print(Bob['chosenBases'])
    input("Pressione Enter para ir para o Passo 4...\n")
    
    print("Passo 4: Bob explicita para Alice quais bases ele utilizou")
    print("Passo 5: Alice fala quais bases ela utilizou na codificacao")
    step4_5(bit_size)
    print("Indices na quais Alice e Bob escolheram as mesmas bases:")
    print([i+1 for i in correct_basis_indices])
    input("Pressione Enter para ir para o Passo 6...\n")
    
    print("Passo 6: Alice e Bob desconsideram os qubits na qual suas bases nao batem (Eve faz o mesmo)")
    step6(bit_size, tem_eve)
    print("Bits e Bases que sobraram da Alice:")
    print(Alice['siftedBits'])
    print(Alice['siftedBases'], "\n")
    print("Bits e Bases que sobraram de Bob:")
    print(Bob['siftedBits'])
    print(Bob['siftedBases'], "\n")
    print("Bits e Bases que sobraram da Eve:")
    print(Eve['siftedBits'])
    print(Eve['siftedBases'], "\n")
    print("Tamanho das bases: ", len(Alice['siftedBits']))
    print("Porcentagem da redução: " + str((BITSIZE-len(Alice['siftedBits']))/BITSIZE*100) + "%")
    input("Pressione Enter para ir para o Passo 7...\n")
    
    print("Passo 7: Alice e Bob concordam em divulgar publicamente parte dos qubits medidos, de forma a calcular a taxa de erro.")
    step7(reveal_size)
    print("A taxa de erro calculada eh de: " + str(100*qber_calculated) + "%")
    print("A taxa de erro real eh de: " + str(100*qber_actual) + "%")
    print("A taxa de segurança da chave calculada eh de: " + str(100*secureKeyRate(qber_calculated)) + "%")
    print("A taxa de segurança da chave real eh de: " + str(100*secureKeyRate(qber_actual)) + "%")
    input("Pressione Enter para terminar a apresentacao...\n")
Esempio n. 13
0
class OpenQASMEngine(BasicEngine):
    """
    Engine to convert ProjectQ commands to OpenQASM using qiskit
    """
    def __init__(self,
                 process_func=_dummy_process,
                 qubit_id_mapping_redux=True):
        """
        Initialize the OpenQASMEngine object.

        Args:
            process_func (function): Function to be called periodically to
                process a qiskit.QuantumCircuit. This happens anytime a
                FlushGate gets processed by the engine.
                This function should accept a single argument:
                qiskit.QuantumCircuit.
            qubit_id_mapping_redux (bool): If True, try to allocate new Qubit
                                           IDs to the next available qreg/creg
                                           (if any), otherwise create a new
                                           qreg/creg.
                                           If False, simply create a new
                                           qreg/creg for each new Qubit ID

        Example:
            .. code-block:: python

                from projectq.cengines import MainEngine, OpenQASMEngine

                backend = OpenQASMEngine()
                eng = MainEngine(backend=backend)
                # do something ...
                eng.flush()
                qc = backend.circuit # get the corresponding Qiskit circuit

        If you have a ProjectQ program with multiple measurements (followed by
        `eng.flush()`) the OpenQASMEngine can automatically generate a list of
        circuits:

        Example:
            .. code-block:: python

                from projectq.cengines import MainEngine, OpenQASMEngine

                qc_list = []
                def process(qc):
                    qc_list.append(qc)

                backend = OpenQASMEngine(process_func=process)
                eng = MainEngine(backend=backend)
                # do something ...
                eng.flush()
                # do something ...
                eng.flush()
                qc_list # contains a list of successive circuits
        """
        BasicEngine.__init__(self)
        self._was_flushed = False
        self._openqasm_circuit = QuantumCircuit()
        self._process_func = process_func
        self._qreg_dict = dict()
        self._creg_dict = dict()
        self._qubit_id_mapping_redux = qubit_id_mapping_redux
        self._reg_index = 0
        self._available_indices = []

    @property
    def circuit(self):
        """
        Return the last OpenQASM circuit stored by this engine

        Note:
            This is essentially the quantum circuit up to the last FlushGate.
        """
        return self._openqasm_circuit

    def is_available(self, cmd):
        """
        Return true if the command can be executed.

        Args:
            cmd (Command): Command for which to check availability
        """
        gate = cmd.gate
        n_controls = get_control_count(cmd)

        is_available = False

        if gate in (Measure, Allocate, Deallocate, Barrier):
            is_available = True

        if n_controls == 0:
            if gate in (H, S, Sdag, T, Tdag, X, NOT, Y, Z, Swap):
                is_available = True
            if isinstance(gate, (Ph, R, Rx, Ry, Rz)):
                is_available = True
        elif n_controls == 1:
            if gate in (H, X, NOT, Y, Z):
                is_available = True
            if isinstance(gate, (
                    R,
                    Rz,
            )):
                is_available = True
        elif n_controls == 2:
            if gate in (X, NOT):
                is_available = True

        if not is_available:
            return False
        if not self.is_last_engine:
            return self.next_engine.is_available(cmd)
        else:
            return True

    def _store(self, cmd):
        """
        Temporarily store the command cmd.

        Translates the command and stores it the _openqasm_circuit attribute
        (self._openqasm_circuit)

        Args:
            cmd: Command to store
        """
        gate = cmd.gate
        n_controls = get_control_count(cmd)

        _ccontrolled_gates_func = {
            X: self._openqasm_circuit.ccx,
            NOT: self._openqasm_circuit.ccx,
        }
        _controlled_gates_func = {
            H: self._openqasm_circuit.ch,
            Ph: self._openqasm_circuit.cu1,
            R: self._openqasm_circuit.cu1,
            Rz: self._openqasm_circuit.crz,
            X: self._openqasm_circuit.cx,
            NOT: self._openqasm_circuit.cx,
            Y: self._openqasm_circuit.cy,
            Z: self._openqasm_circuit.cz,
            Swap: self._openqasm_circuit.cswap
        }
        _gates_func = {
            Barrier: self._openqasm_circuit.barrier,
            H: self._openqasm_circuit.h,
            Ph: self._openqasm_circuit.u1,
            S: self._openqasm_circuit.s,
            Sdag: self._openqasm_circuit.sdg,
            T: self._openqasm_circuit.t,
            Tdag: self._openqasm_circuit.tdg,
            R: self._openqasm_circuit.u1,
            Rx: self._openqasm_circuit.rx,
            Ry: self._openqasm_circuit.ry,
            Rz: self._openqasm_circuit.rz,
            X: self._openqasm_circuit.x,
            NOT: self._openqasm_circuit.x,
            Y: self._openqasm_circuit.y,
            Z: self._openqasm_circuit.z,
            Swap: self._openqasm_circuit.swap
        }

        if self._was_flushed:
            self._reset_after_flush()

        if gate == Allocate:
            add = True
            if self._qubit_id_mapping_redux and self._available_indices:
                add = False
                index = self._available_indices.pop()
            else:
                index = self._reg_index
                self._reg_index += 1

            qb_id = cmd.qubits[0][0].id
            self._qreg_dict[qb_id] = QuantumRegister(1, 'q{}'.format(index))
            self._creg_dict[qb_id] = ClassicalRegister(1, 'c{}'.format(index))

            if add:
                self._openqasm_circuit.add_register(self._qreg_dict[qb_id])
                self._openqasm_circuit.add_register(self._creg_dict[qb_id])

        elif gate == Deallocate:
            qb_id = cmd.qubits[0][0].id
            # self._openqasm_circuit.reset(self._qreg_dict[qb_id])

            if self._qubit_id_mapping_redux:
                self._available_indices.append(
                    int(self._qreg_dict[qb_id].name[1:]))
                del self._qreg_dict[qb_id]
                del self._creg_dict[qb_id]

        elif gate == Measure:
            assert len(cmd.qubits) == 1 and len(cmd.qubits[0]) == 1
            qb_id = cmd.qubits[0][0].id
            # self._openqasm_circuit.barrier(self._qreg_dict[qb_id])
            self._openqasm_circuit.measure(self._qreg_dict[qb_id],
                                           self._creg_dict[qb_id])

        elif n_controls == 2:
            targets = [
                self._qreg_dict[qb.id] for qureg in cmd.qubits for qb in qureg
            ]
            controls = [self._qreg_dict[qb.id] for qb in cmd.control_qubits]

            try:
                _ccontrolled_gates_func[gate](*(controls + targets))
            except KeyError:
                raise RuntimeError(
                    'Unable to perform {} gate with n=2 control qubits'.format(
                        gate))

        elif n_controls == 1:
            target_qureg = [
                self._qreg_dict[qb.id] for qureg in cmd.qubits for qb in qureg
            ]

            try:
                if isinstance(gate, Ph):
                    _controlled_gates_func[type(gate)](
                        -gate.angle / 2.,
                        self._qreg_dict[cmd.control_qubits[0].id],
                        target_qureg[0])
                elif isinstance(gate, (
                        R,
                        Rz,
                )):
                    _controlled_gates_func[type(gate)](
                        gate.angle, self._qreg_dict[cmd.control_qubits[0].id],
                        target_qureg[0])
                else:
                    _controlled_gates_func[gate](
                        self._qreg_dict[cmd.control_qubits[0].id],
                        *target_qureg)
            except KeyError as e:
                raise RuntimeError(
                    'Unable to perform {} gate with n=1 control qubits'.format(
                        gate))
        else:
            target_qureg = [
                self._qreg_dict[qb.id] for qureg in cmd.qubits for qb in qureg
            ]
            if isinstance(gate, Ph):
                _gates_func[type(gate)](-gate.angle / 2., target_qureg[0])
            elif isinstance(gate, (R, Rx, Ry, Rz)):
                _gates_func[type(gate)](gate.angle, target_qureg[0])
            else:
                _gates_func[gate](*target_qureg)

    def _reset_after_flush(self):
        """
        Reset the internal quantum circuit after a FlushGate
        """
        self._was_flushed = False
        regs = []
        regs.extend(self._openqasm_circuit.qregs)
        regs.extend(self._openqasm_circuit.cregs)

        self._openqasm_circuit = QuantumCircuit()
        for reg in regs:
            self._openqasm_circuit.add_register(reg)

    def _run(self):
        """
        Run the circuit.
        """
        self._was_flushed = True
        self._process_func(self._openqasm_circuit)

    def receive(self, command_list):
        """
        Receives a command list and, for each command, stores it until
        completion.

        Args:
            command_list: List of commands to execute
        """
        for cmd in command_list:
            if not cmd.gate == FlushGate():
                self._store(cmd)
            else:
                self._run()

        if not self.is_last_engine:
            self.send(command_list)
import matplotlib.pyplot as plt
from executeCircuit import execute_locally, extractClassical
from qAlgorithms import ctrl_initialize
import numpy as np
import operator

n = 1

a = QuantumRegister(n, "arm")
r = QuantumRegister(n, "reward")
qc = QuantumCircuit(a, r)

new_circ = QuantumCircuit(name=r"$\psi$")
a1 = QuantumRegister(n)
r1 = QuantumRegister(n)
new_circ.add_register(a1, r1)
state0 = [complex(np.sqrt(0.3), 0.0), complex(np.sqrt(0.7), 0.0)]
state1 = [complex(np.sqrt(1), 0.0), complex(0.0, 0.0)]
new_circ.h(a1)
new_circ.ctrl_initialize(statevector=state0,
                         ctrl_state='0',
                         ctrl_qubits=a1,
                         qubits=r1)
new_circ.ctrl_initialize(statevector=state1,
                         ctrl_state='1',
                         ctrl_qubits=a1,
                         qubits=r1)
'''
#SAME AS ctrl_initialize
#Rotation for 0->30% / 1->70% controlled by action 1
new_circ.cry(2*np.pi/6.77,a1[0],r1[0])
Esempio n. 15
0
    def get_output(self,
                   quantum_instance,
                   qc_state_in=None,
                   params=None,
                   shots=None):
        """
        Get classical data samples from the generator.
        Running the quantum generator circuit results in a quantum state.
        To train this generator with a classical discriminator, we need to sample classical outputs
        by measuring the quantum state and mapping them to feature space defined by the training
        data.

        Args:
            quantum_instance (QuantumInstance): Quantum Instance, used to run the generator
                circuit.
            qc_state_in (QuantumCircuit): deprecated
            params (numpy.ndarray): array or None, parameters which should
                be used to run the generator, if None use self._params
            shots (int): if not None use a number of shots that is different from the
                number set in quantum_instance

        Returns:
            list: generated samples, array: sample occurrence in percentage
        """
        instance_shots = quantum_instance.run_config.shots
        q = QuantumRegister(sum(self._num_qubits), name='q')
        qc = QuantumCircuit(q)
        qc.append(self.construct_circuit(params), q)
        if quantum_instance.is_statevector:
            pass
        else:
            c = ClassicalRegister(sum(self._num_qubits), name='c')
            qc.add_register(c)
            qc.measure(q, c)

        if shots is not None:
            quantum_instance.set_config(shots=shots)

        result = quantum_instance.execute(qc)

        generated_samples = []
        if quantum_instance.is_statevector:
            result = result.get_statevector(qc)
            values = np.multiply(result, np.conj(result))
            values = list(values.real)
            keys = []
            for j in range(len(values)):
                keys.append(np.binary_repr(j, int(sum(self._num_qubits))))
        else:
            result = result.get_counts(qc)
            keys = list(result)
            values = list(result.values())
            values = [float(v) / np.sum(values) for v in values]
        generated_samples_weights = values
        for i, _ in enumerate(keys):
            index = 0
            temp = []
            for k, p in enumerate(self._num_qubits):
                bin_rep = 0
                j = 0
                while j < p:
                    bin_rep += int(keys[i][index]) * 2**(int(p) - j - 1)
                    j += 1
                    index += 1
                if len(self._num_qubits) > 1:
                    temp.append(self._data_grid[k][int(bin_rep)])
                else:
                    temp.append(self._data_grid[int(bin_rep)])
            generated_samples.append(temp)

        self.generator_circuit._probabilities = generated_samples_weights
        if shots is not None:
            # Restore the initial quantum_instance configuration
            quantum_instance.set_config(shots=instance_shots)
        return generated_samples, generated_samples_weights
Esempio n. 16
0
    def _make_syndrome_graph(self, results=None):

        S = rx.PyGraph(multigraph=False)
        if results:

            node_map = {}
            for string in results:
                nodes = self._string2nodes(string)
                for node in nodes:
                    if node not in node_map:
                        node_map[node] = S.add_node(node)
                for source in nodes:
                    for target in nodes:
                        if target != source:
                            S.add_edge(node_map[source], node_map[target], 1)

        else:
            qc = self.code.circuit["0"]

            blank_qc = QuantumCircuit()
            for qreg in qc.qregs:
                blank_qc.add_register(qreg)
            for creg in qc.cregs:
                blank_qc.add_register(creg)

            error_circuit = {}
            circuit_name = {}
            depth = len(qc)
            for j in range(depth):
                qubits = qc.data[j][1]
                for qubit in qubits:
                    for error in ["x", "y", "z"]:
                        temp_qc = copy.deepcopy(blank_qc)
                        temp_qc.name = str((j, qubit, error))
                        temp_qc.data = qc.data[0:j]
                        getattr(temp_qc, error)(qubit)
                        temp_qc.data += qc.data[j: depth + 1]
                        circuit_name[(j, qubit, error)] = temp_qc.name
                        error_circuit[temp_qc.name] = temp_qc

            if HAS_AER:
                simulator = Aer.get_backend("aer_simulator")
            else:
                simulator = BasicAer.get_backend("qasm_simulator")

            job = execute(list(error_circuit.values()), simulator)

            node_map = {}
            for j in range(depth):
                qubits = qc.data[j][1]
                for qubit in qubits:
                    for error in ["x", "y", "z"]:
                        raw_results = {}
                        raw_results["0"] = job.result().get_counts(
                            str((j, qubit, error))
                        )
                        results = self.code.process_results(raw_results)["0"]

                        for string in results:

                            nodes = self._string2nodes(string)

                            assert len(nodes) in [0, 2], (
                                "Error of type "
                                + error
                                + " on qubit "
                                + str(qubit)
                                + " at depth "
                                + str(j)
                                + " creates "
                                + str(len(nodes))
                                + " nodes in syndrome graph, instead of 2."
                            )
                            for node in nodes:
                                if node not in node_map:
                                    node_map[node] = S.add_node(node)
                            for source in nodes:
                                for target in nodes:
                                    if target != source:
                                        S.add_edge(
                                            node_map[source], node_map[target], 1
                                        )

        return S
Esempio n. 17
0
class AmplitudeEstimation(AmplitudeEstimationAlgorithm):
    r"""The Quantum Phase Estimation-based Amplitude Estimation algorithm.

    This class implements the original Quantum Amplitude Estimation (QAE) algorithm, introduced by
    [1]. This canonical version uses quantum phase estimation along with a set of :math:`m`
    additional evaluation qubits to find an estimate :math:`\tilde{a}`, that is restricted to the
    grid

    .. math::

        \tilde{a} \in \{\sin^2(\pi  y / 2^m) : y = 0, ..., 2^{m-1}\}

    More evaluation qubits produce a finer sampling grid, therefore the accuracy of the algorithm
    increases with :math:`m`.

    Using a maximum likelihood post processing, this grid constraint can be circumvented.
    This improved estimator is implemented as well, see [2] Appendix A for more detail.

    References:
        [1]: Brassard, G., Hoyer, P., Mosca, M., & Tapp, A. (2000).
             Quantum Amplitude Amplification and Estimation.
             `arXiv:quant-ph/0005055 <http://arxiv.org/abs/quant-ph/0005055>`_.
        [2]: Grinko, D., Gacon, J., Zoufal, C., & Woerner, S. (2019).
             Iterative Quantum Amplitude Estimation.
             `arXiv:1912.05559 <https://arxiv.org/abs/1912.05559>`_.
    """
    def __init__(self,
                 num_eval_qubits: int,
                 state_preparation: Optional[Union[QuantumCircuit,
                                                   CircuitFactory]] = None,
                 grover_operator: Optional[Union[QuantumCircuit,
                                                 CircuitFactory]] = None,
                 objective_qubits: Optional[List[int]] = None,
                 post_processing: Optional[Callable[[float], float]] = None,
                 phase_estimation_circuit: Optional[QuantumCircuit] = None,
                 iqft: Optional[QuantumCircuit] = None,
                 quantum_instance: Optional[Union[QuantumInstance,
                                                  BaseBackend]] = None,
                 a_factory: Optional[CircuitFactory] = None,
                 q_factory: Optional[CircuitFactory] = None,
                 i_objective: Optional[int] = None) -> None:
        r"""
        Args:
            num_eval_qubits: The number of evaluation qubits.
            state_preparation: A circuit preparing the input state, referred to as
                :math:`\mathcal{A}`.
            grover_operator: The Grover operator :math:`\mathcal{Q}` used as unitary in the
                phase estimation circuit.
            objective_qubits: A list of qubit indices to specify the oracle in the Grover operator,
                if the Grover operator is not supplied. A measurement outcome is classified as
                'good' state if all objective qubits are in state :math:`|1\rangle`, otherwise it
                is classified as 'bad'.
            post_processing: A mapping applied to the result of the algorithm
                :math:`0 \leq a \leq 1`, usually used to map the estimate to a target interval.
            phase_estimation_circuit: The phase estimation circuit used to run the algorithm.
                Defaults to the standard phase estimation circuit from the circuit library,
                `qiskit.circuit.library.PhaseEstimation`.
            iqft: The inverse quantum Fourier transform component, defaults to using a standard
                implementation from `qiskit.circuit.library.QFT` when None.
            quantum_instance: The backend (or `QuantumInstance`) to execute the circuits on.
            a_factory: Deprecated, use ``state_preparation``.
                The CircuitFactory subclass object representing the problem unitary.
            q_factory: Deprecated, use ``grover_operator``.
                The CircuitFactory subclass object representing an amplitude estimation
                sample (based on a_factory).
            i_objective: Deprecated, use ``objective_qubits``.
                The index of the objective qubit, i.e. the qubit marking 'good' solutions
                with the state :math:`|1\rangle` and 'bad' solutions with the state
                :math:`0\rangle`.
        """
        validate_min('num_eval_qubits', num_eval_qubits, 1)

        # support legacy input if passed as positional arguments
        if isinstance(state_preparation, CircuitFactory):
            a_factory = state_preparation
            state_preparation = None

        if isinstance(grover_operator, CircuitFactory):
            q_factory = grover_operator
            grover_operator = None

        if isinstance(objective_qubits, int):
            i_objective = objective_qubits
            objective_qubits = None

        super().__init__(state_preparation=state_preparation,
                         grover_operator=grover_operator,
                         objective_qubits=objective_qubits,
                         post_processing=post_processing,
                         quantum_instance=quantum_instance,
                         a_factory=a_factory,
                         q_factory=q_factory,
                         i_objective=i_objective)

        # get parameters
        self._m = num_eval_qubits  # pylint: disable=invalid-name
        self._M = 2**num_eval_qubits  # pylint: disable=invalid-name

        # NOTE removed deprecation warnings from IQFT, support removed as of August, 1st 2020
        self._iqft = iqft
        self._pec = phase_estimation_circuit
        self._circuit = None
        self._ret = {}  # type: Dict[str, Any]

    def construct_circuit(self, measurement: bool = False) -> QuantumCircuit:
        """Construct the Amplitude Estimation quantum circuit.

        Args:
            measurement: Boolean flag to indicate if measurements should be included in the circuit.

        Returns:
            The QuantumCircuit object for the constructed circuit.
        """
        if self.state_preparation is None:  # circuit factories
            iqft = QFT(self._m, do_swaps=False,
                       inverse=True) if self._iqft is None else self._iqft
            pec = PhaseEstimationCircuit(
                iqft=iqft,
                num_ancillae=self._m,
                state_in_circuit_factory=self.a_factory,
                unitary_circuit_factory=self.q_factory)
            self._circuit = pec.construct_circuit(measurement=measurement)
        else:
            if self._pec is not None:
                pec = self._pec
            else:
                from qiskit.circuit.library import PhaseEstimation
                pec = PhaseEstimation(self._m,
                                      self.grover_operator,
                                      iqft=self._iqft)

            # mypy thinks self.circuit is None even after explicitly being set to QuantumCircuit
            self._circuit = QuantumCircuit(*pec.qregs)
            self._circuit.compose(
                self.state_preparation,  # type: ignore
                list(
                    range(self._m,
                          self._m + self.state_preparation.num_qubits)),
                inplace=True)
            self._circuit.compose(pec, inplace=True)  # type: ignore

            if measurement:
                cr = ClassicalRegister(self._m)
                self._circuit.add_register(cr)  # type: ignore
                self._circuit.measure(list(range(self._m)),
                                      list(range(self._m)))  # type: ignore

        return self._circuit

    def _evaluate_statevector_results(
        self, probabilities: Union[List[float], np.ndarray]
    ) -> Tuple[OrderedDict, OrderedDict]:
        """Evaluate the results from statevector simulation.

        Given the probabilities from statevector simulation of the QAE circuit, compute the
        probabilities that the measurements y/gridpoints a are the best estimate.

        Args:
            probabilities: The probabilities obtained from the statevector simulation,
                i.e. real(statevector * statevector.conj())[0]

        Raises:
            AquaError: If `construct_circuit` has not been called before. The `construct_circuit`
                method sets an internal variable required in this method.

        Returns:
            Dictionaries containing the a gridpoints with respective probabilities and
                y measurements with respective probabilities, in this order.
        """
        if self._circuit is None:
            raise AquaError(
                'Before calling _evaluate_statevector_results the construct_circuit '
                'method must be called, which sets the internal _circuit variable '
                'required in this method.')

        # map measured results to estimates
        y_probabilities = OrderedDict()  # type: OrderedDict
        for i, probability in enumerate(probabilities):
            b = '{0:b}'.format(i).rjust(self._circuit.num_qubits, '0')[::-1]
            y = int(b[:self._m], 2)
            y_probabilities[y] = y_probabilities.get(y, 0) + probability

        a_probabilities = OrderedDict()  # type: OrderedDict
        for y, probability in y_probabilities.items():
            if y >= int(self._M / 2):
                y = self._M - y
            # due to the finite accuracy of the sine, we round the result to 7 decimals
            a = np.round(np.power(np.sin(y * np.pi / 2**self._m), 2),
                         decimals=7)
            a_probabilities[a] = a_probabilities.get(a, 0) + probability

        return a_probabilities, y_probabilities

    def _compute_fisher_information(self, observed: bool = False) -> float:
        """Computes the Fisher information for the output of the previous run.

        Args:
            observed: If True, the observed Fisher information is returned, otherwise
                the expected Fisher information.

        Returns:
            The Fisher information.
        """
        fisher_information = None
        mlv = self._ret['ml_value']  # MLE in [0,1]
        m = self._m

        if observed:
            a_i = np.asarray(self._ret['values'])
            p_i = np.asarray(self._ret['probabilities'])

            # Calculate the observed Fisher information
            fisher_information = sum(p * derivative_log_pdf_a(a, mlv, m)**2
                                     for p, a in zip(p_i, a_i))
        else:

            def integrand(x):
                return (derivative_log_pdf_a(x, mlv, m))**2 * pdf_a(x, mlv, m)

            grid = np.sin(np.pi * np.arange(self._M / 2 + 1) / self._M)**2
            fisher_information = sum(integrand(x) for x in grid)

        return fisher_information

    def _fisher_confint(self,
                        alpha: float,
                        observed: bool = False) -> List[float]:
        """Compute the Fisher information confidence interval for the MLE of the previous run.

        Args:
            alpha: Specifies the (1 - alpha) confidence level (0 < alpha < 1).
            observed: If True, the observed Fisher information is used to construct the
                confidence interval, otherwise the expected Fisher information.

        Returns:
            The Fisher information confidence interval.
        """
        shots = self._ret['shots']
        mle = self._ret['ml_value']

        # approximate the standard deviation of the MLE and construct the confidence interval
        std = np.sqrt(shots * self._compute_fisher_information(observed))
        confint = mle + norm.ppf(1 - alpha / 2) / std * np.array([-1, 1])

        # transform the confidence interval from [0, 1] to the target interval
        return [self.post_processing(bound) for bound in confint]

    def _likelihood_ratio_confint(self, alpha: float) -> List[float]:
        """Compute the likelihood ratio confidence interval for the MLE of the previous run.

        Args:
            alpha: Specifies the (1 - alpha) confidence level (0 < alpha < 1).

        Returns:
            The likelihood ratio confidence interval.
        """
        # Compute the two intervals in which we the look for values above
        # the likelihood ratio: the two bubbles next to the QAE estimate
        M = self._M  # pylint: disable=invalid-name
        qae = self._ret['value']

        y = int(np.round(M * np.arcsin(np.sqrt(qae)) / np.pi))
        if y == 0:
            right_of_qae = np.sin(np.pi * (y + 1) / M)**2
            bubbles = [qae, right_of_qae]

        elif y == int(M / 2):  # remember, M = 2^m is a power of 2
            left_of_qae = np.sin(np.pi * (y - 1) / M)**2
            bubbles = [left_of_qae, qae]

        else:
            left_of_qae = np.sin(np.pi * (y - 1) / M)**2
            right_of_qae = np.sin(np.pi * (y + 1) / M)**2
            bubbles = [left_of_qae, qae, right_of_qae]

        # likelihood function
        a_i = np.asarray(self._ret['values'])
        p_i = np.asarray(self._ret['probabilities'])
        m = self._m
        shots = self._ret['shots']

        def loglikelihood(a):
            return np.sum(shots * p_i * np.log(pdf_a(a_i, a, m)))

        # The threshold above which the likelihoods are in the
        # confidence interval
        loglik_mle = loglikelihood(self._ret['ml_value'])
        thres = loglik_mle - chi2.ppf(1 - alpha, df=1) / 2

        def cut(x):
            return loglikelihood(x) - thres

        # Store the boundaries of the confidence interval
        # It's valid to start off with the zero-width confidence interval, since the maximum
        # of the likelihood function is guaranteed to be over the threshold, and if alpha = 0
        # that's the valid interval
        lower = upper = self._ret['ml_value']

        # Check the two intervals/bubbles: check if they surpass the
        # threshold and if yes add the part that does to the CI
        for a, b in zip(bubbles[:-1], bubbles[1:]):
            # Compute local maximum and perform a bisect search between
            # the local maximum and the bubble boundaries
            locmax, val = bisect_max(loglikelihood, a, b, retval=True)
            if val >= thres:
                # Bisect pre-condition is that the function has different
                # signs at the boundaries of the interval we search in
                if cut(a) * cut(locmax) < 0:
                    left = bisect(cut, a, locmax)
                    lower = np.minimum(lower, left)
                if cut(locmax) * cut(b) < 0:
                    right = bisect(cut, locmax, b)
                    upper = np.maximum(upper, right)

        # Put together CI
        confint = [lower, upper]
        return [self.post_processing(bound) for bound in confint]

    def confidence_interval(self,
                            alpha: float,
                            kind: str = 'likelihood_ratio') -> List[float]:
        """Compute the (1 - alpha) confidence interval.

        Args:
            alpha: Confidence level: compute the (1 - alpha) confidence interval.
            kind: The method to compute the confidence interval, can be 'fisher', 'observed_fisher'
                or 'likelihood_ratio' (default)

        Returns:
            The (1 - alpha) confidence interval of the specified kind.

        Raises:
            AquaError: If 'mle' is not in self._ret.keys() (i.e. `run` was not called yet).
            NotImplementedError: If the confidence interval method `kind` is not implemented.
        """
        # check if AE did run already
        if 'mle' not in self._ret.keys():
            raise AquaError('Call run() first!')

        # if statevector simulator the estimate is exact
        if self._quantum_instance.is_statevector:
            return 2 * [self._ret['mle']]

        if kind in ['likelihood_ratio', 'lr']:
            return self._likelihood_ratio_confint(alpha)

        if kind in ['fisher', 'fi']:
            return self._fisher_confint(alpha, observed=False)

        if kind in ['observed_fisher', 'observed_information', 'oi']:
            return self._fisher_confint(alpha, observed=True)

        raise NotImplementedError('CI `{}` is not implemented.'.format(kind))

    def _run_mle(self) -> None:
        """Compute the Maximum Likelihood Estimator (MLE).

        Returns:
            The MLE for the previous AE run.

        Note:
            Before calling this method, call the method `run` of the AmplitudeEstimation instance.
        """
        M = self._M  # pylint: disable=invalid-name
        qae = self._ret['value']

        # likelihood function
        a_i = np.asarray(self._ret['values'])
        p_i = np.asarray(self._ret['probabilities'])
        m = self._m
        shots = self._ret['shots']

        def loglikelihood(a):
            return np.sum(shots * p_i * np.log(pdf_a(a_i, a, m)))

        # y is pretty much an integer, but to map 1.9999 to 2 we must first
        # use round and then int conversion
        y = int(np.round(M * np.arcsin(np.sqrt(qae)) / np.pi))

        # Compute the two intervals in which are candidates for containing
        # the maximum of the log-likelihood function: the two bubbles next to
        # the QAE estimate
        if y == 0:
            right_of_qae = np.sin(np.pi * (y + 1) / M)**2
            bubbles = [qae, right_of_qae]

        elif y == int(M / 2):  # remember, M = 2^m is a power of 2
            left_of_qae = np.sin(np.pi * (y - 1) / M)**2
            bubbles = [left_of_qae, qae]

        else:
            left_of_qae = np.sin(np.pi * (y - 1) / M)**2
            right_of_qae = np.sin(np.pi * (y + 1) / M)**2
            bubbles = [left_of_qae, qae, right_of_qae]

        # Find global maximum amongst the two local maxima
        a_opt = qae
        loglik_opt = loglikelihood(a_opt)
        for a, b in zip(bubbles[:-1], bubbles[1:]):
            locmax, val = bisect_max(loglikelihood, a, b, retval=True)
            if val > loglik_opt:
                a_opt = locmax
                loglik_opt = val

        # Convert the value to an estimation
        val_opt = self.post_processing(a_opt)

        # Store MLE and the MLE mapped to an estimation
        self._ret['ml_value'] = a_opt
        self._ret['mle'] = val_opt

    def _run(self) -> 'AmplitudeEstimationResult':
        # check if A factory or state_preparation has been set
        if self.state_preparation is None:
            if self.a_factory is None:  # getter emits deprecation warnings, therefore nest
                raise AquaError(
                    'Either the state_preparation variable or the a_factory '
                    '(deprecated) must be set to run the algorithm.')

        if self._quantum_instance.is_statevector:
            self.construct_circuit(measurement=False)
            # run circuit on statevector simulator
            ret = self._quantum_instance.execute(self._circuit)
            state_vector = np.asarray([ret.get_statevector(self._circuit)])
            self._ret['statevector'] = state_vector

            # get state probabilities
            state_probabilities = np.real(state_vector.conj() *
                                          state_vector)[0]

            # evaluate results
            a_probabilities, y_probabilities = self._evaluate_statevector_results(
                state_probabilities)

            # store number of shots: convention is 1 shot for statevector,
            # needed so that MLE works!
            self._ret['shots'] = 1
        else:
            # run circuit on QASM simulator
            self.construct_circuit(measurement=True)
            ret = self._quantum_instance.execute(self._circuit)

            # get counts
            self._ret['counts'] = ret.get_counts()

            # construct probabilities
            y_probabilities = OrderedDict()
            a_probabilities = OrderedDict()
            shots = self._quantum_instance._run_config.shots

            for state, counts in ret.get_counts().items():
                y = int(state.replace(' ', '')[:self._m][::-1], 2)
                probability = counts / shots
                y_probabilities[y] = probability
                a = np.round(np.power(np.sin(y * np.pi / 2**self._m), 2),
                             decimals=7)
                a_probabilities[a] = a_probabilities.get(a, 0.0) + probability

            # store shots
            self._ret['shots'] = shots

        # construct a_items and y_items
        a_items = [(a, p) for (a, p) in a_probabilities.items() if p > 1e-6]
        y_items = [(y, p) for (y, p) in y_probabilities.items() if p > 1e-6]
        a_items = list(a_probabilities.items())
        y_items = list(y_probabilities.items())
        a_items = sorted(a_items)
        y_items = sorted(y_items)
        self._ret['a_items'] = a_items
        self._ret['y_items'] = y_items

        # map estimated values to original range and extract probabilities
        self._ret['mapped_values'] = [
            self.post_processing(a_item[0]) for a_item in self._ret['a_items']
        ]
        self._ret['values'] = [a_item[0] for a_item in self._ret['a_items']]
        self._ret['y_values'] = [y_item[0] for y_item in y_items]
        self._ret['probabilities'] = [
            a_item[1] for a_item in self._ret['a_items']
        ]
        self._ret['mapped_items'] = [
            (self._ret['mapped_values'][i], self._ret['probabilities'][i])
            for i in range(len(self._ret['mapped_values']))
        ]

        # determine most likely estimator
        self._ret['value'] = None  # estimate in [0,1]
        self._ret['estimation'] = None  # estimate mapped to right interval
        self._ret['max_probability'] = 0
        for val, (est, prob) in zip(self._ret['values'],
                                    self._ret['mapped_items']):
            if prob > self._ret['max_probability']:
                self._ret['max_probability'] = prob
                self._ret['estimation'] = est
                self._ret['value'] = val

        # count the number of Q-oracle calls
        self._ret['num_oracle_queries'] = self._ret['shots'] * (self._M - 1)

        # get MLE
        self._run_mle()

        # get 95% confidence interval
        alpha = 0.05
        kind = 'likelihood_ratio'  # empirically the most precise kind
        self._ret['95%_confidence_interval'] = self.confidence_interval(
            alpha, kind)

        ae_result = AmplitudeEstimationAlgorithmResult()
        ae_result.a_estimation = self._ret['value']
        ae_result.estimation = self._ret['estimation']
        ae_result.num_oracle_queries = self._ret['num_oracle_queries']
        ae_result.confidence_interval = self._ret['95%_confidence_interval']

        result = AmplitudeEstimationResult()
        result.combine(ae_result)
        result.ml_value = self._ret['ml_value']
        result.mapped_a_samples = self._ret['values']
        result.probabilities = self._ret['probabilities']
        result.shots = self._ret['shots']
        result.mle = self._ret['mle']
        if 'statevector' in self._ret:
            result.circuit_result = self._ret['statevector']
        elif 'counts' in self._ret:
            result.circuit_result = dict(self._ret['counts'])
        result.a_samples = self._ret['a_items']
        result.y_measurements = self._ret['y_items']
        result.mapped_values = self._ret['mapped_values']
        result.max_probability = self._ret['max_probability']
        return result
Esempio n. 18
0
def grover_fix_qiskit() -> QuantumCircuit:   
    qc = QuantumCircuit()

    q = QuantumRegister(4, 'q')
    ro = ClassicalRegister(4, 'ro')

    qc.add_register(q)
    qc.add_register(ro)

    qc.h(q[0])
    qc.h(q[1])
    qc.h(q[2])
    qc.h(q[3])
    qc.x(q[0])
    qc.x(q[2])
    qc.x(q[3])
    qc.crz(0.785398163397, q[0], q[3])
    qc.cx(q[0], q[1])
    qc.crz(-0.785398163397, q[1], q[3])
    qc.cx(q[0], q[1])
    qc.crz(0.785398163397, q[1], q[3])
    qc.cx(q[1], q[2])
    qc.crz(-0.785398163397, q[2], q[3])
    qc.cx(q[0], q[2])
    qc.crz(0.785398163397, q[2], q[3])
    qc.cx(q[1], q[2])
    qc.crz(-0.785398163397, q[2], q[3])
    qc.cx(q[0], q[2])
    qc.crz(0.785398163397, q[2], q[3])
    qc.x(q[0])
    qc.x(q[2])
    qc.x(q[3])
    qc.h(q[0])
    qc.h(q[1])
    qc.h(q[2])
    qc.h(q[3])
    qc.x(q[0])
    qc.x(q[1])
    qc.x(q[2])
    qc.x(q[3])
    qc.crz(0.785398163397, q[0], q[3])
    qc.cx(q[0], q[1])
    qc.crz(-0.785398163397, q[1], q[3])
    qc.cx(q[0], q[1])
    qc.crz(0.785398163397, q[1], q[3])
    qc.cx(q[1], q[2])
    qc.crz(-0.785398163397, q[2], q[3])
    qc.cx(q[0], q[2])
    qc.crz(0.785398163397, q[2], q[3])
    qc.cx(q[1], q[2])
    qc.crz(-0.785398163397, q[2], q[3])
    qc.cx(q[0], q[2])
    qc.crz(0.785398163397, q[2], q[3])
    qc.x(q[0])
    qc.x(q[1])
    qc.x(q[2])
    qc.x(q[3])
    qc.h(q[0])
    qc.h(q[1])
    qc.h(q[2])
    qc.h(q[3])
    qc.measure(q[0], ro[0])
    qc.measure(q[1], ro[1])
    qc.measure(q[2], ro[2])
    qc.measure(q[3], ro[3])
    return qc
Esempio n. 19
0
def generate_register_edge_cases():
    """Generate register edge case circuits."""
    register_edge_cases = []
    # Circuit with shared bits in a register
    qubits = [Qubit() for _ in range(5)]
    shared_qc = QuantumCircuit()
    shared_qc.add_bits(qubits)
    shared_qr = QuantumRegister(bits=qubits)
    shared_qc.add_register(shared_qr)
    shared_qc.h(shared_qr)
    shared_qc.cx(0, 1)
    shared_qc.cx(0, 2)
    shared_qc.cx(0, 3)
    shared_qc.cx(0, 4)
    shared_qc.measure_all()
    register_edge_cases.append(shared_qc)
    # Circuit with registers that have a mix of standalone and shared register
    # bits
    qr = QuantumRegister(5, "foo")
    qr = QuantumRegister(name="bar", bits=qr[:3] + [Qubit(), Qubit()])
    cr = ClassicalRegister(5, "foo")
    cr = ClassicalRegister(name="classical_bar", bits=cr[:3] + [Clbit(), Clbit()])
    hybrid_qc = QuantumCircuit(qr, cr)
    hybrid_qc.h(0)
    hybrid_qc.cx(0, 1)
    hybrid_qc.cx(0, 2)
    hybrid_qc.cx(0, 3)
    hybrid_qc.cx(0, 4)
    hybrid_qc.measure(qr, cr)
    register_edge_cases.append(hybrid_qc)
    # Circuit with mixed standalone and shared registers
    qubits = [Qubit() for _ in range(5)]
    clbits = [Clbit() for _ in range(5)]
    mixed_qc = QuantumCircuit()
    mixed_qc.add_bits(qubits)
    mixed_qc.add_bits(clbits)
    qr = QuantumRegister(bits=qubits)
    cr = ClassicalRegister(bits=clbits)
    mixed_qc.add_register(qr)
    mixed_qc.add_register(cr)
    qr_standalone = QuantumRegister(2, "standalone")
    mixed_qc.add_register(qr_standalone)
    cr_standalone = ClassicalRegister(2, "classical_standalone")
    mixed_qc.add_register(cr_standalone)
    mixed_qc.unitary(random_unitary(32, seed=42), qr)
    mixed_qc.unitary(random_unitary(4, seed=100), qr_standalone)
    mixed_qc.measure(qr, cr)
    mixed_qc.measure(qr_standalone, cr_standalone)
    register_edge_cases.append(mixed_qc)
    # Circuit with out of order register bits
    qr_standalone = QuantumRegister(2, "standalone")
    qubits = [Qubit() for _ in range(5)]
    clbits = [Clbit() for _ in range(5)]
    ooo_qc = QuantumCircuit()
    ooo_qc.add_bits(qubits)
    ooo_qc.add_bits(clbits)
    random.seed(42)
    random.shuffle(qubits)
    random.shuffle(clbits)
    qr = QuantumRegister(bits=qubits)
    cr = ClassicalRegister(bits=clbits)
    ooo_qc.add_register(qr)
    ooo_qc.add_register(cr)
    qr_standalone = QuantumRegister(2, "standalone")
    cr_standalone = ClassicalRegister(2, "classical_standalone")
    ooo_qc.add_bits([qr_standalone[1], qr_standalone[0]])
    ooo_qc.add_bits([cr_standalone[1], cr_standalone[0]])
    ooo_qc.add_register(qr_standalone)
    ooo_qc.add_register(cr_standalone)
    ooo_qc.unitary(random_unitary(32, seed=42), qr)
    ooo_qc.unitary(random_unitary(4, seed=100), qr_standalone)
    ooo_qc.measure(qr, cr)
    ooo_qc.measure(qr_standalone, cr_standalone)
    register_edge_cases.append(ooo_qc)
    return register_edge_cases
Esempio n. 20
0
class FullAdder:
    """
    Input:
    A input
    B input
    X carry in

    Reuslt:
    S sum
    C carry out
    """
    def __init__(self):
        self.q = QuantumRegister(6)
        self.c = ClassicalRegister(6)
        self.circ = QuantumCircuit()
        self.circ.add_register(self.q)
        self.circ.add_register(self.c)
        # c1s1 is the register for half adder summation - for the AB bits
        self.A, self.B, self.X, self.c1, self.S, self.C = self.q
        self.result_state = []
        self.result = {'ABX': '00', 'c1': '0', 'CS': '00'}

    def build_circ(self):
        self.circ.cx(self.A, self.S)
        self.circ.cx(self.B, self.S)
        self.circ.cx(self.X, self.S)
        self.circ.ccx(self.A, self.B, self.c1)
        self.circ.barrier()

        self.circ.cx(self.X, self.C)
        self.circ.cx(self.c1, self.C)
        self.circ.ccx(self.X, self.S, self.C)
        self.circ.barrier()

        self.circ.measure(self.q, self.c)

    def input(self, abx):
        if '1' == abx[0]:
            self.circ.x(self.A)
        if '1' == abx[1]:
            self.circ.x(self.B)
        if '1' == abx[2]:
            self.circ.x(self.X)

        self.circ.barrier()

    def run(self):
        job = execute(self.circ, backend=backend, shots=1024)
        st = job.result().get_counts()
        if len(st) == 1:
            # self.result_state = list(st.keys())[0][::-1]
            self.result_state = list(st.keys())[0]
            self.result['ABX'] = self.result_state[3:6][::-1]
            self.result['c1'] = self.result_state[2:3]
            self.result['CS'] = self.result_state[0:2]
        else:
            print("Unexpected output")
            print(st)

    def print_result_state(self):
        print(self.result_state)
        print("Input ABX=%s, c1=%s result CS=%s " %
              (self.result['ABX'], self.result['c1'], self.result['CS']))
Esempio n. 21
0
    def construct_circuit(self, measurement: bool = False) -> QuantumCircuit:
        """Construct circuit.

        Args:
            measurement: Boolean flag to indicate if measurement should be included in the circuit.

        Returns:
            Quantum circuit.
        """

        # Get n value used in Shor's algorithm, to know how many qubits are used
        self._n = math.ceil(math.log(self._N, 2))
        self._qft.num_qubits = self._n + 1
        self._iqft.num_qubits = self._n + 1

        # quantum register where the sequential QFT is performed
        self._up_qreg = QuantumRegister(2 * self._n, name='up')
        # quantum register where the multiplications are made
        self._down_qreg = QuantumRegister(self._n, name='down')
        # auxiliary quantum register used in addition and multiplication
        self._aux_qreg = QuantumRegister(self._n + 2, name='aux')

        # Create Quantum Circuit
        circuit = QuantumCircuit(self._up_qreg,
                                 self._down_qreg,
                                 self._aux_qreg,
                                 name="Shor(N={}, a={})".format(
                                     self._N, self._a))

        # Create gates to perform addition/subtraction by N in Fourier Space
        self._phi_add_N = self._phi_add_gate(self._aux_qreg.size - 1,
                                             self._get_angles(self._N))
        self._iphi_add_N = self._phi_add_N.inverse()

        # Create maximal superposition in top register
        circuit.h(self._up_qreg)

        # Initialize down register to 1
        circuit.x(self._down_qreg[0])

        # Apply the multiplication gates as showed in
        # the report in order to create the exponentiation
        for i, ctl_up in enumerate(self._up_qreg):  # type: ignore
            a = int(pow(self._a, pow(2, i)))
            controlled_multiple_mod_N = self._controlled_multiple_mod_N(
                len(self._down_qreg) + len(self._aux_qreg) + 1,
                a,
            )
            circuit.append(controlled_multiple_mod_N,
                           [ctl_up, *self._down_qreg, *self._aux_qreg])

        # Apply inverse QFT
        iqft = QFT(len(self._up_qreg)).inverse().to_instruction()
        circuit.append(iqft, self._up_qreg)

        if measurement:
            up_cqreg = ClassicalRegister(2 * self._n, name='m')
            circuit.add_register(up_cqreg)
            circuit.measure(self._up_qreg, up_cqreg)

        logger.info(summarize_circuits(circuit))

        return circuit
Esempio n. 22
0
class TruthTableOracle(Oracle):

    CONFIGURATION = {
        'name': 'TruthTableOracle',
        'description': 'Truth Table Oracle',
        'input_schema': {
            '$schema': 'http://json-schema.org/schema#',
            'id': 'truth_table_oracle_schema',
            'type': 'object',
            'properties': {
                'bitmaps': {
                    "type": "array",
                    "default": [],
                    "items": {
                        "type": "string"
                    }
                },
                "optimization": {
                    "type": "string",
                    "default": "off",
                    'oneOf': [{
                        'enum': ['off', 'qm-dlx']
                    }]
                },
                'mct_mode': {
                    'type':
                    'string',
                    'default':
                    'basic',
                    'oneOf': [{
                        'enum': [
                            'basic',
                            'basic-dirty-ancilla',
                            'advanced',
                            'noancilla',
                        ]
                    }]
                },
            },
            'additionalProperties': False
        }
    }

    def __init__(self, bitmaps, optimization='off', mct_mode='basic'):
        """
        Constructor for Truth Table-based Oracle

        Args:
            bitmaps (str or [str]): A single binary string or a list of binary strings representing the desired
                single- and multi-value truth table.
            optimization (str): Optimization mode to use for minimizing the circuit.
                Currently, besides no optimization ('off'), Aqua also supports a 'qm-dlx' mode,
                which uses the Quine-McCluskey algorithm to compute the prime implicants of the truth table,
                and then compute an exact cover to try to reduce the circuit.
            mct_mode (str): The mode to use when constructing multiple-control Toffoli.
        """
        if isinstance(bitmaps, str):
            bitmaps = [bitmaps]

        self.validate(locals())
        super().__init__()

        self._mct_mode = mct_mode
        self._optimization = optimization

        self._bitmaps = bitmaps

        # check that the input bitmaps length is a power of 2
        if not is_power_of_2(len(bitmaps[0])):
            raise AquaError('Length of any bitmap must be a power of 2.')
        for bitmap in bitmaps[1:]:
            if not len(bitmap) == len(bitmaps[0]):
                raise AquaError('Length of all bitmaps must be the same.')
        self._nbits = int(math.log(len(bitmaps[0]), 2))
        self._num_outputs = len(bitmaps)

        esop_exprs = []
        for bitmap in bitmaps:
            esop_expr = self._get_esop_ast(bitmap)
            esop_exprs.append(esop_expr)

        self._esops = [
            ESOP(esop_expr, num_vars=self._nbits) for esop_expr in esop_exprs
        ] if esop_exprs else None

        self.construct_circuit()

    @staticmethod
    def check_pluggable_valid():
        check_pyeda_valid(TruthTableOracle.CONFIGURATION['name'])

    def _get_esop_ast(self, bitmap):
        from pyeda.inter import exprvars, And, Xor
        v = exprvars('v', self._nbits)

        def binstr_to_vars(binstr):
            return [(~v[x[1] - 1] if x[0] == '0' else v[x[1] - 1])
                    for x in zip(binstr, reversed(range(1, self._nbits + 1)))
                    ][::-1]

        if self._optimization == 'off':
            expression = Xor(*[
                And(*binstr_to_vars(term)) for term in [
                    np.binary_repr(idx, self._nbits)
                    for idx, v in enumerate(bitmap) if v == '1'
                ]
            ])
        else:  # self._optimization == 'qm-dlx':
            ones = [i for i, v in enumerate(bitmap) if v == '1']
            if not ones:
                return (
                    'const',
                    0,
                )
            dcs = [
                i for i, v in enumerate(bitmap)
                if v == '*' or v == '-' or v.lower() == 'x'
            ]
            pis = get_prime_implicants(ones=ones, dcs=dcs)
            cover = get_exact_covers(ones, pis)[-1]
            clauses = []
            for c in cover:
                if len(c) == 1:
                    term = np.binary_repr(c[0], self._nbits)
                    clause = And(
                        *[v for i, v in enumerate(binstr_to_vars(term))])
                elif len(c) > 1:
                    c_or = reduce(operator.or_, c)
                    c_and = reduce(operator.and_, c)
                    _ = np.binary_repr(c_and ^ c_or, self._nbits)[::-1]
                    clause = And(*[
                        v for i, v in enumerate(
                            binstr_to_vars(np.binary_repr(c_and, self._nbits)))
                        if _[i] == '0'
                    ])
                else:
                    raise AquaError('Unexpected cover term size {}.'.format(
                        len(c)))
                if clause:
                    clauses.append(clause)
            expression = Xor(*clauses)

        raw_ast = expression.to_ast()
        idx_mapping = {
            u: v + 1
            for u, v in zip(sorted(expression.usupport),
                            [v.indices[0] for v in sorted(expression.support)])
        }

        if raw_ast[0] == 'and' or raw_ast[0] == 'or' or raw_ast[0] == 'xor':
            clauses = []
            for c in raw_ast[1:]:
                if c[0] == 'lit':
                    clauses.append(('lit', (idx_mapping[c[1]]) if c[1] > 0 else
                                    (-idx_mapping[-c[1]])))
                elif (c[0] == 'or' or c[0] == 'and') and (raw_ast[0] != c[0]):
                    clause = []
                    for l in c[1:]:
                        clause.append(
                            ('lit', (idx_mapping[l[1]]) if l[1] > 0 else
                             (-idx_mapping[-l[1]])))
                    clauses.append((c[0], *clause))
                else:
                    raise AquaError(
                        'Unrecognized logic expression: {}'.format(raw_ast))
        elif raw_ast[0] == 'lit':
            return 'lit', idx_mapping[
                raw_ast[1]] if raw_ast[1] > 0 else -idx_mapping[-raw_ast[1]]
        elif raw_ast[0] == 'const':
            return raw_ast
        else:
            raise AquaError('Unrecognized root expression type: {}.'.format(
                raw_ast[0]))
        ast = (raw_ast[0], *clauses)
        return ast

    @property
    def variable_register(self):
        return self._variable_register

    @property
    def ancillary_register(self):
        return self._ancillary_register

    @property
    def output_register(self):
        return self._output_register

    def construct_circuit(self):
        if self._circuit is not None:
            return self._circuit
        self._circuit = QuantumCircuit()
        self._output_register = QuantumRegister(self._num_outputs, name='o')
        if self._esops:
            for i, e in enumerate(self._esops):
                if e is not None:
                    ci = e.construct_circuit(
                        output_register=self._output_register, output_idx=i)
                    self._circuit += ci
            self._variable_register = self._ancillary_register = None
            for qreg in self._circuit.qregs:
                if qreg.name == 'v':
                    self._variable_register = qreg
                elif qreg.name == 'a':
                    self._ancillary_register = qreg
        else:
            self._variable_register = QuantumRegister(self._nbits, name='v')
            self._ancillary_register = None
            self._circuit.add_register(self._variable_register,
                                       self._output_register)
        return self._circuit

    def evaluate_classically(self, measurement):
        assignment = [
            (var + 1) * (int(tf) * 2 - 1)
            for tf, var in zip(measurement[::-1], range(len(measurement)))
        ]
        ret = [bitmap[int(measurement, 2)] == '1' for bitmap in self._bitmaps]
        if self._num_outputs == 1:
            return ret[0], assignment
        else:
            return ret, assignment
Esempio n. 23
0
    def construct_circuit(
        self,
        state_register=None,
        ancillary_register=None,
        auxiliary_register=None,
        measurement=False,
    ):
        """Construct the Phase Estimation circuit

        Args:
            state_register (QuantumRegister): the optional register to use for the quantum state
            ancillary_register (QuantumRegister): the optional register to use for
            the ancillary measurement qubits
            auxiliary_register (QuantumRegister): an optional auxiliary quantum register
            measurement (bool): Boolean flag to indicate if measurement should be included
            in the circuit.

        Returns:
            QuantumCircuit: the QuantumCircuit object for the constructed circuit

        Raises:
            RuntimeError: Multiple identity pauli terms are present
            ValueError: invalid mode
        """
        # pylint: disable=invalid-name
        if self._circuit is None:
            if ancillary_register is None:
                a = QuantumRegister(self._num_ancillae, name='a')
            else:
                a = ancillary_register
            self._ancillary_register = a

            if state_register is None:
                if self._operator is not None:
                    q = QuantumRegister(self._operator.num_qubits, name='q')
                elif self._unitary_circuit_factory is not None:
                    q = QuantumRegister(
                        self._unitary_circuit_factory.num_target_qubits,
                        name='q')
                else:
                    raise RuntimeError('Missing operator specification.')
            else:
                q = state_register
            self._state_register = q

            qc = QuantumCircuit(a, q)

            if auxiliary_register is None:
                num_aux_qubits, aux = 0, None
                if self._state_in_circuit_factory is not None:
                    num_aux_qubits = self._state_in_circuit_factory.required_ancillas(
                    )
                if self._unitary_circuit_factory is not None:
                    num_aux_qubits = \
                        max(num_aux_qubits,
                            self._unitary_circuit_factory.required_ancillas_controlled())

                if num_aux_qubits > 0:
                    aux = QuantumRegister(num_aux_qubits, name='aux')
                    qc.add_register(aux)
            else:
                aux = auxiliary_register
                qc.add_register(aux)

            # initialize state_in
            if self._state_in is not None:
                qc.data += self._state_in.construct_circuit('circuit', q).data
            elif self._state_in_circuit_factory is not None:
                self._state_in_circuit_factory.build(qc, q, aux)

            # Put all ancillae in uniform superposition
            qc.u2(0, np.pi, a)

            # phase kickbacks via dynamics
            if self._operator is not None:
                # check for identify paulis to get its coef for applying
                # global phase shift on ancillae later
                num_identities = 0
                for p in self._pauli_list:
                    if np.all(np.logical_not(p[1].z)) and np.all(
                            np.logical_not(p[1].x)):
                        num_identities += 1
                        if num_identities > 1:
                            raise RuntimeError(
                                'Multiple identity pauli terms are present.')
                        self._ancilla_phase_coef = p[0].real if isinstance(
                            p[0], complex) else p[0]

                if len(self._pauli_list) == 1:
                    slice_pauli_list = self._pauli_list
                else:
                    if self._expansion_mode == 'trotter':
                        slice_pauli_list = self._pauli_list
                    elif self._expansion_mode == 'suzuki':
                        slice_pauli_list = suzuki_expansion_slice_pauli_list(
                            self._pauli_list, 1, self._expansion_order)
                    else:
                        raise ValueError(
                            'Unrecognized expansion mode {}.'.format(
                                self._expansion_mode))
                for i in range(self._num_ancillae):

                    qc_evolutions_inst = evolution_instruction(
                        slice_pauli_list,
                        -self._evo_time,
                        self._num_time_slices,
                        controlled=True,
                        power=(2**i),
                        shallow_slicing=self._shallow_circuit_concat)
                    if self._shallow_circuit_concat:
                        qc_evolutions = QuantumCircuit(q, a)
                        qc_evolutions.append(qc_evolutions_inst,
                                             qargs=list(q) + [a[i]])
                        qc.data += qc_evolutions.data
                    else:
                        qc.append(qc_evolutions_inst, qargs=list(q) + [a[i]])
                    # global phase shift for the ancilla due to the identity pauli term
                    qc.u1(self._evo_time * self._ancilla_phase_coef * (2**i),
                          a[i])

            elif self._unitary_circuit_factory is not None:
                for i in range(self._num_ancillae):
                    self._unitary_circuit_factory.build_controlled_power(
                        qc, q, a[i], 2**i, aux)

            # inverse qft on ancillae
            if isinstance(self._iqft, QuantumCircuit):
                # check if QFT has the right size
                if self._iqft.num_qubits != len(a):
                    try:  # try resizing
                        self._iqft.num_qubits = len(a)
                    except AttributeError:
                        raise ValueError(
                            'The IQFT cannot be resized and does not have the '
                            'required size of {}'.format(len(a)))

                if hasattr(self._iqft, 'do_swaps'):
                    self._iqft.do_swaps = False
                qc.append(self._iqft.to_instruction(), a)
            else:
                self._iqft.construct_circuit(mode='circuit',
                                             qubits=a,
                                             circuit=qc,
                                             do_swaps=False)

            if measurement:
                c_ancilla = ClassicalRegister(self._num_ancillae, name='ca')
                qc.add_register(c_ancilla)
                # real hardware can currently not handle operations after measurements, which might
                # happen if the circuit gets transpiled, hence we're adding a safeguard-barrier
                qc.barrier()
                qc.measure(a, c_ancilla)

            self._circuit = qc
        return self._circuit
Esempio n. 24
0
class BruteforceISDCircuit(ISDAbstractCircuit):

    # mct stands for qiskit aqua multicontrol
    # nwr stands for n bits of weight r
    def __init__(self, h, syndrome, w, need_measures, mct_mode, nwr_mode):
        super().__init__(need_measures, mct_mode, nwr_mode)
        assert w > 0, "Weight must be positive"
        self.h = h
        self.w = w
        self.r = h.shape[0]
        self.n = h.shape[1]
        assert syndrome.shape[0] == self.r, "Syndrome should be of length r"
        self.syndrome = syndrome
        _logger.info(
            "n: {0}, r: {1}, w: {2}, syndrome: {3}, measures: {4}, mct_mode: {5}"
            .format(self.n, self.r, self.w, self.syndrome, self.need_measures,
                    self.mct_mode))
        self._initialize_circuit()

    def _initialize_circuit(self):
        """
        Initialize the circuit with n qubits. The n is the same n of the H parity matrix and it is used to represent the choice of the column of the matrix.

        :param n: The number of qubits
        :returns: the quantum circuit and the selectors_q register
        :rtype:

        """
        self.circuit = QuantumCircuit(
            name="bruteforce_{0}_{1}_{2}_{3}_{4}".format(
                self.n, self.r, self.w, self.mct_mode, self.nwr_mode))
        # TODO
        qubits_involved_in_multicontrols = []
        if self.nwr_mode == self.NWR_BENES:
            # To compute benes_flip_q size and the permutation pattern
            self.benes_dict = hwg.generate_qubits_with_given_weight_benes_get_pattern(
                self.n, self.w)

            # We don't use only n qubits, but the nearest power of 2
            self.selectors_q = QuantumRegister(self.benes_dict['n_lines'],
                                               'select')
            self.benes_flip_q = QuantumRegister(self.benes_dict['n_flips'],
                                                "flip")
            self.n_func_domain = len(self.benes_flip_q) + self.w
            self.circuit.add_register(self.selectors_q)
            self.circuit.add_register(self.benes_flip_q)
            self.inversion_about_zero_qubits = self.benes_flip_q
        elif self.nwr_mode == self.NWR_FPC:
            self.fpc_dict = hwc.get_circuit_for_qubits_weight_get_pattern(
                self.n)
            self.selectors_q = QuantumRegister(self.fpc_dict['n_lines'],
                                               'select')
            self.fpc_cout_q = QuantumRegister(self.fpc_dict['n_couts'], 'cout')
            self.fpc_cin_q = QuantumRegister(1, 'cin')
            self.fpc_eq_q = QuantumRegister(1, 'eq')
            self.fpc_two_eq_q = QuantumRegister(1, 'f2eq')
            self.n_func_domain = 2**len(self.selectors_q)
            self.circuit.add_register(self.fpc_cin_q)
            self.circuit.add_register(self.selectors_q)
            self.circuit.add_register(self.fpc_cout_q)
            self.circuit.add_register(self.fpc_eq_q)
            self.circuit.add_register(self.fpc_two_eq_q)
            self.inversion_about_zero_qubits = self.selectors_q
            qubits_involved_in_multicontrols.append(
                len(self.fpc_dict['results']))

        # We should implement a check on n if it's not a power of 2
        if len(self.selectors_q) != self.n:
            raise Exception("A.T.M. we can't have less registers")

        qubits_involved_in_multicontrols.append(
            len(self.inversion_about_zero_qubits[1:]))

        self.sum_q = QuantumRegister(self.r, 'sum')
        self.circuit.add_register(self.sum_q)

        if self.mct_mode == self.MCT_ADVANCED:
            self.mct_anc = QuantumRegister(1, 'mctAnc')
            self.circuit.add_register(self.mct_anc)
        elif self.mct_mode == self.MCT_BASIC:
            _logger.debug("qubits involved in multicontrols are {}".format(
                qubits_involved_in_multicontrols))
            self.mct_anc = QuantumRegister(
                max(qubits_involved_in_multicontrols) - 2, 'mctAnc')
            self.circuit.add_register(self.mct_anc)
        elif self.mct_mode == self.MCT_NOANCILLA:
            # no ancilla to add
            self.mct_anc = None

        self.to_measure = self.selectors_q

    def prepare_input(self):
        _logger.debug("Here")
        self.circuit.barrier()
        if self.nwr_mode == self.NWR_BENES:
            self.circuit.h(self.benes_flip_q)
            hwg.generate_qubits_with_given_weight_benes(
                self.circuit, self.selectors_q, self.benes_flip_q,
                self.benes_dict)
        elif self.nwr_mode == self.NWR_FPC:
            self.circuit.h(self.selectors_q)
        self.circuit.barrier()

    def prepare_input_i(self):
        _logger.debug("Here")
        self.circuit.barrier()
        if self.nwr_mode == self.NWR_BENES:
            hwg.generate_qubits_with_given_weight_benes_i(
                self.circuit, self.selectors_q, self.benes_flip_q,
                self.benes_dict)
            self.circuit.h(self.benes_flip_q)
        elif self.nwr_mode == self.NWR_FPC:
            self.circuit.h(self.selectors_q)
        self.circuit.barrier()

    def _hamming_weight_selectors_check(self):
        _logger.debug("Here")
        self.circuit.barrier()
        self.fpc_result_qubits = hwc.get_circuit_for_qubits_weight_check(
            self.circuit, self.selectors_q, self.fpc_cin_q, self.fpc_cout_q,
            self.fpc_eq_q, self.mct_anc, self.w, self.fpc_dict)
        self.circuit.barrier()
        _logger.debug(
            "Result qubits for Hamming Weight of selectors {}".format(
                self.fpc_result_qubits))

    def _hamming_weight_selectors_check_i(self):
        _logger.debug("Here")
        self.circuit.barrier()
        self.fpc_result_qubits = hwc.get_circuit_for_qubits_weight_check_i(
            self.circuit, self.selectors_q, self.fpc_cin_q, self.fpc_cout_q,
            self.fpc_eq_q, self.mct_anc, self.w, self.fpc_dict,
            self.fpc_result_qubits)
        self.circuit.barrier()

    def _matrix2gates(self):
        _logger.debug("Here")
        self.circuit.barrier()
        for i in range(self.h.shape[1]):
            qregs.conditionally_initialize_qureg_given_bitstring(
                self.h[:, i].tolist(), self.sum_q, [self.selectors_q[i]], None,
                self.circuit, self.mct_mode)
        self.circuit.barrier()

    def _matrix2gates_i(self):
        _logger.debug("Here")
        self.circuit.barrier()
        for i in reversed(range(self.h.shape[1])):
            qregs.conditionally_initialize_qureg_given_bitstring(
                self.h[:, i].tolist(), self.sum_q, [self.selectors_q[i]], None,
                self.circuit, self.mct_mode)
        self.circuit.barrier()

    def _syndrome2gates(self):
        _logger.debug("Here")
        self.circuit.barrier()
        qregs.initialize_qureg_to_complement_of_bitarray(
            self.syndrome.tolist(), self.sum_q, self.circuit)
        self.circuit.barrier()

    def _syndrome2gates_i(self):
        return self._syndrome2gates()

    def _flip_correct_state(self):
        _logger.debug("Here")
        self.circuit.barrier()
        if self.nwr_mode == self.NWR_BENES:
            controls_q = self.sum_q[1:]
            to_invert_q = self.sum_q[0]
        elif self.nwr_mode == self.NWR_FPC:
            controls_q = [self.fpc_eq_q[0]] + [qr for qr in self.sum_q[1:]]
            to_invert_q = self.sum_q[0]
        # A CZ obtained by H CX H
        self.circuit.h(to_invert_q)
        self.circuit.mct(
            controls_q, to_invert_q, self.mct_anc, mode=self.mct_mode)
        self.circuit.h(to_invert_q)
        # CZ END
        self.circuit.barrier()

    def oracle(self):
        _logger.debug("Here")
        if self.nwr_mode == self.NWR_BENES:
            self._matrix2gates()
            self._syndrome2gates()
            self._flip_correct_state()
            self._syndrome2gates_i()
            self._matrix2gates_i()
        elif self.nwr_mode == self.NWR_FPC:
            self._matrix2gates()
            self._syndrome2gates()
            self._hamming_weight_selectors_check()
            self._flip_correct_state()
            self._hamming_weight_selectors_check_i()
            self._syndrome2gates_i()
            self._matrix2gates_i()
Esempio n. 25
0
from qiskit import QuantumRegister, QuantumCircuit

qc = QuantumCircuit()
q = QuantumRegister(5, 'q')
qc.add_register(q)

# searched bit string: s = 01001
qc.x(q[1])
qc.x(q[2])
qc.x(q[4])
qc.h(q[4])
qc.mct(list(range(4)), 4)
qc.h(q[4])
qc.x(q[1])
qc.x(q[2])
qc.x(q[4])


def get_circuit(**kwargs):
    """Get oracle circuit."""
    return qc
Esempio n. 26
0
                       \ 
                (q2)---(q0)---(q1)
                     |      |
                     |      |
                    [q5]   [q4]   

States |1000> and |0111> gives us the maximum probability, because it means, that
one vertice (q0) is in one zone, and all the others vertices are in the other zone.


                
"""
q = QuantumRegister(11)
c = ClassicalRegister(4)
circ = QuantumCircuit()
circ.add_register(q)
circ.add_register(c)


def prepare():
    """ Put vertices in the zones. Into the superposition state to check all the possibilites once.
    """
    circ.h(q[0:4])

    # Oracle phase flip
    circ.x(q[10])
    circ.h(q[10])


def cutter_edge_checker(a: QuantumRegister, b: QuantumRegister,
                        res: QuantumRegister):
class QCircuitMachine(RuleBasedStateMachine):
    """Build a Hypothesis rule based state machine for constructing, transpiling
    and simulating a series of random QuantumCircuits.

    Build circuits with up to QISKIT_RANDOM_QUBITS qubits, apply a random
    selection of gates from qiskit.circuit.library with randomly selected
    qargs, cargs, and parameters. At random intervals, transpile the circuit for
    a random backend with a random optimization level and simulate both the
    initial and the transpiled circuits to verify that their counts are the
    same.

    """

    qubits = Bundle("qubits")
    clbits = Bundle("clbits")

    backend = Aer.get_backend("qasm_simulator")
    max_qubits = int(backend.configuration().n_qubits / 2)

    def __init__(self):
        super().__init__()
        self.qc = QuantumCircuit()

    @precondition(lambda self: len(self.qc.qubits) < self.max_qubits)
    @rule(target=qubits, n=st.integers(min_value=1, max_value=max_qubits))
    def add_qreg(self, n):
        """Adds a new variable sized qreg to the circuit, up to max_qubits."""
        n = min(n, self.max_qubits - len(self.qc.qubits))
        qreg = QuantumRegister(n)
        self.qc.add_register(qreg)
        return multiple(*list(qreg))

    @rule(target=clbits, n=st.integers(1, 5))
    def add_creg(self, n):
        """Add a new variable sized creg to the circuit."""
        creg = ClassicalRegister(n)
        self.qc.add_register(creg)
        return multiple(*list(creg))

    # Gates of various shapes

    @rule(gate=st.sampled_from(oneQ_gates), qarg=qubits)
    def add_1q_gate(self, gate, qarg):
        """Append a random 1q gate on a random qubit."""
        self.qc.append(gate(), [qarg], [])

    @rule(
        gate=st.sampled_from(twoQ_gates),
        qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
    )
    def add_2q_gate(self, gate, qargs):
        """Append a random 2q gate across two random qubits."""
        self.qc.append(gate(), qargs)

    @rule(
        gate=st.sampled_from(threeQ_gates),
        qargs=st.lists(qubits, max_size=3, min_size=3, unique=True),
    )
    def add_3q_gate(self, gate, qargs):
        """Append a random 3q gate across three random qubits."""
        self.qc.append(gate(), qargs)

    @rule(
        gate=st.sampled_from(oneQ_oneP_gates),
        qarg=qubits,
        param=st.floats(
            allow_nan=False,
            allow_infinity=False,
            min_value=-10 * pi,
            max_value=10 * pi,
            allow_subnormal=False,
        ),
    )
    def add_1q1p_gate(self, gate, qarg, param):
        """Append a random 1q gate with 1 random float parameter."""
        self.qc.append(gate(param), [qarg])

    @rule(
        gate=st.sampled_from(oneQ_twoP_gates),
        qarg=qubits,
        params=st.lists(
            st.floats(
                allow_nan=False,
                allow_infinity=False,
                min_value=-10 * pi,
                max_value=10 * pi,
                allow_subnormal=False,
            ),
            min_size=2,
            max_size=2,
        ),
    )
    def add_1q2p_gate(self, gate, qarg, params):
        """Append a random 1q gate with 2 random float parameters."""
        self.qc.append(gate(*params), [qarg])

    @rule(
        gate=st.sampled_from(oneQ_threeP_gates),
        qarg=qubits,
        params=st.lists(
            st.floats(
                allow_nan=False,
                allow_infinity=False,
                min_value=-10 * pi,
                max_value=10 * pi,
                allow_subnormal=False,
            ),
            min_size=3,
            max_size=3,
        ),
    )
    def add_1q3p_gate(self, gate, qarg, params):
        """Append a random 1q gate with 3 random float parameters."""
        self.qc.append(gate(*params), [qarg])

    @rule(
        gate=st.sampled_from(twoQ_oneP_gates),
        qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
        param=st.floats(
            allow_nan=False,
            allow_infinity=False,
            min_value=-10 * pi,
            max_value=10 * pi,
            allow_subnormal=False,
        ),
    )
    def add_2q1p_gate(self, gate, qargs, param):
        """Append a random 2q gate with 1 random float parameter."""
        self.qc.append(gate(param), qargs)

    @rule(
        gate=st.sampled_from(twoQ_threeP_gates),
        qargs=st.lists(qubits, max_size=2, min_size=2, unique=True),
        params=st.lists(
            st.floats(
                allow_nan=False,
                allow_infinity=False,
                min_value=-10 * pi,
                max_value=10 * pi,
                allow_subnormal=False,
            ),
            min_size=3,
            max_size=3,
        ),
    )
    def add_2q3p_gate(self, gate, qargs, params):
        """Append a random 2q gate with 3 random float parameters."""
        self.qc.append(gate(*params), qargs)

    @rule(gate=st.sampled_from(oneQ_oneC_gates), qarg=qubits, carg=clbits)
    def add_1q1c_gate(self, gate, qarg, carg):
        """Append a random 1q, 1c gate."""
        self.qc.append(gate(), [qarg], [carg])

    @rule(gate=st.sampled_from(variadic_gates), qargs=st.lists(qubits, min_size=1, unique=True))
    def add_variQ_gate(self, gate, qargs):
        """Append a gate with a variable number of qargs."""
        self.qc.append(gate(len(qargs)), qargs)

    @precondition(lambda self: len(self.qc.data) > 0)
    @rule(carg=clbits, data=st.data())
    def add_c_if_last_gate(self, carg, data):
        """Modify the last gate to be conditional on a classical register."""
        creg = carg.register
        val = data.draw(st.integers(min_value=0, max_value=2 ** len(creg) - 1))

        last_gate = self.qc.data[-1]

        # Conditional instructions are not supported
        assume(isinstance(last_gate[0], Gate))

        last_gate[0].c_if(creg, val)

    # Properties to check

    @invariant()
    def qasm(self):
        """After each circuit operation, it should be possible to build QASM."""
        self.qc.qasm()

    @precondition(lambda self: any(isinstance(d[0], Measure) for d in self.qc.data))
    @rule(
        backend=st.one_of(st.none(), st.sampled_from(mock_backends)),
        opt_level=st.integers(min_value=0, max_value=3),
    )
    def equivalent_transpile(self, backend, opt_level):
        """Simulate, transpile and simulate the present circuit. Verify that the
        counts are not significantly different before and after transpilation.

        """

        print(f"Evaluating circuit at level {opt_level} on {backend}:\n{self.qc.qasm()}")

        assume(backend is None or backend.configuration().n_qubits >= len(self.qc.qubits))

        shots = 4096

        aer_counts = execute(self.qc, backend=self.backend, shots=shots).result().get_counts()

        try:
            xpiled_qc = transpile(self.qc, backend=backend, optimization_level=opt_level)
        except Exception as e:
            failed_qasm = "Exception caught during transpilation of circuit: \n{}".format(
                self.qc.qasm()
            )
            raise RuntimeError(failed_qasm) from e

        xpiled_aer_counts = (
            execute(xpiled_qc, backend=self.backend, shots=shots).result().get_counts()
        )

        count_differences = dicts_almost_equal(aer_counts, xpiled_aer_counts, 0.05 * shots)

        assert count_differences == "", "Counts not equivalent: {}\nFailing QASM: \n{}".format(
            count_differences, self.qc.qasm()
        )
    def add_circuits(self,
                     n_circuits,
                     do_measure=True,
                     basis=None,
                     basis_weights=None):
        """Adds circuits to program.

        Generates a circuit with a random number of operations in `basis`.
        Also adds a random number of measurements in
        [1,nQubits] to end of circuit.

        Args:
            n_circuits (int): Number of circuits to add.
            do_measure (bool): Whether to add measurements.
            basis (list(str) or None): List of op names. If None, basis
                is randomly chosen with unique ops in (2,7)
            basis_weights (list(float) or None): List of weights
                corresponding to indices in `basis`.
        Raises:
            AttributeError: if operation is not recognized.
        """
        if basis is None:
            basis = list(
                random.sample(self.op_signature.keys(), random.randint(2, 7)))
            basis_weights = [1. / len(basis)] * len(basis)
        if basis_weights is not None:
            assert len(basis) == len(basis_weights)
        uop_basis = basis[:]
        if basis_weights:
            uop_basis_weights = basis_weights[:]
        else:
            uop_basis_weights = None
        # remove barrier from uop basis if it is specified
        if 'barrier' in uop_basis:
            ind = uop_basis.index('barrier')
            del uop_basis[ind]
            if uop_basis_weights:
                del uop_basis_weights[ind]
        # remove measure from uop basis if it is specified
        if 'measure' in uop_basis:
            ind = uop_basis.index('measure')
            del uop_basis[ind]
            if uop_basis_weights:
                del uop_basis_weights[ind]
        # self.basis_gates = uop_basis
        self.basis_gates = basis
        self.circuit_name_list = []
        # TODO: replace choices with random.choices() when python 3.6 is
        # required.
        self.n_qubit_list = choices(range(self.min_qubits,
                                          self.max_qubits + 1),
                                    k=n_circuits)
        self.depth_list = choices(range(self.min_depth, self.max_depth + 1),
                                  k=n_circuits)
        for i_circuit in range(n_circuits):
            n_qubits = self.n_qubit_list[i_circuit]
            if self.min_regs_exceeds_nqubits(uop_basis, n_qubits):
                # no gate operation from this circuit can fit in the available
                # number of qubits.
                continue
            depth_cnt = self.depth_list[i_circuit]
            reg_pop = numpy.arange(1, n_qubits + 1)
            register_weights = reg_pop[::-1].astype(float)
            register_weights /= register_weights.sum()
            max_registers = numpy.random.choice(reg_pop, p=register_weights)
            reg_weight = numpy.ones(max_registers) / float(max_registers)
            reg_sizes = rand_register_sizes(n_qubits, reg_weight)
            n_registers = len(reg_sizes)
            circuit = QuantumCircuit()
            for i_size, size in enumerate(reg_sizes):
                cr_name = 'cr' + str(i_size)
                qr_name = 'qr' + str(i_size)
                creg = ClassicalRegister(int(size), cr_name)
                qreg = QuantumRegister(int(size), qr_name)
                circuit.add_register(qreg, creg)
            while depth_cnt > 0:
                # TODO: replace choices with random.choices() when python 3.6
                # is required.
                op_name = choices(basis, weights=basis_weights)[0]
                if hasattr(circuit, op_name):
                    operator = getattr(circuit, op_name)
                else:
                    raise AttributeError('operation \"{0}\"'
                                         ' not recognized'.format(op_name))
                n_regs = self.op_signature[op_name]['nregs']
                n_params = self.op_signature[op_name]['nparams']
                if n_regs == 0:  # this is a barrier or measure
                    n_regs = random.randint(1, n_qubits)
                if n_qubits >= n_regs:
                    # warning: assumes op function signature specifies
                    # op parameters before qubits
                    op_args = []
                    if n_params:
                        op_args = [random.random() for _ in range(n_params)]
                    if op_name == 'measure':
                        # if measure occurs here, assume it's to do a conditional
                        # randomly select a register to measure
                        ireg = random.randint(0, n_registers - 1)
                        qr_name = 'qr' + str(ireg)
                        cr_name = 'cr' + str(ireg)
                        qreg = circuit.regs[qr_name]
                        creg = circuit.regs[cr_name]
                        for qind in range(qreg.size):
                            operator(qreg[qind], creg[qind])
                        ifval = random.randint(0, (1 << qreg.size) - 1)
                        # TODO: replace choices with random.choices() when
                        # python 3.6 is required.
                        uop_name = choices(uop_basis,
                                           weights=uop_basis_weights)[0]
                        if hasattr(circuit, uop_name):
                            uop = getattr(circuit, uop_name)
                        else:
                            raise AttributeError(
                                'operation \"{0}\"'
                                ' not recognized'.format(uop_name))
                        unregs = self.op_signature[uop_name]['nregs']
                        unparams = self.op_signature[uop_name]['nparams']
                        if unregs == 0:  # this is a barrier or measure
                            unregs = random.randint(1, n_qubits)
                        if qreg.size >= unregs:
                            qind_list = random.sample(range(qreg.size), unregs)
                            uop_args = []
                            if unparams:
                                uop_args = [
                                    random.random() for _ in range(unparams)
                                ]
                            uop_args.extend([qreg[qind] for qind in qind_list])
                            uop(*uop_args).c_if(creg, ifval)
                        depth_cnt -= 1
                    elif op_name == 'barrier':
                        ireg = random.randint(0, n_registers - 1)
                        qreg = circuit.qregs[ireg]
                        bar_args = [(qreg, mi) for mi in range(qreg.size)]
                        operator(*bar_args)
                    else:
                        # select random register
                        ireg = random.randint(0, n_registers - 1)
                        qreg = circuit.qregs[ireg]
                        if qreg.size >= n_regs:
                            qind_list = random.sample(range(qreg.size), n_regs)
                            op_args.extend([qreg[qind] for qind in qind_list])
                            operator(*op_args)
                            depth_cnt -= 1
                        else:
                            break
            nmeasure = random.randint(1, n_qubits)
            m_list = random.sample(range(nmeasure), nmeasure)
            if do_measure:
                for qind in m_list:
                    rind = 0  # register index
                    cumtot = 0
                    while qind >= cumtot + circuit.qregs[rind].size:
                        cumtot += circuit.qregs[rind].size
                        rind += 1
                    qrind = int(qind - cumtot)
                    qreg = circuit.qregs[rind]
                    creg = circuit.cregs[rind]
                    circuit.measure(qreg[qrind], creg[qrind])
            self.circuit_list.append(circuit)
    def _make_syndrome_graph(self):
        """
        This method injects all possible Pauli errors into the circuit for
        ``code``.

        This is done by examining the qubits used in each gate of the
        circuit for a stored logical 0. A graph is then created with a node
        for each non-trivial syndrome element, and an edge between all such
        elements that can be created by the same error.
        """

        S = rx.PyGraph(multigraph=False)

        qc = self.code.circuit['0']

        blank_qc = QuantumCircuit()
        for qreg in qc.qregs:
            blank_qc.add_register(qreg)
        for creg in qc.cregs:
            blank_qc.add_register(creg)

        error_circuit = {}
        circuit_name = {}
        depth = len(qc)
        for j in range(depth):
            qubits = qc.data[j][1]
            for qubit in qubits:
                for error in ['x', 'y', 'z']:
                    temp_qc = copy.deepcopy(blank_qc)
                    temp_qc.name = str((j, qubit, error))
                    temp_qc.data = qc.data[0:j]
                    getattr(temp_qc, error)(qubit)
                    temp_qc.data += qc.data[j:depth + 1]
                    circuit_name[(j, qubit, error)] = temp_qc.name
                    error_circuit[temp_qc.name] = temp_qc

        if HAS_AER:
            simulator = Aer.get_backend('qasm_simulator')
        else:
            simulator = BasicAer.get_backend('qasm_simulator')

        job = execute(list(error_circuit.values()), simulator)

        node_map = {}
        for j in range(depth):
            qubits = qc.data[j][1]
            for qubit in qubits:
                for error in ['x', 'y', 'z']:
                    raw_results = {}
                    raw_results['0'] = job.result().get_counts(
                        str((j, qubit, error)))
                    results = self.code.process_results(raw_results)['0']

                    for string in results:

                        nodes = self._string2nodes(string)

                        assert len(nodes) in [0, 2], "Error of type " + \
                            error + " on qubit " + str(qubit) + \
                            " at depth " + str(j) + " creates " + \
                            str(len(nodes)) + \
                            " nodes in syndrome graph, instead of 2."
                        for node in nodes:
                            if node not in node_map:
                                node_map[node] = S.add_node(node)
                        for source in nodes:
                            for target in nodes:
                                if target != source:
                                    S.add_edge(node_map[source],
                                               node_map[target], 1)

        return S
Esempio n. 30
0
teleportation_circuit = QuantumCircuit(qr, crz, crx)

teleportation_circuit.append(init_gate, [0])

create_bell_pair(teleportation_circuit, 1, 2)
teleportation_circuit.barrier()

alice_gates(teleportation_circuit, 0, 1)
teleportation_circuit.barrier()

measure_and_send(teleportation_circuit, 0, 1)
teleportation_circuit.barrier()

bob_gates(teleportation_circuit, 2, crz, crx)

teleportation_circuit.append(inverse_init_gate, [2])
cr_result = ClassicalRegister(1)
teleportation_circuit.add_register(cr_result)
teleportation_circuit.measure(2, 2)

print(teleportation_circuit.draw())

backend = BasicAer.get_backend("qasm_simulator")
shots = 100
results = execute(teleportation_circuit, backend=backend).result()
answer = results.get_counts()
# fig = plt.figure()
fig = plot_histogram(answer)
plt.show()