def _setup(self, operator: Optional[BaseOperator]) -> None: self._operator = None self._ret = {} self._pauli_list = None self._phase_estimation_circuit = None if operator: self._operator = op_converter.to_weighted_pauli_operator(operator.copy()) self._ret['translation'] = sum([abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([ [ self._ret['translation'], Pauli( np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits) ) ] ]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=self._state_in, iqft=self._iqft, num_time_slices=self._num_time_slices, num_ancillae=self._num_ancillae, expansion_mode=self._expansion_mode, expansion_order=self._expansion_order, shallow_circuit_concat=self._shallow_circuit_concat, pauli_list=self._pauli_list )
def __init__(self, operator, state_in, iqft, num_time_slices=1, num_ancillae=1, expansion_mode='trotter', expansion_order=1, shallow_circuit_concat=False): """ Constructor. Args: operator (BaseOperator): 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 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._operator = op_converter.to_weighted_pauli_operator(operator) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)]
def _setup(self): self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] if len(self._pauli_list) == 1: slice_pauli_list = self._pauli_list else: if self._expansion_mode == 'trotter': slice_pauli_list = self._pauli_list else: slice_pauli_list = suzuki_expansion_slice_pauli_list( self._pauli_list, 1, self._expansion_order) self._slice_pauli_list = slice_pauli_list
def __init__( self, operator: BaseOperator, state_in: Optional[InitialState], iqft: IQFT, num_time_slices: int = 1, num_ancillae: int = 1, expansion_mode: str = 'trotter', expansion_order: int = 1, shallow_circuit_concat: bool = False) -> None: """ Args: operator: The Hamiltonian Operator state_in: An optional InitialState component representing an initial quantum state. ``None`` may be supplied. iqft: A Inverse Quantum Fourier Transform component num_time_slices: The number of time slices, has a minimum value of 1. num_ancillae: The number of ancillary qubits to use for the measurement, has a min. value of 1. expansion_mode: The expansion mode ('trotter'|'suzuki') expansion_order: The suzuki expansion order, has a min. value of 1. shallow_circuit_concat: Set True to use shallow (cheap) mode for circuit concatenation of evolution slices. By default this is False. See :meth:`qiskit.aqua.operators.common.evolution_instruction` for more information. """ validate_min('num_time_slices', num_time_slices, 1) validate_min('num_ancillae', num_ancillae, 1) validate_in_set('expansion_mode', expansion_mode, {'trotter', 'suzuki'}) validate_min('expansion_order', expansion_order, 1) super().__init__() self._operator = op_converter.to_weighted_pauli_operator(operator.copy()) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum([abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([ [ self._ret['translation'], Pauli( np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits) ) ] ]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list ) self._binary_fractions = [1 / 2 ** p for p in range(1, num_ancillae + 1)]
def _setup( self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]]) -> None: self._operator = None self._ret = {} self._pauli_list = None self._phase_estimation_circuit = None self._slice_pauli_list = None if operator: # Convert to Legacy Operator if Operator flow passed in if isinstance(operator, OperatorBase): operator = operator.to_legacy_op() self._operator = op_converter.to_weighted_pauli_operator( operator.copy()) self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] if len(self._pauli_list) == 1: slice_pauli_list = self._pauli_list else: if self._expansion_mode == 'trotter': slice_pauli_list = self._pauli_list else: slice_pauli_list = suzuki_expansion_slice_pauli_list( self._pauli_list, 1, self._expansion_order) self._slice_pauli_list = slice_pauli_list
def bksf_mapping(fer_op): """ Transform from InteractionOpeator to QubitOperator for Bravyi-Kitaev fast algorithm. The electronic Hamiltonian is represented in terms of creation and annihilation operators. These creation and annihilation operators could be used to define Majorana modes as follows: c_{2i} = a_i + a^{\\dagger}_i, c_{2i+1} = (a_i - a^{\\dagger}_{i})/(1j) These Majorana modes can be used to define edge operators B_i and A_{ij}: B_i=c_{2i}c_{2i+1}, A_{ij}=c_{2i}c_{2j} using these edge operators the fermionic algebra can be generated and hence all the terms in the electronic Hamiltonian can be expressed in terms of edge operators. The terms in electronic Hamiltonian can be divided into five types (arXiv 1208.5986). We can find the edge operator expression for each of those five types. For example, the excitation operator term in Hamiltonian when represented in terms of edge operators becomes: a_i^{\\dagger}a_j+a_j^{\\dagger}a_i = (-1j/2)*(A_ij*B_i+B_j*A_ij) For the sake of brevity the reader is encouraged to look up the expressions of other terms from the code below. The variables for edge operators are chosen according to the nomenclature defined above (B_i and A_ij). A detailed description of these operators and the terms of the electronic Hamiltonian are provided in (arXiv 1712.00446). Args: fer_op (FermionicOperator): the fermionic operator in the second quantized form Returns: WeightedPauliOperator: mapped qubit operator """ fer_op = copy.deepcopy(fer_op) # bksf mapping works with the 'physicist' notation. fer_op.h2 = np.einsum('ijkm->ikmj', fer_op.h2) modes = fer_op.modes # Initialize qubit operator as constant. qubit_op = WeightedPauliOperator(paulis=[]) edge_list = bravyi_kitaev_fast_edge_list(fer_op) # Loop through all indices. for p in range(modes): # pylint: disable=invalid-name for q in range(modes): # Handle one-body terms. h1_pq = fer_op.h1[p, q] if h1_pq != 0.0 and p >= q: qubit_op += _one_body(edge_list, p, q, h1_pq) # Keep looping for the two-body terms. for r in range(modes): for s in range(modes): # pylint: disable=invalid-name h2_pqrs = fer_op.h2[p, q, r, s] # Skip zero terms. if (h2_pqrs == 0.0) or (p == q) or (r == s): continue # Identify and skip one of the complex conjugates. if [p, q, r, s] != [s, r, q, p]: if len(set([p, q, r, s])) == 4: if min(r, s) < min(p, q): continue # Handle case of 3 unique indices elif len(set([p, q, r, s])) == 3: qubit_op += _two_body(edge_list, p, q, r, s, 0.5 * h2_pqrs) continue elif p != r and q < p: continue qubit_op += _two_body(edge_list, p, q, r, s, h2_pqrs) qubit_op.simplify() return qubit_op
def __init__(self, operator: BaseOperator, state_in: InitialState, iqft: IQFT, num_time_slices: int = 1, num_ancillae: int = 1, expansion_mode: str = 'trotter', expansion_order: int = 1, shallow_circuit_concat: bool = False) -> None: """ Args: operator: the hamiltonian Operator object state_in: the InitialState component representing the initial quantum state iqft: the Inverse Quantum Fourier Transform component num_time_slices: the number of time slices, has a min. value of 1. num_ancillae: the number of ancillary qubits to use for the measurement, has a min. value of 1. expansion_mode: the expansion mode (trotter|suzuki) expansion_order: the suzuki expansion order, has a min. value of 1. shallow_circuit_concat: indicate whether to use shallow (cheap) mode for circuit concatenation """ validate_min('num_time_slices', num_time_slices, 1) validate_min('num_ancillae', num_ancillae, 1) validate_in_set('expansion_mode', expansion_mode, {'trotter', 'suzuki'}) validate_min('expansion_order', expansion_order, 1) super().__init__() self._operator = op_converter.to_weighted_pauli_operator( operator.copy()) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)]