# Copyright 2018-2023 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."""The fermionic representation classes and functions."""importrefromcopyimportcopyimportpennylaneasqmlfrompennylane.typingimportTensorLike
[docs]classFermiWord(dict):r"""Immutable dictionary used to represent a Fermi word, a product of fermionic creation and annihilation operators, that can be constructed from a standard dictionary. The keys of the dictionary are tuples of two integers. The first integer represents the position of the creation/annihilation operator in the Fermi word and the second integer represents the orbital it acts on. The values of the dictionary are one of ``'+'`` or ``'-'`` symbols that denote creation and annihilation operators, respectively. The operator :math:`a^{\dagger}_0 a_1` can then be constructed as >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> print(w) a⁺(0) a(1) """# override the arithmetic dunder methods for numpy arrays so that the# methods defined on this class are used instead# (i.e. ensure `np.array + FermiWord` uses `FermiWord.__radd__` instead of `np.array.__add__`)__numpy_ufunc__=None__array_ufunc__=Nonedef__init__(self,operator):self.sorted_dic=dict(sorted(operator.items()))indices=[i[0]foriinself.sorted_dic.keys()]ifindices:iflist(range(max(indices)+1))!=indices:raiseValueError("The operator indices must belong to the set {0, ..., len(operator)-1}.")super().__init__(operator)
[docs]defadjoint(self):r"""Return the adjoint of FermiWord."""n=len(self.items())adjoint_dict={}forkey,valueinreversed(self.items()):position=n-key[0]-1orbital=key[1]fermi="+"ifvalue=="-"else"-"adjoint_dict[(position,orbital)]=fermireturnFermiWord(adjoint_dict)
[docs]defitems(self):"""Returns the dictionary items in sorted order."""returnself.sorted_dic.items()
@propertydefwires(self):r"""Return wires in a FermiWord."""returnset(i[1]foriinself.sorted_dic.keys())def__missing__(self,key):r"""Return empty string for a missing key in FermiWord."""return""
[docs]defupdate(self,item):r"""Restrict updating FermiWord after instantiation."""raiseTypeError("FermiWord object does not support assignment")
def__setitem__(self,key,item):r"""Restrict setting items after instantiation."""raiseTypeError("FermiWord object does not support assignment")def__reduce__(self):r"""Defines how to pickle and unpickle a FermiWord. Otherwise, un-pickling would cause __setitem__ to be called, which is forbidden on PauliWord. For more information, see: https://docs.python.org/3/library/pickle.html#object.__reduce__ """returnFermiWord,(dict(self),)def__copy__(self):r"""Copy the FermiWord instance."""returnFermiWord(dict(self.items()))def__deepcopy__(self,memo):r"""Deep copy the FermiWord instance."""res=self.__copy__()memo[id(self)]=resreturnresdef__hash__(self):r"""Hash value of a FermiWord."""returnhash(frozenset(self.items()))
[docs]defto_string(self):r"""Return a compact string representation of a FermiWord. Each operator in the word is represented by the number of the wire it operates on, and a `+` or `-` to indicate either a creation or annihilation operator. >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> w.to_string() 'a⁺(0) a(1)' """iflen(self)==0:return"I"symbol_map={"+":"\u207a","-":""}string=" ".join(["a"+symbol_map[j]+"("+i+")"fori,jinzip([str(i[1])foriinself.sorted_dic.keys()],self.sorted_dic.values())])returnstring
def__str__(self):r"""String representation of a FermiWord."""returnf"{self.to_string()}"def__repr__(self):r"""Terminal representation of a FermiWord"""returnf"FermiWord({self.sorted_dic})"def__add__(self,other):"""Add a FermiSentence, FermiWord or constant to a FermiWord. Converts both elements into FermiSentences, and uses the FermiSentence __add__ method"""self_fs=FermiSentence({self:1.0})ifisinstance(other,FermiSentence):returnself_fs+otherifisinstance(other,FermiWord):returnself_fs+FermiSentence({other:1.0})ifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot add {type(other)} to a FermiWord.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")returnself_fs+FermiSentence({FermiWord({}):other})def__radd__(self,other):"""Add a FermiWord to a constant, i.e. `2 + FermiWord({...})`"""returnself.__add__(other)def__sub__(self,other):"""Subtract a FermiSentence, FermiWord or constant from a FermiWord. Converts both elements into FermiSentences (with negative coefficient for `other`), and uses the FermiSentence __add__ method"""self_fs=FermiSentence({self:1.0})ifisinstance(other,FermiWord):returnself_fs+FermiSentence({other:-1.0})ifisinstance(other,FermiSentence):other_fs=FermiSentence(dict(zip(other.keys(),[-vforvinother.values()])))returnself_fs+other_fsifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot subtract {type(other)} from a FermiWord.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")returnself_fs+FermiSentence({FermiWord({}):-1*other})# -constant * Idef__rsub__(self,other):"""Subtract a FermiWord to a constant, i.e. `2 - FermiWord({...})`"""ifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot subtract a FermiWord from {type(other)}.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")self_fs=FermiSentence({self:-1.0})other_fs=FermiSentence({FermiWord({}):other})returnself_fs+other_fsdef__mul__(self,other):r"""Multiply a FermiWord with another FermiWord, a FermiSentence, or a constant. >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> print(w * w) a⁺(0) a(1) a⁺(0) a(1) """ifisinstance(other,FermiWord):iflen(self)==0:returncopy(other)iflen(other)==0:returncopy(self)order_final=[i[0]+len(self)foriinother.sorted_dic.keys()]other_wires=[i[1]foriinother.sorted_dic.keys()]dict_other=dict(zip([(order_idx,other_wires[i])fori,order_idxinenumerate(order_final)],other.values(),))dict_self=dict(zip(self.keys(),self.values()))dict_self.update(dict_other)returnFermiWord(dict_self)ifisinstance(other,FermiSentence):returnFermiSentence({self:1})*otherifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot multiply FermiWord by {type(other)}.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")returnFermiSentence({self:other})def__rmul__(self,other):r"""Reverse multiply a FermiWord Multiplies a FermiWord "from the left" with an object that can't be modified to support __mul__ for FermiWord. Will be defaulted in for example ``2 * FermiWord({(0, 0): "+"})``, where the ``__mul__`` operator on an integer will fail to multiply with a FermiWord"""returnself.__mul__(other)def__pow__(self,value):r"""Exponentiate a Fermi word to an integer power. >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> print(w**3) a⁺(0) a(1) a⁺(0) a(1) a⁺(0) a(1) """ifvalue<0ornotisinstance(value,int):raiseValueError("The exponent must be a positive integer.")operator=FermiWord({})for_inrange(value):operator*=selfreturnoperator
[docs]defto_mat(self,n_orbitals=None,format="dense",buffer_size=None):r"""Return the matrix representation. Args: n_orbitals (int or None): Number of orbitals. If not provided, it will be inferred from the largest orbital index in the Fermi operator. format (str): The format of the matrix. It is "dense" by default. Use "csr" for sparse. buffer_size (int or None)`: The maximum allowed memory in bytes to store intermediate results in the calculation of sparse matrices. It defaults to ``2 ** 30`` bytes that make 1GB of memory. In general, larger buffers allow faster computations. Returns: NumpyArray: Matrix representation of the :class:`~.FermiWord`. **Example** >>> w = FermiWord({(0, 0): '+', (1, 1): '-'}) >>> w.to_mat() array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]) """largest_orb_id=max(key[1]forkeyinself.keys())+1ifn_orbitalsandn_orbitals<largest_orb_id:raiseValueError(f"n_orbitals cannot be smaller than {largest_orb_id}, got: {n_orbitals}.")largest_order=n_orbitalsorlargest_orb_idreturnqml.jordan_wigner(self,ps=True).to_mat(wire_order=list(range(largest_order)),format=format,buffer_size=buffer_size)
[docs]defshift_operator(self,initial_position,final_position):r"""Shifts an operator in the FermiWord from ``initial_position`` to ``final_position`` by applying the fermionic anti-commutation relations. There are three `anti-commutator relations <https://en.wikipedia.org/wiki/Creation_and_annihilation_operators#Creation_and_annihilation_operators_in_quantum_field_theories>`_: .. math:: \left\{ a_i, a_j \right\} = 0, \quad \left\{ a^{\dagger}_i, a^{\dagger}_j \right\} = 0, \quad \left\{ a_i, a^{\dagger}_j \right\} = \delta_{ij}, where .. math:: \left\{a_i, a_j \right\} = a_i a_j + a_j a_i, and .. math:: \delta_{ij} = \begin{cases} 1 & i = j \\ 0 & i \neq j \end{cases}. Args: initial_position (int): The position of the operator to be shifted. final_position (int): The desired position of the operator. Returns: FermiSentence: The ``FermiSentence`` obtained after applying the anti-commutator relations. Raises: TypeError: if ``initial_position`` or ``final_position`` is not an integer ValueError: if ``initial_position`` or ``final_position`` are outside the range ``[0, len(fermiword) - 1]`` where ``len(fermiword)`` is the number of operators in the FermiWord. **Example** >>> w = qml.FermiWord({(0, 0): '+', (1, 1): '-'}) >>> w.shift_operator(0, 1) -1 * a(1) a⁺(0) """ifnotisinstance(initial_position,int)ornotisinstance(final_position,int):raiseTypeError("Positions must be integers.")ifinitial_position<0orfinal_position<0:raiseValueError("Positions must be positive integers.")ifinitial_position>len(self.sorted_dic)-1orfinal_position>len(self.sorted_dic)-1:raiseValueError("Positions are out of range.")ifinitial_position==final_position:returnFermiSentence({self:1})fw=selffs=FermiSentence({fw:1})delta=1ifinitial_position<final_positionelse-1current=initial_positionwhilecurrent!=final_position:indices=list(fw.sorted_dic.keys())next=current+deltacurr_idx,curr_val=indices[current],fw[indices[current]]next_idx,next_val=indices[next],fw[indices[next]]# commuting identical termsifcurr_idx[1]==next_idx[1]andcurr_val==next_val:current+=deltacontinuecoeff=fs.pop(fw)fw=dict(fw)fw[(current,next_idx[1])]=next_valfw[(next,curr_idx[1])]=curr_valifcurr_idx[1]!=next_idx[1]:delfw[curr_idx],fw[next_idx]fw=FermiWord(fw)# anti-commutator is 0ifcurr_val==next_valorcurr_idx[1]!=next_idx[1]:current+=deltafs+=-coeff*fwcontinue# anti-commutator is 1_min=min(current,next)_max=max(current,next)items=list(fw.sorted_dic.items())left=FermiWord({(i,key[1]):valuefori,(key,value)inenumerate(items[:_min])})middle=FermiWord({(i,key[1]):valuefori,(key,value)inenumerate(items[_min:_max+1])})right=FermiWord({(i,key[1]):valuefori,(key,value)inenumerate(items[_max+1:])})terms=left*(1-middle)*rightfs+=coeff*termscurrent+=deltareturnfs
# pylint: disable=useless-super-delegation
[docs]classFermiSentence(dict):r"""Immutable dictionary used to represent a Fermi sentence, a linear combination of Fermi words, with the keys as FermiWord instances and the values correspond to coefficients. >>> w1 = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> w2 = FermiWord({(0, 1) : '+', (1, 2) : '-'}) >>> s = FermiSentence({w1 : 1.2, w2: 3.1}) >>> print(s) 1.2 * a⁺(0) a(1) + 3.1 * a⁺(1) a(2) """# override the arithmetic dunder methods for numpy arrays so that the# methods defined on this class are used instead# (i.e. ensure `np.array + FermiSentence` uses `FermiSentence.__radd__` instead of `np.array.__add__`)__numpy_ufunc__=None__array_ufunc__=Nonedef__init__(self,operator):super().__init__(operator)
[docs]defadjoint(self):r"""Return the adjoint of FermiSentence."""adjoint_dict={}forkey,valueinself.items():word=key.adjoint()scalar=qml.math.conj(value)adjoint_dict[word]=scalarreturnFermiSentence(adjoint_dict)
@propertydefwires(self):r"""Return wires of the FermiSentence."""returnset().union(*(fw.wiresforfwinself.keys()))def__str__(self):r"""String representation of a FermiSentence."""iflen(self)==0:return"0 * I"return"\n+ ".join(f"{coeff} * {fw.to_string()}"forfw,coeffinself.items())def__repr__(self):r"""Terminal representation for FermiSentence."""returnf"FermiSentence({dict(self)})"def__missing__(self,key):r"""If the FermiSentence does not contain a FermiWord then the associated value will be 0."""return0.0def__add__(self,other):r"""Add a FermiSentence, FermiWord or constant to a FermiSentence by iterating over the smaller one and adding its terms to the larger one."""ifnotisinstance(other,(TensorLike,FermiWord,FermiSentence)):raiseTypeError(f"Cannot add {type(other)} to a FermiSentence.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")ifisinstance(other,FermiWord):other=FermiSentence({other:1})ifisinstance(other,TensorLike):other=FermiSentence({FermiWord({}):other})smaller_fs,larger_fs=((self,copy(other))iflen(self)<len(other)else(other,copy(self)))forkeyinsmaller_fs:larger_fs[key]+=smaller_fs[key]returnlarger_fsdef__radd__(self,other):"""Add a FermiSentence to a constant, i.e. `2 + FermiSentence({...})`"""returnself.__add__(other)def__sub__(self,other):r"""Subtract a FermiSentence, FermiWord or constant from a FermiSentence"""ifisinstance(other,FermiWord):other=FermiSentence({other:-1})returnself.__add__(other)ifisinstance(other,FermiSentence):other=FermiSentence(dict(zip(other.keys(),[-1*vforvinother.values()])))returnself.__add__(other)ifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot subtract {type(other)} from a FermiSentence.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")other=FermiSentence({FermiWord({}):-1*other})# -constant * Ireturnself.__add__(other)def__rsub__(self,other):"""Subtract a FermiSentence to a constant, i.e. >>> 2 - FermiSentence({...}) """ifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot subtract a FermiSentence from {type(other)}.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")self_fs=FermiSentence(dict(zip(self.keys(),[-1*vforvinself.values()])))other_fs=FermiSentence({FermiWord({}):other})# constant * Ireturnself_fs+other_fsdef__mul__(self,other):r"""Multiply two Fermi sentences by iterating over each sentence and multiplying the Fermi words pair-wise"""ifisinstance(other,FermiWord):other=FermiSentence({other:1})ifisinstance(other,FermiSentence):if(len(self)==0)or(len(other)==0):returnFermiSentence({FermiWord({}):0})product=FermiSentence({})forfw1,coeff1inself.items():forfw2,coeff2inother.items():product[fw1*fw2]+=coeff1*coeff2returnproductifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot multiply FermiSentence by {type(other)}.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")vals=[i*otherforiinself.values()]returnFermiSentence(dict(zip(self.keys(),vals)))def__rmul__(self,other):r"""Reverse multiply a FermiSentence Multiplies a FermiSentence "from the left" with an object that can't be modified to support __mul__ for FermiSentence. Will be defaulted in for example when multiplying ``2 * fermi_sentence``, since the ``__mul__`` operator on an integer will fail to multiply with a FermiSentence"""ifnotisinstance(other,TensorLike):raiseTypeError(f"Cannot multiply {type(other)} by FermiSentence.")ifqml.math.size(other)>1:raiseValueError(f"Arithmetic Fermi operations can only accept an array of length 1, "f"but received {other} of length {len(other)}")vals=[i*otherforiinself.values()]returnFermiSentence(dict(zip(self.keys(),vals)))def__pow__(self,value):r"""Exponentiate a Fermi sentence to an integer power."""ifvalue<0ornotisinstance(value,int):raiseValueError("The exponent must be a positive integer.")operator=FermiSentence({FermiWord({}):1})# 1 times Identityfor_inrange(value):operator*=selfreturnoperator
[docs]defsimplify(self,tol=1e-8):r"""Remove any FermiWords in the FermiSentence with coefficients less than the threshold tolerance."""items=list(self.items())forfw,coeffinitems:ifabs(coeff)<=tol:delself[fw]
[docs]defto_mat(self,n_orbitals=None,format="dense",buffer_size=None):r"""Return the matrix representation. Args: n_orbitals (int or None): Number of orbitals. If not provided, it will be inferred from the largest orbital index in the Fermi operator format (str): The format of the matrix. It is "dense" by default. Use "csr" for sparse. buffer_size (int or None)`: The maximum allowed memory in bytes to store intermediate results in the calculation of sparse matrices. It defaults to ``2 ** 30`` bytes that make 1GB of memory. In general, larger buffers allow faster computations. Returns: NumpyArray: Matrix representation of the :class:`~.FermiSentence`. **Example** >>> fs = FermiSentence({FermiWord({(0, 0): "+", (1, 1): "-"}): 1.2, FermiWord({(0, 0): "+", (1, 0): "-"}): 3.1}) >>> fs.to_mat() array([0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 1.2 + 0.0j, 3.1 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 3.1 + 0.0j]) """largest_orb_id=max(key[1]forfermi_wordinself.keys()forkeyinfermi_word.keys())+1ifn_orbitalsandn_orbitals<largest_orb_id:raiseValueError(f"n_orbitals cannot be smaller than {largest_orb_id}, got: {n_orbitals}.")largest_order=n_orbitalsorlargest_orb_idreturnqml.jordan_wigner(self,ps=True).to_mat(wire_order=list(range(largest_order)),format=format,buffer_size=buffer_size)
[docs]deffrom_string(fermi_string):r"""Return a fermionic operator object from its string representation. The string representation is a compact format that uses the orbital index and ``'+'`` or ``'-'`` symbols to indicate creation and annihilation operators, respectively. For instance, the string representation for the operator :math:`a^{\dagger}_0 a_1 a^{\dagger}_0 a_1` is ``'0+ 1- 0+ 1-'``. The ``'-'`` symbols can be optionally dropped such that ``'0+ 1 0+ 1'`` represents the same operator. The format commonly used in OpenFermion to represent the same operator, ``'0^ 1 0^ 1'`` , is also supported. Args: fermi_string (str): string representation of the fermionic object Returns: FermiWord: the fermionic operator object **Example** >>> from_string('0+ 1- 0+ 1-') a⁺(0) a(1) a⁺(0) a(1) >>> from_string('0+ 1 0+ 1') a⁺(0) a(1) a⁺(0) a(1) >>> from_string('0^ 1 0^ 1') a⁺(0) a(1) a⁺(0) a(1) >>> op1 = FermiC(0) * FermiA(1) * FermiC(2) * FermiA(3) >>> op2 = from_string('0+ 1- 2+ 3-') >>> op1 == op2 True """iffermi_string.isspace()ornotfermi_string:returnFermiWord({})fermi_string=" ".join(fermi_string.split())ifnotall(s.isdigit()orsin["+","-","^"," "]forsinfermi_string):raiseValueError(f"Invalid character encountered in string {fermi_string}.")fermi_string=re.sub(r"\^","+",fermi_string)operators=[i+"-"ifi[-1]notin"+-"elseiforiinre.split(r"\s",fermi_string)]returnFermiWord({(i,int(s[:-1])):s[-1]fori,sinenumerate(operators)})
def_to_string(fermi_op,of=False):r"""Return a string representation of the :class:`~.FermiWord` object. Args: fermi_op (FermiWord): the fermionic operator of (bool): whether to return a string representation in the same style as OpenFermion using the shorthand: 'q^' = a^\dagger_q 'q' = a_q. Each operator in the word is represented by the number of the wire it operates on Returns: (str): a string representation of the :class:`~.FermiWord` object **Example** >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> _to_string(w) '0+ 1-' >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'}) >>> _to_string(w, of=True) '0^ 1' """ifnotisinstance(fermi_op,FermiWord):raiseValueError(f"fermi_op must be a FermiWord, got: {type(fermi_op)}")pl_to_of_map={"+":"^","-":""}iflen(fermi_op)==0:return"I"op_list=[""for_inrange(len(fermi_op))]forloc,wireinfermi_op:ifof:op_str=str(wire)+pl_to_of_map[fermi_op[(loc,wire)]]else:op_str=str(wire)+fermi_op[(loc,wire)]op_list[loc]+=op_strreturn" ".join(op_list).rstrip()# pylint: disable=too-few-public-methods
[docs]classFermiC(FermiWord):r"""FermiC(orbital) The fermionic creation operator :math:`a^{\dagger}` For instance, the operator ``qml.FermiC(2)`` denotes :math:`a^{\dagger}_2`. This operator applied to :math:`\ket{0000}` gives :math:`\ket{0010}`. Args: orbital(int): the non-negative integer indicating the orbital the operator acts on. .. note:: While the ``FermiC`` class represents a mathematical operator, it is not a PennyLane qubit :class:`~.Operator`. .. seealso:: :class:`~pennylane.FermiA` **Example** To construct the operator :math:`a^{\dagger}_0`: >>> w = FermiC(0) >>> print(w) a⁺(0) This can be combined with the annihilation operator :class:`~pennylane.FermiA`. For example, :math:`a^{\dagger}_0 a_1 a^{\dagger}_2 a_3` can be constructed as: >>> w = qml.FermiC(0) * qml.FermiA(1) * qml.FermiC(2) * qml.FermiA(3) >>> print(w) a⁺(0) a(1) a⁺(2) a(3) """def__init__(self,orbital):ifnotisinstance(orbital,int)ororbital<0:raiseValueError(f"FermiC: expected a single, positive integer value for orbital, but received {orbital}")self.orbital=orbitaloperator={(0,orbital):"+"}super().__init__(operator)
[docs]defadjoint(self):"""Return the adjoint of FermiC."""returnFermiA(self.orbital)
[docs]classFermiA(FermiWord):r"""FermiA(orbital) The fermionic annihilation operator :math:`a` For instance, the operator ``qml.FermiA(2)`` denotes :math:`a_2`. This operator applied to :math:`\ket{0010}` gives :math:`\ket{0000}`. Args: orbital(int): the non-negative integer indicating the orbital the operator acts on. .. note:: While the ``FermiA`` class represents a mathematical operator, it is not a PennyLane qubit :class:`~.Operator`. .. seealso:: :class:`~pennylane.FermiC` **Example** To construct the operator :math:`a_0`: >>> w = FermiA(0) >>> print(w) a(0) This can be combined with the creation operator :class:`~pennylane.FermiC`. For example, :math:`a^{\dagger}_0 a_1 a^{\dagger}_2 a_3` can be constructed as: >>> w = qml.FermiC(0) * qml.FermiA(1) * qml.FermiC(2) * qml.FermiA(3) >>> print(w) a⁺(0) a(1) a⁺(2) a(3) """def__init__(self,orbital):ifnotisinstance(orbital,int)ororbital<0:raiseValueError(f"FermiA: expected a single, positive integer value for orbital, but received {orbital}")self.orbital=orbitaloperator={(0,orbital):"-"}super().__init__(operator)
[docs]defadjoint(self):"""Return the adjoint of FermiA."""returnFermiC(self.orbital)