"""Debug querying the internal state of the emulator."""from__future__importannotationsfromdataclassesimportdataclassfromtypingimportProtocol,TypeVarimportnumpyasnpimportnumpy.typingasnptfromselene_quest_plugin.stateimportSeleneQuestState,TracedStatefromtyping_extensionsimportSelf__all__=["TracedState","NotSingleStateError","PartialState","PartialVector","StateVector",]#: Type encoding a single state. e.g. StateVector for a state vector.S=TypeVar("S")#: Type encoding a state vector, type alias for numpy array of complex numbers.StateVector=npt.NDArray[np.complexfloating]@dataclass(frozen=True)classNotSingleStateError(Exception):"""Raised when a Selene state is not a single state, i.e. it has unspecified qubits that have been traced out."""total_qubits:intn_specified_qubits:intdef__str__(self)->str:return(f"Selene state is not a single state: "f"total qubits {self.total_qubits} != "f"specified qubits {self.n_specified_qubits}.")
[docs]classPartialState(Protocol[S]):"""Protocol for an emulator state type. Different simulation backends may have different state representations."""@propertydeftotal_qubits(self)->int:"""Total number of qubits in the state."""...@propertydefspecified_qubits(self)->list[int]:"""List of specified qubits in the state."""...
[docs]defstate_distribution(self,zero_threshold:float=1e-12)->list[TracedState[S]]:"""Distribution of states after tracing out unspecified qubits. In general this results in a distribution of states, each with a probability. Args: zero_threshold: Threshold for considering a state amplitude to be zero. Defaults to 1e-12. Returns: List of traced states, each with a state vector and a probability."""...
[docs]defas_single_state(self,zero_threshold:float=1e-12)->S:"""If the state is a single pure state return it. Args: zero_threshold: Threshold for considering a state amplitude to be zero. Defaults to 1e-12. Raises: NotSingleStateError: If the state is not a pure state. Returns: The state as a single state type. """all_states=self.state_distribution(zero_threshold)iflen(all_states)!=1:raiseNotSingleStateError(total_qubits=self.total_qubits,n_specified_qubits=len(self.specified_qubits),)returnall_states[0].state
[docs]classPartialVector(PartialState[StateVector]):"""Partial state vector for simulator backends with statevector representation. Partial in the sense that some qubits may be traced out, and the state is represented as a distribution of state vectors. """_inner:SeleneQuestState
[docs]def__init__(self,base_state:StateVector,total_qubits:int,specified_qubits:list[int])->None:"""Initialize a PartialVector from a base state vector, total qubits, and specified qubits. Args: base_state: The state vector over all qubits in the system. total_qubits: Total number of qubits in the system specified_qubits: List of specified qubits in the state. Those not in this list are considered traced out. """iflen(base_state)!=(1<<total_qubits):raiseValueError(f"Base state vector length ({len(base_state)}) does not match "f"2 ** total_qubits ({1<<total_qubits}).")self._inner=SeleneQuestState(state=base_state,total_qubits=total_qubits,specified_qubits=specified_qubits,)
@propertydeftotal_qubits(self)->int:"""Total number of qubits in the state."""returnself._inner.total_qubits@propertydefspecified_qubits(self)->list[int]:"""List of specified qubits in the state. Those not in this list are considered traced out."""returnself._inner.specified_qubits
[docs]defstate_distribution(self,zero_threshold:float=1e-12)->list[TracedState[StateVector]]:out=self._inner.get_state_vector_distribution(zero_threshold=zero_threshold)# force float to remove numpy typesreturn[TracedState(float(st.probability),st.state)forstinout]
@classmethoddef_from_inner(cls,inner:SeleneQuestState)->Self:"""Create a PartialVector from an inner SeleneQuestState."""obj=cls.__new__(cls)obj._inner=innerreturnobj