# (C) Copyright IBM 2023.## This code is licensed under the Apache License, Version 2.0. You may# obtain a copy of this license in the LICENSE.txt file in the root directory# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.## Any modifications or derivative works of this code must retain this# copyright notice, and modified files need to carry a notice indicating# that they have been altered from the originals."""Hop gate ansatz."""from__future__importannotationsimportitertoolsfromdataclassesimportdataclassimportnumpyasnpfromffsim.gatesimportapply_hop_gate,apply_orbital_rotationfromffsim.variational.utilimport(orbital_rotation_from_parameters,orbital_rotation_to_parameters,)
[docs]@dataclass(frozen=True)classHopGateAnsatzOperator:"""A hop gate ansatz operator. The hop gate ansatz consists of a sequence of `hop gates`_. Note that this ansatz does not implement any interactions between spin alpha and spin beta orbitals. It was designed to be used with `entanglement forging`_. Attributes: norb (int): The number of spatial orbitals. interaction_pairs (list[tuple[int, int]]): The orbital pairs to apply the hop gates to. thetas (np.ndarray): The rotation angles for the hop gates. final_orbital_rotation (np.ndarray): An optional final orbital rotation to append to the ansatz, used to optimize the orbital basis. .. _hop gates: ffsim.html#ffsim.apply_hop_gate .. _entanglement forging: https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.3.010309 """norb:intinteraction_pairs:list[tuple[int,int]]thetas:np.ndarrayfinal_orbital_rotation:np.ndarray|None=Nonedef_apply_unitary_(self,vec:np.ndarray,norb:int,nelec:int|tuple[int,int],copy:bool)->np.ndarray:"""Apply the operator to a vector."""ifcopy:vec=vec.copy()fortarget_orbs,thetainzip(itertools.cycle(self.interaction_pairs),self.thetas):vec=apply_hop_gate(vec,theta,target_orbs=target_orbs,norb=norb,nelec=nelec,copy=False)ifself.final_orbital_rotationisnotNone:vec=apply_orbital_rotation(vec,mat=self.final_orbital_rotation,norb=norb,nelec=nelec,copy=False,)returnvec
[docs]defto_parameters(self)->np.ndarray:"""Convert the operator to a real-valued parameter vector."""num_params=len(self.thetas)ifself.final_orbital_rotationisnotNone:num_params+=self.norb**2params=np.zeros(num_params)params[:len(self.thetas)]=self.thetasifself.final_orbital_rotationisnotNone:params[len(self.thetas):]=orbital_rotation_to_parameters(self.final_orbital_rotation)returnparams
[docs]@staticmethoddeffrom_parameters(params:np.ndarray,norb:int,interaction_pairs:list[tuple[int,int]],with_final_orbital_rotation:bool=False,)->HopGateAnsatzOperator:"""Initialize the operator from a real-valued parameter vector. Args: params: The real-valued parameter vector. norb: The number of spatial orbitals. interaction_pairs: The orbital pairs to apply the hop gates to. with_final_orbital_rotation: Whether to include a final orbital rotation in the ansatz operator. """final_orbital_rotation=Noneifwith_final_orbital_rotation:final_orbital_rotation=orbital_rotation_from_parameters(params[-(norb**2):],norb)params=params[:-(norb**2)]returnHopGateAnsatzOperator(norb=norb,interaction_pairs=interaction_pairs,thetas=params,final_orbital_rotation=final_orbital_rotation,)