def _setup(self): self._operator.to_paulis() self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] pauli_list = self._operator.reorder_paulis( grouping=self._paulis_grouping) if len(pauli_list) == 1: slice_pauli_list = pauli_list else: if self._expansion_mode == 'trotter': slice_pauli_list = pauli_list else: slice_pauli_list = Operator._suzuki_expansion_slice_pauli_list( pauli_list, 1, self._expansion_order) self._slice_pauli_list = slice_pauli_list
def __init__(self, operator, state_in, iqft, num_time_slices=1, num_ancillae=1, paulis_grouping='random', expansion_mode='trotter', expansion_order=1, shallow_circuit_concat=False): """ Constructor. Args: operator (Operator): the hamiltonian Operator object state_in (InitialState): the InitialState pluggable component representing the initial quantum state iqft (IQFT): the Inverse Quantum Fourier Transform pluggable component num_time_slices (int): the number of time slices num_ancillae (int): the number of ancillary qubits to use for the measurement paulis_grouping (str): the pauli term grouping mode expansion_mode (str): the expansion mode (trotter|suzuki) expansion_order (int): the suzuki expansion order shallow_circuit_concat (bool): indicate whether to use shallow (cheap) mode for circuit concatenation """ self.validate(locals()) super().__init__() self._num_ancillae = num_ancillae self._ret = {} self._operator = copy.deepcopy(operator) self._operator.to_paulis() self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_component = PhaseEstimation( self._operator, state_in, iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, paulis_grouping=paulis_grouping, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)]
def _setup_qpe(self): self._operator._check_representation('paulis') self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] # check for identify paulis to get its coef for applying global phase shift on ancillae later num_identities = 0 for p in self._operator.paulis: if np.all(p[1].v == 0) and np.all(p[1].w == 0): 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] self._construct_qpe_evolution() logger.info('QPE circuit qasm length is roughly {}.'.format( len(self._circuit.qasm().split('\n'))))
def __init__(self, operator, state_in, iqft, num_time_slices=1, num_ancillae=1, paulis_grouping='random', expansion_mode='trotter', expansion_order=1, shallow_circuit_concat=False): self.validate(locals()) super().__init__() self._ret = {} self._operator = copy.deepcopy(operator) self._operator.to_paulis() self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_component = PhaseEstimation( self._operator, state_in, iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, paulis_grouping=paulis_grouping, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)]
def limit_paulis(mat, n=5, sparsity=None): """ Limits the number of Pauli basis matrices of a hermitian matrix to the n highest magnitude ones. Args: mat (np.ndarray): Input matrix n (int): number of surviving Pauli matrices (default=5) sparsity (float < 1): sparsity of matrix Returns: scipy.sparse.csr_matrix """ from qiskit_aqua import Operator # Bringing matrix into form 2**Nx2**N l = mat.shape[0] if np.log2(l) % 1 != 0: k = int(2**np.ceil(np.log2(l))) m = np.zeros([k, k], dtype=np.complex128) m[:l, :l] = mat m[l:, l:] = np.identity(k-l) mat = m # Getting Pauli matrices op = Operator(matrix=mat) op._check_representation("paulis") op._simplify_paulis() paulis = sorted(op.paulis, key=lambda x: abs(x[0]), reverse=True) g = 2**op.num_qubits mat = scipy.sparse.csr_matrix(([], ([], [])), shape=(g, g), dtype=np.complex128) # Truncation if sparsity is None: for pa in paulis[:n]: mat += pa[0]*pa[1].to_spmatrix() else: idx = 0 while mat[:l, :l].nnz/l**2 < sparsity: mat += paulis[idx][0]*paulis[idx][1].to_spmatrix() idx += 1 n = idx mat = mat.toarray() return mat[:l, :l]
def _compute_energy(self): self._operator.to_paulis() self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.paulis]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator._simplify_paulis() translation_op = Operator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op._simplify_paulis() self._operator += translation_op # stretch the operator for p in self._operator._paulis: p[0] = p[0] * self._ret['stretch'] # check for identify paulis to get its coef for applying global phase shift on ancilla later num_identities = 0 for p in self._operator.paulis: 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] self._ret['phase'] = self._estimate_phase_iteratively() self._ret['top_measurement_decimal'] = sum([ t[0] * t[1] for t in zip([1 / 2**p for p in range(1, self._num_iterations + 1)], [int(n) for n in self._ret['top_measurement_label']]) ]) self._ret['energy'] = self._ret['phase'] / self._ret[ 'stretch'] - self._ret['translation']