def _build_one_sector(available_hopping_ops, untapered_op, z2_symmetries): to_be_computed_list = [] for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] left_op = available_hopping_ops.get('E_{}'.format(m_u)) right_op_1 = available_hopping_ops.get('E_{}'.format(n_u)) right_op_2 = available_hopping_ops.get('Edag_{}'.format(n_u)) to_be_computed_list.append( (m_u, n_u, left_op, right_op_1, right_op_2)) if logger.isEnabledFor(logging.INFO): logger.info("Building all commutators:") TextProgressBar(sys.stderr) results = parallel_map( self._build_commutator_routine, to_be_computed_list, task_args=(untapered_op, z2_symmetries), num_processes=algorithm_globals.num_processes) for result in results: m_u, n_u, q_mat_op, w_mat_op, m_mat_op, v_mat_op = result if q_mat_op is not None: all_matrix_operators['q_{}_{}'.format(m_u, n_u)] = q_mat_op if w_mat_op is not None: all_matrix_operators['w_{}_{}'.format(m_u, n_u)] = w_mat_op if m_mat_op is not None: all_matrix_operators['m_{}_{}'.format(m_u, n_u)] = m_mat_op if v_mat_op is not None: all_matrix_operators['v_{}_{}'.format(m_u, n_u)] = v_mat_op
def construct_circuit( self, parameters: Union[np.ndarray, List[Parameter], ParameterVector], q: Optional[QuantumRegister] = None) -> QuantumCircuit: """Construct the variational form, given its parameters. Args: parameters: circuit parameters q: Quantum Register for the circuit. Returns: Quantum Circuit a quantum circuit with given `parameters` Raises: ValueError: the number of parameters is incorrect. ValueError: if num_qubits has not been set and is still None """ if len(parameters) != self._num_parameters: raise ValueError('The number of parameters has to be {}'.format( self._num_parameters)) if self._num_qubits is None: raise ValueError( 'The number of qubits is None and must be set before the circuit ' 'can be created.') if q is None: q = QuantumRegister(self._num_qubits, name='q') if isinstance(self._initial_state, QuantumCircuit): circuit = QuantumCircuit(q) circuit.append(self._initial_state.to_gate(), range(self._initial_state.num_qubits)) elif self._initial_state is not None: circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) if logger.isEnabledFor( logging.DEBUG) and self._logging_construct_circuit: logger.debug("Evolving hopping operators:") TextProgressBar(sys.stderr) self._logging_construct_circuit = False num_excitations = len(self._hopping_ops) results = parallel_map( UVCC._construct_circuit_for_one_excited_operator, [(self._hopping_ops[index % num_excitations], parameters[index]) for index in range(self._reps * num_excitations)], task_args=(q, self._num_time_slices), num_processes=aqua_globals.num_processes) for qc in results: if self._shallow_circuit_concat: circuit.data += qc.data else: circuit += qc return circuit
def _build_one_sector(available_hopping_ops): to_be_computed_list = [] for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] left_op = available_hopping_ops.get( '_'.join([str(x) for x in excitations_list[m_u]]), None) right_op_1 = available_hopping_ops.get( '_'.join([str(x) for x in excitations_list[n_u]]), None) right_op_2 = available_hopping_ops.get( '_'.join([str(x) for x in reversed(excitations_list[n_u])]), None) to_be_computed_list.append((m_u, n_u, left_op, right_op_1, right_op_2)) if logger.isEnabledFor(logging.INFO): logger.info("Building all commutators:") TextProgressBar(sys.stderr) results = parallel_map(QEquationOfMotion._build_commutator_rountine, to_be_computed_list, task_args=(self._untapered_op, self._z2_symmetries)) for result in results: m_u, n_u, q_mat_op, w_mat_op, m_mat_op, v_mat_op = result q_commutators[m_u][n_u] = op_converter.to_tpb_grouped_weighted_pauli_operator( q_mat_op, TPBGroupedWeightedPauliOperator.sorted_grouping) \ if q_mat_op is not None else q_commutators[m_u][n_u] w_commutators[m_u][n_u] = op_converter.to_tpb_grouped_weighted_pauli_operator( w_mat_op, TPBGroupedWeightedPauliOperator.sorted_grouping) \ if w_mat_op is not None else w_commutators[m_u][n_u] m_commutators[m_u][n_u] = op_converter.to_tpb_grouped_weighted_pauli_operator( m_mat_op, TPBGroupedWeightedPauliOperator.sorted_grouping) \ if m_mat_op is not None else m_commutators[m_u][n_u] v_commutators[m_u][n_u] = op_converter.to_tpb_grouped_weighted_pauli_operator( v_mat_op, TPBGroupedWeightedPauliOperator.sorted_grouping) \ if v_mat_op is not None else v_commutators[m_u][n_u]
def to_weighted_pauli_operator(operator): """ Converting a given operator to `WeightedPauliOperator` Args: operator (WeightedPauliOperator | TPBGroupedWeightedPauliOperator | MatrixOperator | Operator): one of supported operator type Returns: WeightedPauliOperator: the converted weighted pauli operator """ if operator.__class__ == WeightedPauliOperator: return operator elif operator.__class__ == TPBGroupedWeightedPauliOperator: # destroy the grouping but keep z2 symmetries info return WeightedPauliOperator(paulis=operator.paulis, z2_symmetries=operator.z2_symmetries, name=operator.name) elif operator.__class__ == MatrixOperator: if operator.is_empty(): return WeightedPauliOperator(paulis=[]) logger.warning( "Converting time from a MatrixOperator to a Pauli-type Operator grows exponentially. " "If you are converting a system with large number of qubits, it will take time. " "You can turn on DEBUG logging to check the progress.") num_qubits = operator.num_qubits coeff = 2**(-num_qubits) paulis = [] possible_basis = 'IXYZ' if operator.dia_matrix is not None: possible_basis = 'IZ' if logger.isEnabledFor(logging.DEBUG): logger.debug( "Converting a MatrixOperator to a Pauli-type Operator:") TextProgressBar(sys.stderr) results = parallel_map(_conversion, [ basis for basis in itertools.product(possible_basis, repeat=num_qubits) ], task_kwargs={"matrix": operator._matrix}, num_processes=aqua_globals.num_processes) for trace_value, pauli in results: weight = trace_value * coeff if weight != 0.0 and np.abs(weight) > operator.atol: paulis.append([weight, pauli]) return WeightedPauliOperator(paulis, z2_symmetries=operator.z2_symmetries, name=operator.name) elif operator.__class__ == Operator: warnings.warn( "The `Operator` class is deprecated. Please use `WeightedPauliOperator` or " "`TPBGroupedWeightedPauliOperator` or `MatrixOperator` instead", DeprecationWarning) return operator.to_weighted_pauli_operator() else: raise AquaError( "Unsupported type to convert to WeightedPauliOperator: {}".format( operator.__class__))
def _build_hopping_operators(self): if logger.isEnabledFor(logging.DEBUG): TextProgressBar(sys.stderr) results = parallel_map( UCCSD._build_hopping_operator, self._single_excitations + self._double_excitations, task_args=(self._num_orbitals, self._num_particles, self._qubit_mapping, self._two_qubit_reduction, self._z2_symmetries, self._skip_commute_test), num_processes=aqua_globals.num_processes) hopping_ops = [] s_e_list = [] d_e_list = [] for op, index in results: if op is not None and not op.is_empty(): hopping_ops.append(op) if len(index) == 2: # for double excitation s_e_list.append(index) else: # for double excitation d_e_list.append(index) self._single_excitations = s_e_list self._double_excitations = d_e_list num_parameters = len(hopping_ops) * self._depth return hopping_ops, num_parameters
def evaluate_with_result(self, result, statevector_mode, use_simulator_operator_mode=False, circuit_name_prefix=''): """ This method can be only used with the circuits generated by the `construct_evaluation_circuit` method with the same `circuit_name_prefix` since the circuit names are tied to some meanings. Calculate the evaluated value with the measurement results. Args: result (qiskit.Result): the result from the backend. statevector_mode (bool): indicate which type of simulator are used. use_simulator_operator_mode (bool): if aer_provider is used, we can do faster evaluation for pauli mode on statevector simulation circuit_name_prefix (str): a prefix of circuit name Returns: float: the mean value float: the standard deviation Raises: AquaError: if Operator is empty """ if self.is_empty(): raise AquaError("Operator is empty, check the operator.") avg, std_dev, variance = 0.0, 0.0, 0.0 if statevector_mode: if use_simulator_operator_mode: temp = \ result.data( circuit_name_prefix + 'aer_mode')[ 'snapshots']['expectation_value']['test'][0]['value'] avg = temp[0] + 1j * temp[1] else: quantum_state = np.asarray(result.get_statevector(circuit_name_prefix + 'psi')) for weight, pauli in self._paulis: # all I if np.all(np.logical_not(pauli.z)) and np.all(np.logical_not(pauli.x)): avg += weight else: quantum_state_i = \ result.get_statevector(circuit_name_prefix + pauli.to_label()) avg += (weight * (np.vdot(quantum_state, quantum_state_i))) else: if logger.isEnabledFor(logging.DEBUG): logger.debug("Computing the expectation from measurement results:") TextProgressBar(sys.stderr) # pick the first result to get the total number of shots num_shots = sum(list(result.get_counts(0).values())) results = parallel_map(WeightedPauliOperator._routine_compute_mean_and_var, [([self._paulis[idx] for idx in indices], result.get_counts(circuit_name_prefix + basis.to_label())) for basis, indices in self._basis], num_processes=aqua_globals.num_processes) for res in results: avg += res[0] variance += res[1] std_dev = np.sqrt(variance / num_shots) return avg, std_dev
def to_weighted_pauli_operator( operator: Union[WeightedPauliOperator, TPBGroupedWeightedPauliOperator, MatrixOperator]) \ -> WeightedPauliOperator: """ Converting a given operator to `WeightedPauliOperator` Args: operator: one of supported operator type Returns: The converted weighted pauli operator Raises: AquaError: Unsupported type to convert Warnings: Converting time from a MatrixOperator to a Pauli-type Operator grows exponentially. If you are converting a system with large number of qubits, it will take time. You can turn on DEBUG logging to check the progress. """ if operator.__class__ == WeightedPauliOperator: return cast(WeightedPauliOperator, operator) elif operator.__class__ == TPBGroupedWeightedPauliOperator: # destroy the grouping but keep z2 symmetries info op_tpb = cast(TPBGroupedWeightedPauliOperator, operator) return WeightedPauliOperator(paulis=op_tpb.paulis, z2_symmetries=op_tpb.z2_symmetries, name=op_tpb.name) elif operator.__class__ == MatrixOperator: op_m = cast(MatrixOperator, operator) if op_m.is_empty(): return WeightedPauliOperator(paulis=[]) if op_m.num_qubits > 10: logger.warning("Converting time from a MatrixOperator to a Pauli-type Operator grows " "exponentially. If you are converting a system with large number of " "qubits, it will take time. And now you are converting a %s-qubit " "Hamiltonian. You can turn on DEBUG logging to check the progress." "", op_m.num_qubits) num_qubits = op_m.num_qubits coeff = 2 ** (-num_qubits) paulis = [] possible_basis = 'IXYZ' if op_m.dia_matrix is not None: possible_basis = 'IZ' if logger.isEnabledFor(logging.DEBUG): logger.debug("Converting a MatrixOperator to a Pauli-type Operator:") TextProgressBar(sys.stderr) results = parallel_map(_conversion, list(itertools.product(possible_basis, repeat=num_qubits)), task_kwargs={"matrix": op_m._matrix}, num_processes=aqua_globals.num_processes) for trace_value, pauli in results: weight = trace_value * coeff if weight != 0.0 and np.abs(weight) > op_m.atol: paulis.append([weight, pauli]) return WeightedPauliOperator(paulis, z2_symmetries=operator.z2_symmetries, name=operator.name) else: raise AquaError("Unsupported type to convert to WeightedPauliOperator: " "{}".format(operator.__class__))
def _build_hopping_operators(self): if logger.isEnabledFor(logging.DEBUG): TextProgressBar(sys.stderr) results = parallel_map(UVCC._build_hopping_operator, self._excitations, task_args=(self._basis, 'direct'), num_processes=algorithm_globals.num_processes) hopping_ops = [qubit_op for qubit_op in results if qubit_op is not None] num_parameters = len(hopping_ops) * self._reps return hopping_ops, num_parameters
def mapping_new(self, map_type, threshold=0.00000001): """Map fermionic operator to qubit operator. Using multiprocess to speedup the mapping, the improvement can be observed when h2 is a non-sparse matrix. Args: map_type (str): case-insensitive mapping type. "jordan_wigner", "parity", "bravyi_kitaev", "bksf" threshold (float): threshold for Pauli simplification Returns: WeightedPauliOperator: create an Operator object in Paulis form. Raises: QiskitChemistryError: if the `map_type` can not be recognized. """ # ################################################################### # ########### DEFINING MAPPED FERMIONIC OPERATORS ############## # ################################################################### self._map_type = map_type n = self._modes # number of fermionic modes / qubits map_type = map_type.lower() if map_type == 'jordan_wigner': a_list = self._jordan_wigner_mode(n) elif map_type == 'parity': a_list = self._parity_mode(n) elif map_type == 'bravyi_kitaev': a_list = self._bravyi_kitaev_mode(n) elif map_type == 'bksf': return bksf_mapping(self) else: raise QiskitChemistryError('Please specify the supported modes: ' 'jordan_wigner, parity, bravyi_kitaev, bksf') # ################################################################### # ########### BUILDING THE MAPPED HAMILTONIAN ################ # ################################################################### pauli_list = WeightedPauliOperator(paulis=[]) if logger.isEnabledFor(logging.DEBUG): logger.debug("Mapping one-body terms to Qubit Hamiltonian:") TextProgressBar(output_handler=sys.stderr) results = parallel_map(FermionicOperator._n_body_mapping, [(self._h1[i, j], a_list[i], a_list[j]) for i, j in itertools.product(range(n), repeat=2) if self._h1[i, j] != 0], task_args=(threshold,), num_processes=aqua_globals.num_processes) for result in results: pauli_list += result pauli_list.chop(threshold=threshold) if logger.isEnabledFor(logging.DEBUG): logger.debug("Mapping two-body terms to Qubit Hamiltonian:") TextProgressBar(output_handler=sys.stderr)
def _build_hopping_operators(self): if logger.isEnabledFor(logging.DEBUG): TextProgressBar(sys.stderr) results = parallel_map(UCCSD._build_hopping_operator, self._single_excitations + self._double_excitations, task_args=(self._num_orbitals, self._num_particles, self._qubit_mapping, self._two_qubit_reduction, self._z2_symmetries), num_processes=aqua_globals.num_processes) hopping_ops = [qubit_op for qubit_op in results if qubit_op is not None] num_parameters = len(hopping_ops) * self._depth return hopping_ops, num_parameters
def transpile(self): input_files = self.get_unrun_files(transpile_only=True) print('\n ============= TRANSPILATION ONLY ================') print('\n RESUMING \n') print(len(input_files), ' circuits left:') print(input_files) circ_list = self.create_circ_list(input_files) print('Circuits generated. Transpiling...') TextProgressBar() circ_list = compiler.transpile(circ_list, backend=self.backend, optimization_level=self.optim) for circ in circ_list: self.save_qasm(circ)
def construct_circuit(self, parameters, q=None): """ Construct the variational form, given its parameters. Args: parameters (numpy.ndarray): circuit parameters q (QuantumRegister): Quantum Register for the circuit. Returns: QuantumCircuit: a quantum circuit with given `parameters` Raises: ValueError: the number of parameters is incorrect. """ from .uccsd import UCCSD if len(parameters) != self._num_parameters: raise ValueError('The number of parameters has to be {}'.format( self._num_parameters)) if q is None: q = QuantumRegister(self._num_qubits, name='q') if self._initial_state is not None: circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) if logger.isEnabledFor( logging.DEBUG) and self._logging_construct_circuit: logger.debug("Evolving hopping operators:") TextProgressBar(sys.stderr) self._logging_construct_circuit = False num_excitations = len(self._hopping_ops) results = parallel_map( UCCSD._construct_circuit_for_one_excited_operator, [(self._hopping_ops[index % num_excitations], parameters[index]) for index in range(self._depth * num_excitations)], task_args=(q, self._num_time_slices), num_processes=aqua_globals.num_processes) for qc in results: if self._shallow_circuit_concat: circuit.data += qc.data else: circuit += qc return circuit
def _build_hopping_operators(self): from .uccsd import UCCSD hopping_ops = [] if logger.isEnabledFor(logging.DEBUG): TextProgressBar(sys.stderr) results = parallel_map( UCCSD._build_hopping_operator, self._single_excitations + self._double_excitations, task_args=(self._num_orbitals, self._num_particles, self._qubit_mapping, self._two_qubit_reduction, self._qubit_tapering, self._symmetries, self._cliffords, self._sq_list, self._tapering_values)) hopping_ops = [ qubit_op for qubit_op in results if qubit_op is not None ] num_parameters = len(hopping_ops) * self._depth return hopping_ops, num_parameters
def get_depth_and_size(self, dir, transpile=True, backend_name=None): # def _get_size_and_depth(self, row): # name = row.name # circ = QuantumCircuit.from_qasm_file(os.path.join(self.res_dir, name)) # row['depth'] = circ.depth() # row['size'] = circ.size() # self.df.parallel_apply(_get_size_and_depth, axis=1) # def _get_size_and_depth(slice): # for row in slice.iterrows(): # name = row.name # circ = QuantumCircuit.from_qasm(os.path.join(self.res_dir, name)) # row['depth'] = circ.depth() # row['size'] = circ.size() # self.df = parallelize_dataframe(self.df, _get_size_and_depth) if backend_name: IBMQ.load_accounts() backend = IBMQ.backends( filters=lambda x: x.name() == backend_name)[0] file_list = get_file_list(dir, '.qasm') file_list_abs = [os.path.join(dir, file) for file in file_list] pool = Pool() print('==Creating circuit list==') # circ_list = pool.map(QuantumCircuit.from_qasm_file, file_list_abs) circ_list = Parallel(n_jobs=cpu_count())( delayed(QuantumCircuit.from_qasm_file)(file) for file in file_list_abs) # pool.close() # pool.join() if transpile: print('==Transpiling!==') TextProgressBar() circ_list = compiler.transpile(circ_list, backend) file_list_pkl = [ os.path.splitext(file)[0] + '.pkl' for file in file_list ] for i in range(len(file_list_pkl)): self.df.loc[file_list_pkl[i], 'depth'] = circ_list[i].depth() self.df.loc[file_list_pkl[i], 'size'] = circ_list[i].size() return
def get_kernel_matrix(quantum_instance, feature_map, x1_vec, x2_vec=None, enforce_psd=True): """ Construct kernel matrix, if x2_vec is None, self-innerproduct is conducted. Notes: When using `statevector_simulator`, we only build the circuits for Psi(x1)|0> rather than Psi(x2)^dagger Psi(x1)|0>, and then we perform the inner product classically. That is, for `statevector_simulator`, the total number of circuits will be O(N) rather than O(N^2) for `qasm_simulator`. Args: quantum_instance (QuantumInstance): quantum backend with all settings feature_map (FeatureMap): a feature map that maps data to feature space x1_vec (numpy.ndarray): data points, 2-D array, N1xD, where N1 is the number of data, D is the feature dimension x2_vec (numpy.ndarray): data points, 2-D array, N2xD, where N2 is the number of data, D is the feature dimension enforce_psd (bool): enforces that the kernel matrix is positive semi-definite by setting negative eigenvalues to zero. This is only applied in the symmetric case, i.e., if `x2_vec == None`. Returns: numpy.ndarray: 2-D matrix, N1xN2 """ if isinstance(feature_map, QuantumCircuit): use_parameterized_circuits = True else: use_parameterized_circuits = feature_map.support_parameterized_circuit if x2_vec is None: is_symmetric = True x2_vec = x1_vec else: is_symmetric = False is_statevector_sim = quantum_instance.is_statevector measurement = not is_statevector_sim measurement_basis = '0' * feature_map.num_qubits mat = np.ones((x1_vec.shape[0], x2_vec.shape[0])) # get all indices if is_symmetric: mus, nus = np.triu_indices(x1_vec.shape[0], k=1) # remove diagonal term else: mus, nus = np.indices((x1_vec.shape[0], x2_vec.shape[0])) mus = np.asarray(mus.flat) nus = np.asarray(nus.flat) if is_statevector_sim: if is_symmetric: to_be_computed_data = x1_vec else: to_be_computed_data = np.concatenate((x1_vec, x2_vec)) if use_parameterized_circuits: # build parameterized circuits, it could be slower for building circuit # but overall it should be faster since it only transpile one circuit feature_map_params = ParameterVector( 'x', feature_map.feature_dimension) parameterized_circuit = QSVM._construct_circuit( (feature_map_params, feature_map_params), feature_map, measurement, is_statevector_sim=is_statevector_sim) parameterized_circuit = quantum_instance.transpile( parameterized_circuit)[0] circuits = [ parameterized_circuit.assign_parameters( {feature_map_params: x}) for x in to_be_computed_data ] else: # the second x is redundant to_be_computed_data_pair = [(x, x) for x in to_be_computed_data] if logger.isEnabledFor(logging.DEBUG): logger.debug("Building circuits:") TextProgressBar(sys.stderr) circuits = parallel_map( QSVM._construct_circuit, to_be_computed_data_pair, task_args=(feature_map, measurement, is_statevector_sim), num_processes=aqua_globals.num_processes) results = quantum_instance.execute( circuits, had_transpiled=use_parameterized_circuits) if logger.isEnabledFor(logging.DEBUG): logger.debug("Calculating overlap:") TextProgressBar(sys.stderr) offset = 0 if is_symmetric else len(x1_vec) matrix_elements = parallel_map( QSVM._compute_overlap, list(zip(mus, nus + offset)), task_args=(results, is_statevector_sim, measurement_basis), num_processes=aqua_globals.num_processes) for i, j, value in zip(mus, nus, matrix_elements): mat[i, j] = value if is_symmetric: mat[j, i] = mat[i, j] else: for idx in range(0, len(mus), QSVM.BATCH_SIZE): to_be_computed_data_pair = [] to_be_computed_index = [] for sub_idx in range(idx, min(idx + QSVM.BATCH_SIZE, len(mus))): i = mus[sub_idx] j = nus[sub_idx] x1 = x1_vec[i] x2 = x2_vec[j] if not np.all(x1 == x2): to_be_computed_data_pair.append((x1, x2)) to_be_computed_index.append((i, j)) if use_parameterized_circuits: # build parameterized circuits, it could be slower for building circuit # but overall it should be faster since it only transpile one circuit feature_map_params_x = ParameterVector( 'x', feature_map.feature_dimension) feature_map_params_y = ParameterVector( 'y', feature_map.feature_dimension) parameterized_circuit = QSVM._construct_circuit( (feature_map_params_x, feature_map_params_y), feature_map, measurement, is_statevector_sim=is_statevector_sim) parameterized_circuit = quantum_instance.transpile( parameterized_circuit)[0] circuits = [ parameterized_circuit.assign_parameters({ feature_map_params_x: x, feature_map_params_y: y }) for x, y in to_be_computed_data_pair ] else: if logger.isEnabledFor(logging.DEBUG): logger.debug("Building circuits:") TextProgressBar(sys.stderr) circuits = parallel_map( QSVM._construct_circuit, to_be_computed_data_pair, task_args=(feature_map, measurement), num_processes=aqua_globals.num_processes) results = quantum_instance.execute( circuits, had_transpiled=use_parameterized_circuits) if logger.isEnabledFor(logging.DEBUG): logger.debug("Calculating overlap:") TextProgressBar(sys.stderr) matrix_elements = parallel_map( QSVM._compute_overlap, range(len(circuits)), task_args=(results, is_statevector_sim, measurement_basis), num_processes=aqua_globals.num_processes) for (i, j), value in zip(to_be_computed_index, matrix_elements): mat[i, j] = value if is_symmetric: mat[j, i] = mat[i, j] if enforce_psd and is_symmetric and not is_statevector_sim: # Find the closest positive semi-definite approximation to kernel matrix, in case it is # symmetric. The (symmetric) matrix should always be positive semi-definite by # construction, but this can be violated in case of noise, such as sampling noise, thus, # the adjustment is only done if NOT using the statevector simulation. D, U = np.linalg.eig(mat) mat = U @ np.diag(np.maximum(0, D)) @ U.transpose() return mat
def construct_circuit(self, parameters, q=None): """ Construct the variational form, given its parameters. Args: parameters (Union(numpy.ndarray, list[Parameter], ParameterVector)): circuit parameters q (QuantumRegister, optional): Quantum Register for the circuit. Returns: QuantumCircuit: a quantum circuit with given `parameters` Raises: ValueError: the number of parameters is incorrect. """ if len(parameters) != self._num_parameters: raise ValueError('The number of parameters has to be {}'.format( self._num_parameters)) if q is None: q = QuantumRegister(self._num_qubits, name='q') if self._initial_state is not None: circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) if logger.isEnabledFor( logging.DEBUG) and self._logging_construct_circuit: logger.debug("Evolving hopping operators:") TextProgressBar(sys.stderr) self._logging_construct_circuit = False num_excitations = len(self._hopping_ops) if not self.uccd_singlet: list_excitation_operators = [ (self._hopping_ops[index % num_excitations], parameters[index]) for index in range(self._depth * num_excitations) ] else: list_excitation_operators = [] counter = 0 for i in range(int(self._depth * self.num_groups)): for _ in range( len(self._double_excitations_grouped[ i % self.num_groups])): list_excitation_operators.append( (self._hopping_ops[counter], parameters[i])) counter += 1 results = parallel_map( UCCSD._construct_circuit_for_one_excited_operator, list_excitation_operators, task_args=(q, self._num_time_slices), num_processes=aqua_globals.num_processes) for qc in results: if self._shallow_circuit_concat: circuit.data += qc.data else: circuit += qc return circuit
def construct_kernel_matrix(self, x1_vec, x2_vec=None, quantum_instance=None): """ Construct kernel matrix, if x2_vec is None, self-innerproduct is conducted. Args: x1_vec (numpy.ndarray): data points, 2-D array, N1xD, where N1 is the number of data, D is the feature dimension x2_vec (numpy.ndarray): data points, 2-D array, N2xD, where N2 is the number of data, D is the feature dimension quantum_instance (QuantumInstance): quantum backend with all setting Returns: numpy.ndarray: 2-D matrix, N1xN2 """ self._quantum_instance = self._quantum_instance \ if quantum_instance is None else quantum_instance from .qsvm import QSVM if x2_vec is None: is_symmetric = True x2_vec = x1_vec else: is_symmetric = False is_statevector_sim = self.quantum_instance.is_statevector measurement = not is_statevector_sim measurement_basis = '0' * self.num_qubits mat = np.ones((x1_vec.shape[0], x2_vec.shape[0])) # get all indices if is_symmetric: mus, nus = np.triu_indices(x1_vec.shape[0], k=1) # remove diagonal term else: mus, nus = np.indices((x1_vec.shape[0], x2_vec.shape[0])) mus = np.asarray(mus.flat) nus = np.asarray(nus.flat) for idx in range(0, len(mus), QSVM.BATCH_SIZE): to_be_computed_list = [] to_be_computed_index = [] for sub_idx in range(idx, min(idx + QSVM.BATCH_SIZE, len(mus))): i = mus[sub_idx] j = nus[sub_idx] x1 = x1_vec[i] x2 = x2_vec[j] if not np.all(x1 == x2): to_be_computed_list.append((x1, x2)) to_be_computed_index.append((i, j)) if logger.isEnabledFor(logging.DEBUG): logger.debug("Building circuits:") TextProgressBar(sys.stderr) circuits = parallel_map(QSVM._construct_circuit, to_be_computed_list, task_args=(self.num_qubits, self.feature_map, measurement), num_processes=aqua_globals.num_processes) results = self.quantum_instance.execute(circuits) if logger.isEnabledFor(logging.DEBUG): logger.debug("Calculating overlap:") TextProgressBar(sys.stderr) matrix_elements = parallel_map(QSVM._compute_overlap, range(len(circuits)), task_args=(results, is_statevector_sim, measurement_basis), num_processes=aqua_globals.num_processes) for idx in range(len(to_be_computed_index)): i, j = to_be_computed_index[idx] mat[i, j] = matrix_elements[idx] if is_symmetric: mat[j, i] = mat[i, j] return mat
def mapping(self, map_type, threshold=0.00000001): """ Map fermionic operator to qubit operator. Using multiprocess to speedup the mapping, the improvement can be observed when h2 is a non-sparse matrix. Args: map_type (str): case-insensitive mapping type. "jordan_wigner", "parity", "bravyi_kitaev", "bksf" threshold (float): threshold for Pauli simplification Returns: PauliSumOp: create an Operator object in Paulis form. Raises: QiskitNatureError: if the `map_type` can not be recognized. """ # ################################################################### # ########### DEFINING MAPPED FERMIONIC OPERATORS ############## # ################################################################### self._map_type = map_type n = self._modes # number of fermionic modes / qubits map_type = map_type.lower() if map_type == 'jordan_wigner': a_list = self._jordan_wigner_mode(n) elif map_type == 'parity': a_list = self._parity_mode(n) elif map_type == 'bravyi_kitaev': a_list = self._bravyi_kitaev_mode(n) elif map_type == 'bksf': return bksf_mapping(self) else: raise QiskitNatureError( 'Please specify the supported modes: ' 'jordan_wigner, parity, bravyi_kitaev, bksf') # ################################################################### # ########### BUILDING THE MAPPED HAMILTONIAN ################ # ################################################################### pauli_list: Optional[PauliSumOp] = None if logger.isEnabledFor(logging.DEBUG): logger.debug("Mapping one-body terms to Qubit Hamiltonian:") TextProgressBar(output_handler=sys.stderr) results = parallel_map( FermionicOperator._one_body_mapping, [(self._h1[i, j], a_list[i], a_list[j]) for i, j in itertools.product(range(n), repeat=2) if self._h1[i, j] != 0], task_args=(threshold, ), num_processes=algorithm_globals.num_processes) if results: pauli_list = results[0] for result in results[1:]: pauli_list += result # TODO: implement chop # pauli_list.chop(threshold=threshold) if logger.isEnabledFor(logging.DEBUG): logger.debug("Mapping two-body terms to Qubit Hamiltonian:") TextProgressBar(output_handler=sys.stderr) results = parallel_map( FermionicOperator._two_body_mapping, [(self._h2[i, j, k, m], a_list[i], a_list[j], a_list[k], a_list[m]) for i, j, k, m in itertools.product(range(n), repeat=4) if self._h2[i, j, k, m] != 0], task_args=(threshold, ), num_processes=algorithm_globals.num_processes) if results: pauli_list = results[ 0] if pauli_list is None else pauli_list + results[0] for result in results[1:]: pauli_list += result # TODO: implement chop # pauli_list.chop(threshold=threshold) if self._ph_trans_shift is not None: pauli_term = ('I' * self._modes, self._ph_trans_shift) pauli_sum_op = PauliSumOp.from_list([pauli_term]) pauli_list = pauli_sum_op if pauli_list is None else pauli_list + pauli_sum_op return pauli_list
def construct_circuit(self, parameters, q=None): """ Construct the variational form, given its parameters. Args: parameters (Union(numpy.ndarray, list[Parameter], ParameterVector)): circuit parameters q (QuantumRegister, optional): Quantum Register for the circuit. Returns: QuantumCircuit: a quantum circuit with given `parameters` Raises: ValueError: the number of parameters is incorrect. """ if len(parameters) != self._num_parameters: raise ValueError('The number of parameters has to be {}'.format( self._num_parameters)) if q is None: q = QuantumRegister(self._num_qubits, name='q') if isinstance(self._initial_state, QuantumCircuit): circuit = QuantumCircuit(q) circuit.compose(self._initial_state, inplace=True) elif isinstance(self._initial_state, InitialState): circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) if logger.isEnabledFor( logging.DEBUG) and self._logging_construct_circuit: logger.debug("Evolving hopping operators:") TextProgressBar(sys.stderr) self._logging_construct_circuit = False num_excitations = len(self._hopping_ops) if not self.uccd_singlet: list_excitation_operators = [ (self._hopping_ops[index % num_excitations], parameters[index]) for index in range(self._reps * num_excitations) ] else: list_excitation_operators = [] counter = 0 for i in range(int(self._reps * self.num_groups)): for _ in range( len(self._double_excitations_grouped[ i % self.num_groups])): list_excitation_operators.append( (self._hopping_ops[counter], parameters[i])) counter += 1 # TODO to uncomment to update for Operator flow: # from functools import reduce # ops = [(qubit_op.to_opflow().to_matrix_op() * param).exp_i() # for (qubit_op, param) in list_excitation_operators] # circuit += reduce(lambda x, y: x @ y, reversed(ops)).to_circuit() # return circuit results = parallel_map( UCCSD._construct_circuit_for_one_excited_operator, list_excitation_operators, task_args=(q, self._num_time_slices), num_processes=aqua_globals.num_processes) if self._shallow_circuit_concat: for qc in results: for _, qbits, _ in qc._data: for i, _ in enumerate(qbits): qbits[i] = circuit.qubits[qbits[i].index] for qc in results: circuit._data += qc._data else: for qc in results: circuit += qc return circuit
def get_kernel_matrix(quantum_instance, feature_map, x1_vec, x2_vec=None): """ Construct kernel matrix, if x2_vec is None, self-innerproduct is conducted. Notes: When using `statevector_simulator`, we only build the circuits for Psi(x1)|0> rather than Psi(x2)^dagger Psi(x1)|0>, and then we perform the inner product classically. That is, for `statevector_simulator`, the total number of circuits will be O(N) rather than O(N^2) for `qasm_simulator`. Args: quantum_instance (QuantumInstance): quantum backend with all settings feature_map (FeatureMap): a feature map that maps data to feature space x1_vec (numpy.ndarray): data points, 2-D array, N1xD, where N1 is the number of data, D is the feature dimension x2_vec (numpy.ndarray): data points, 2-D array, N2xD, where N2 is the number of data, D is the feature dimension Returns: numpy.ndarray: 2-D matrix, N1xN2 """ if x2_vec is None: is_symmetric = True x2_vec = x1_vec else: is_symmetric = False is_statevector_sim = quantum_instance.is_statevector measurement = not is_statevector_sim measurement_basis = '0' * feature_map.num_qubits mat = np.ones((x1_vec.shape[0], x2_vec.shape[0])) # get all indices if is_symmetric: mus, nus = np.triu_indices(x1_vec.shape[0], k=1) # remove diagonal term else: mus, nus = np.indices((x1_vec.shape[0], x2_vec.shape[0])) mus = np.asarray(mus.flat) nus = np.asarray(nus.flat) if is_statevector_sim: if is_symmetric: to_be_computed_data = x1_vec else: to_be_computed_data = np.concatenate((x1_vec, x2_vec)) # the second x is redundant to_be_computed_data_pair = [(x, x) for x in to_be_computed_data] if logger.isEnabledFor(logging.DEBUG): logger.debug("Building circuits:") TextProgressBar(sys.stderr) circuits = parallel_map(QSVM._construct_circuit, to_be_computed_data_pair, task_args=(feature_map, measurement, is_statevector_sim), num_processes=aqua_globals.num_processes) results = quantum_instance.execute(circuits) if logger.isEnabledFor(logging.DEBUG): logger.debug("Calculating overlap:") TextProgressBar(sys.stderr) offset = 0 if is_symmetric else len(x1_vec) matrix_elements = parallel_map( QSVM._compute_overlap, list(zip(mus, nus + offset)), task_args=(results, is_statevector_sim, measurement_basis), num_processes=aqua_globals.num_processes) for i, j, value in zip(mus, nus, matrix_elements): mat[i, j] = value if is_symmetric: mat[j, i] = mat[i, j] else: for idx in range(0, len(mus), QSVM.BATCH_SIZE): to_be_computed_data_pair = [] to_be_computed_index = [] for sub_idx in range(idx, min(idx + QSVM.BATCH_SIZE, len(mus))): i = mus[sub_idx] j = nus[sub_idx] x1 = x1_vec[i] x2 = x2_vec[j] if not np.all(x1 == x2): to_be_computed_data_pair.append((x1, x2)) to_be_computed_index.append((i, j)) if logger.isEnabledFor(logging.DEBUG): logger.debug("Building circuits:") TextProgressBar(sys.stderr) circuits = parallel_map( QSVM._construct_circuit, to_be_computed_data_pair, task_args=(feature_map, measurement), num_processes=aqua_globals.num_processes) results = quantum_instance.execute(circuits) if logger.isEnabledFor(logging.DEBUG): logger.debug("Calculating overlap:") TextProgressBar(sys.stderr) matrix_elements = parallel_map( QSVM._compute_overlap, range(len(circuits)), task_args=(results, is_statevector_sim, measurement_basis), num_processes=aqua_globals.num_processes) for (i, j), value in zip(to_be_computed_index, matrix_elements): mat[i, j] = value if is_symmetric: mat[j, i] = mat[i, j] return mat