def test_find_Z2_symmetries(self): """test for find_Z2_symmetries""" qubit_op = PauliSumOp.from_list([ ("II", -1.0537076071291125), ("IZ", 0.393983679438514), ("ZI", -0.39398367943851387), ("ZZ", -0.01123658523318205), ("XX", 0.1812888082114961), ]) z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) self.assertEqual(z2_symmetries.symmetries, [Pauli("ZZ")]) self.assertEqual(z2_symmetries.sq_paulis, [Pauli("IX")]) self.assertEqual(z2_symmetries.sq_list, [0]) self.assertEqual(z2_symmetries.tapering_values, None) tapered_op = z2_symmetries.taper(qubit_op)[1] self.assertEqual(tapered_op.z2_symmetries.symmetries, [Pauli("ZZ")]) self.assertEqual(tapered_op.z2_symmetries.sq_paulis, [Pauli("IX")]) self.assertEqual(tapered_op.z2_symmetries.sq_list, [0]) self.assertEqual(tapered_op.z2_symmetries.tapering_values, [-1]) z2_symmetries.tapering_values = [-1] primitive = SparsePauliOp.from_list([ ("I", -1.0424710218959303), ("Z", -0.7879673588770277), ("X", -0.18128880821149604), ]) expected_op = TaperedPauliSumOp(primitive, z2_symmetries) self.assertEqual(tapered_op, expected_op)
def test_truncate_tapered_op(self): """Test setting cutoff tolerances for the tapered operator works.""" qubit_op = PauliSumOp.from_list([ ("II", -1.0537076071291125), ("IZ", 0.393983679438514), ("ZI", -0.39398367943851387), ("ZZ", -0.01123658523318205), ("XX", 0.1812888082114961), ]) z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) z2_symmetries.tol = 0.2 # removes the X part of the tapered op which is < 0.2 tapered_op = z2_symmetries.taper(qubit_op)[1] primitive = SparsePauliOp.from_list([ ("I", -1.0424710218959303), ("Z", -0.7879673588770277), ]) expected_op = TaperedPauliSumOp(primitive, z2_symmetries) self.assertEqual(tapered_op, expected_op)
def _process_z2symmetry_reduction(self, qubit_op: PauliSumOp, aux_ops: List[PauliSumOp]) -> Tuple: """ Implement z2 symmetries in the qubit operator Args: qubit_op : qubit operator aux_ops: auxiliary operators Returns: (z2_qubit_op, z2_aux_ops, z2_symmetries) Raises: QiskitNatureError: Invalid input """ z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): logger.debug('No Z2 symmetries found') z2_qubit_op = qubit_op z2_aux_ops = aux_ops z2_symmetries = Z2Symmetries([], [], [], None) else: logger.debug( '%s Z2 symmetries found: %s', len(z2_symmetries.symmetries), ','.join( [symm.to_label() for symm in z2_symmetries.symmetries])) # Check auxiliary operators commute with main operator's symmetry logger.debug('Checking operators commute with symmetry:') symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append( PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) commutes = FermionicTransformation._check_commutes( symmetry_ops, qubit_op) if not commutes: raise QiskitNatureError( 'Z2 symmetry failure main operator must commute ' 'with symmetries found from it') for i, aux_op in enumerate(aux_ops): commutes = FermionicTransformation._check_commutes( symmetry_ops, aux_op) if not commutes: aux_ops[ i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstring hf_bitstr = hartree_fock_bitstring( num_orbitals=self._molecule_info['num_orbitals'], qubit_mapping=self._qubit_mapping, two_qubit_reduction=self._two_qubit_reduction, num_particles=self._molecule_info['num_particles']) z2_symmetries = FermionicTransformation._pick_sector( z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len( z2_symmetries.symmetries): raise QiskitNatureError( 'z2symmetry_reduction tapering values list has ' 'invalid length {} should be {}'.format( len(self._z2symmetry_reduction), len(z2_symmetries.symmetries))) valid = np.all(np.isin(self._z2symmetry_reduction, [-1, 1])) if not valid: raise QiskitNatureError( 'z2symmetry_reduction tapering values list must ' 'contain -1\'s and/or 1\'s only was {}'.format( self._z2symmetry_reduction, )) z2_symmetries.tapering_values = self._z2symmetry_reduction logger.debug('Apply symmetry with tapering values %s', z2_symmetries.tapering_values) chop_to = 0.00000001 # Use same threshold as qubit mapping to chop tapered operator z2_qubit_op = z2_symmetries.taper(qubit_op).chop(chop_to) z2_aux_ops = [] for aux_op in aux_ops: if aux_op is None: z2_aux_ops += [None] else: z2_aux_ops += [z2_symmetries.taper(aux_op).chop(chop_to)] return z2_qubit_op, z2_aux_ops, z2_symmetries