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
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)
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
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
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
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)
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
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")
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])
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
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
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
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
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
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']))
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
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
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
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()
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
\ (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
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()