# Copyright 2018-2021 Xanadu Quantum Technologies Inc.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# http://www.apache.org/licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""This module contains the qml.state measurement."""fromcollections.abcimportSequencefromtypingimportOptionalimportpennylaneasqmlfrompennylane.typingimportTensorLikefrompennylane.wiresimportWireError,Wiresfrom.measurementsimportState,StateMeasurement
[docs]defstate()->"StateMP":r"""Quantum state in the computational basis. This function accepts no observables and instead instructs the QNode to return its state. A ``wires`` argument should *not* be provided since ``state()`` always returns a pure state describing all wires in the device. Note that the output shape of this measurement process depends on the number of wires defined for the device. Returns: StateMP: Measurement process instance **Example:** .. code-block:: python3 dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(): qml.Hadamard(wires=1) return qml.state() Executing this QNode: >>> circuit() array([0.70710678+0.j, 0.70710678+0.j, 0. +0.j, 0. +0.j]) The returned array is in lexicographic order. Hence, we have a :math:`1/\sqrt{2}` amplitude in both :math:`|00\rangle` and :math:`|01\rangle`. .. note:: Differentiating :func:`~pennylane.state` is currently only supported when using the classical backpropagation differentiation method (``diff_method="backprop"``) with a compatible device. .. details:: :title: Usage Details A QNode with the ``qml.state`` output can be used in a cost function which is then differentiated: >>> dev = qml.device('default.qubit', wires=2) >>> @qml.qnode(dev, diff_method="backprop") ... def test(x): ... qml.RY(x, wires=[0]) ... return qml.state() >>> def cost(x): ... return np.abs(test(x)[0]) >>> cost(x) 0.9987502603949663 >>> qml.grad(cost)(x) tensor(-0.02498958, requires_grad=True) """returnStateMP()
[docs]defdensity_matrix(wires)->"DensityMatrixMP":r"""Quantum density matrix in the computational basis. This function accepts no observables and instead instructs the QNode to return its density matrix or reduced density matrix. The ``wires`` argument gives the possibility to trace out a part of the system. It can result in obtaining a mixed state, which can be only represented by the reduced density matrix. Args: wires (Sequence[int] or int): the wires of the subsystem Returns: DensityMatrixMP: Measurement process instance **Example:** .. code-block:: python3 dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(): qml.Y(0) qml.Hadamard(wires=1) return qml.density_matrix([0]) Executing this QNode: >>> circuit() array([[0.+0.j 0.+0.j] [0.+0.j 1.+0.j]]) The returned matrix is the reduced density matrix, where system 1 is traced out. .. note:: Calculating the derivative of :func:`~pennylane.density_matrix` is currently only supported when using the classical backpropagation differentiation method (``diff_method="backprop"``) with a compatible device. """wires=Wires(wires)returnDensityMatrixMP(wires=wires)
[docs]classStateMP(StateMeasurement):"""Measurement process that returns the quantum state in the computational basis. Please refer to :func:`pennylane.state` for detailed documentation. Args: wires (.Wires): The wires the measurement process applies to. id (str): custom label given to a measurement instance, can be useful for some applications where the instance has to be identified """_shortname=State#! Note: deprecated. Change the value to "state" in v0.42def__init__(self,wires:Optional[Wires]=None,id:Optional[str]=None):super().__init__(wires=wires,id=id)@classmethoddef_abstract_eval(cls,n_wires:Optional[int]=None,has_eigvals=False,shots:Optional[int]=None,num_device_wires:int=0,):n_wires=n_wiresornum_device_wiresshape=(2**n_wires,)returnshape,complex@propertydefnumeric_type(self):returncomplex
[docs]defprocess_state(self,state:Sequence[complex],wire_order:Wires):# pylint:disable=redefined-outer-namedefcast_to_complex(state):dtype=str(state.dtype)if"complex"indtype:returnstateifqml.math.get_interface(state)=="tensorflow":returnqml.math.cast(state,"complex128")floating_single="float32"indtypeor"complex64"indtypereturnqml.math.cast(state,"complex64"iffloating_singleelse"complex128")ifnotself.wiresorwire_order==self.wires:returncast_to_complex(state)ifnotall(winself.wiresforwinwire_order):bad_wires=[wforwinwire_orderifwnotinself.wires]raiseWireError(f"State wire order has wires {bad_wires} not present in "f"measurement with wires {self.wires}. StateMP.process_state cannot trace out wires.")shape=(2,)*len(wire_order)batch_size=Noneifqml.math.ndim(state)==1elseqml.math.shape(state)[0]shape=(batch_size,)+shapeifbatch_sizeelseshapestate=qml.math.reshape(state,shape)ifwires_to_add:=Wires(set(self.wires)-set(wire_order)):for_inwires_to_add:state=qml.math.stack([state,qml.math.zeros_like(state)],axis=-1)wire_order=wire_order+wires_to_adddesired_axes=[wire_order.index(w)forwinself.wires]ifbatch_size:desired_axes=[0]+[i+1foriindesired_axes]state=qml.math.transpose(state,desired_axes)flat_shape=(2**len(self.wires),)ifbatch_size:flat_shape=(batch_size,)+flat_shapestate=qml.math.reshape(state,flat_shape)returncast_to_complex(state)
[docs]defprocess_density_matrix(self,density_matrix:Sequence[complex],wire_order:Wires):# pylint:disable=redefined-outer-nameraiseValueError("Processing from density matrix to state is not supported.")
[docs]classDensityMatrixMP(StateMP):"""Measurement process that returns the quantum state in the computational basis. Please refer to :func:`density_matrix` for detailed documentation. Args: wires (.Wires): The wires the measurement process applies to. id (str): custom label given to a measurement instance, can be useful for some applications where the instance has to be identified """def__init__(self,wires:Wires,id:Optional[str]=None):super().__init__(wires=wires,id=id)@classmethoddef_abstract_eval(cls,n_wires:Optional[int]=None,has_eigvals=False,shots:Optional[int]=None,num_device_wires:int=0,):n_wires=n_wiresornum_device_wiresshape=(2**n_wires,2**n_wires)returnshape,complex