def _find_taper_op( self, qubit_op: PauliSumOp, sector_locator: Optional[Callable[[Z2Symmetries], Optional[List[int]]]] = None, ) -> Tuple[PauliSumOp, Z2Symmetries]: # Return operator unchanged and empty symmetries if we do not taper tapered_qubit_op = qubit_op z2_symmetries = self._no_symmetries # If we were given a sector, or one might be located, we first need to find any symmetries if self.z2symmetry_reduction is not None: z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op) if z2_symmetries.is_empty(): logger.debug("No Z2 symmetries found") else: # As we have symmetries, if we have a sector locator, if that provides one back # it will override any value defined on constructor if sector_locator is not None and self.z2symmetry_reduction == "auto": z2symmetry_reduction = sector_locator(z2_symmetries) if z2symmetry_reduction is not None: self.z2symmetry_reduction = z2symmetry_reduction # Overrides any value # We may end up that neither were we given a sector nor that the locator # returned one. Since though we may have found valid symmetries above we should # simply just forget about them so as not to return something we are not using. if self.z2symmetry_reduction is None: z2_symmetries = self._no_symmetries # So now if we have a sector and have symmetries we found we can attempt to taper if (self.z2symmetry_reduction is not None and self.z2symmetry_reduction != "auto" and not z2_symmetries.is_empty()): # check sector definition fits to symmetries found 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))) # Check all operators commute with main operator's symmetry logger.debug( "Sanity check that operator commutes with the symmetry") symmetry_ops = [] for symmetry in z2_symmetries.symmetries: symmetry_ops.append( PauliSumOp.from_list([(symmetry.to_label(), 1.0)])) commutes = QubitConverter._check_commutes(symmetry_ops, qubit_op) if not commutes: raise QiskitNatureError( "Z2 symmetry failure. The operator must commute " "with symmetries found from it!") z2_symmetries.tapering_values = self._z2symmetry_reduction tapered_qubit_op = z2_symmetries.taper( qubit_op) if commutes else None return tapered_qubit_op, z2_symmetries
def _no_symmetries(self) -> Z2Symmetries: return Z2Symmetries([], [], [], None)