Source code for pennylane.templates.subroutines.arbitrary_unitary
# 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.r"""Contains the ArbitraryUnitary template."""importpennylaneasqmlfrompennylane.operationimportAnyWires,Operationfrompennylane.opsimportPauliRot_PAULIS=["I","X","Y","Z"]def_tuple_to_word(index_tuple):"""Convert an integer tuple to the corresponding Pauli word. The Pauli operators are converted as ``0 -> I``, ``1 -> X``, ``2 -> Y``, ``3 -> Z``. Args: index_tuple (Tuple[int]): An integer tuple describing the Pauli word Returns: str: The corresponding Pauli word """return"".join([_PAULIS[i]foriinindex_tuple])def_n_k_gray_code(n,k,start=0):"""Iterates over a full n-ary Gray code with k digits. Args: n (int): Base of the Gray code. Needs to be greater than one. k (int): Number of digits of the Gray code. Needs to be greater than zero. start (int, optional): Optional start of the Gray code. The generated code will be shorter as the code does not wrap. Defaults to 0. """foriinrange(start,n**k):codeword=[0]*kbase_repesentation=[]val=iforjinrange(k):base_repesentation.append(val%n)val//=nshift=0forjinreversed(range(k)):codeword[j]=(base_repesentation[j]+shift)%nshift+=n-codeword[j]yieldcodeworddef_all_pauli_words_but_identity(num_wires):# Start at 1 to ignore identityyield from(_tuple_to_word(idx_tuple)foridx_tuplein_n_k_gray_code(4,num_wires,start=1))
[docs]classArbitraryUnitary(Operation):"""Implements an arbitrary unitary on the specified wires. An arbitrary unitary on :math:`n` wires is parametrized by :math:`4^n - 1` independent real parameters. This templates uses Pauli word rotations to parametrize the unitary. **Example** ArbitraryUnitary can be used as a building block, e.g. to parametrize arbitrary two-qubit operations in a circuit: .. code-block:: python def arbitrary_nearest_neighbour_interaction(weights, wires): for i, w in enumerate(range(0, len(wires) - 1, 2)): ArbitraryUnitary(weights[i], wires=[w, w + 1]) Args: weights (tensor_like): The angles of the Pauli word rotations, needs to have length :math:`4^n - 1` where :math:`n` is the number of wires the template acts upon. wires (Iterable): wires that the template acts on """num_wires=AnyWiresgrad_method=Nonenum_params=1ndim_params=(1,)def__init__(self,weights,wires,id=None):shape=qml.math.shape(weights)dim=4**len(wires)-1iflen(shape)notin(1,2)orshape[-1]!=dim:raiseValueError(f"Weights tensor must be of shape {(dim,)} or (batch_dim, {dim}); got {shape}.")super().__init__(weights,wires=wires,id=id)
[docs]@staticmethoddefcompute_decomposition(weights,wires):# pylint: disable=arguments-differr"""Representation of the operator as a product of other operators. .. math:: O = O_1 O_2 \dots O_n. .. seealso:: :meth:`~.ArbitraryUnitary.decomposition`. Args: weights (tensor_like): The angles of the Pauli word rotations, needs to have length :math:`4^n - 1` where :math:`n` is the number of wires the template acts upon. wires (Any or Iterable[Any]): wires that the operator acts on Returns: list[.Operator]: decomposition of the operator """op_list=[]fori,pauli_wordinenumerate(_all_pauli_words_but_identity(len(wires))):op_list.append(PauliRot(weights[...,i],pauli_word,wires=wires))returnop_list
[docs]@staticmethoddefshape(n_wires):"""Compute the expected shape of the weights tensor. Args: n_wires (int): number of wires that template acts on """return(4**n_wires-1,)