class_docstr: Implements a local, expressive, and quantum-number-preserving ansatz proposed by
  `Anselmetti et al. (2021) <https://doi.org/10.1088/1367-2630/ac2cb3>`_.
  
  This template prepares the :math:`N`-qubit trial state by applying :math:`D` layers of gate-fabric blocks
  :math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` to the Hartree-Fock state in the Jordan-Wigner basis
  
  .. math::
  
      \vert \Psi(\vec{\theta},\vec{\phi})\rangle =
      \hat{U}_{GF}^{(D)}(\vec{\theta}_{D},\vec{\phi}_{D}) \ldots
      \hat{U}_{GF}^{(2)}(\vec{\theta}_{2},\vec{\phi}_{2})
      \hat{U}_{GF}^{(1)}(\vec{\theta}_{1},\vec{\phi}_{1}) \vert HF \rangle,
  
  where each of the gate fabric blocks :math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` is comprised of two-parameter four-qubit
  gates :math:`\hat{Q}(\theta, \phi)` that act on four nearest-neighbour qubits. The circuit implementing a
  single layer of the gate fabric block for :math:`N = 8` is shown in the figure below:
  
  .. figure:: ../../_static/templates/layers/gate_fabric_layer.png
      :align: center
      :width: 100%
      :target: javascript:void(0);
  
  The gate element :math:`\hat{Q}(\theta, \phi)` (`Anselmetti et al. (2021) <https://doi.org/10.1088/1367-2630/ac2cb3>`_)
  is composed of a four-qubit spin-adapted spatial orbital rotation gate, which is implemented by the :class:`~.OrbitalRotation()`
  operation and a four-qubit diagonal pair-exchange gate, which is equivalent to the :class:`~.DoubleExcitation()`
  operation. In addition to these two gates, the gate element :math:`\hat{Q}(\theta, \phi)` can also include an optional
  constant :math:`\hat{\Pi} \in \{\hat{I}, \text{OrbitalRotation}(\pi)\}` gate.
  
  .. figure:: ../../_static/templates/layers/q_gate_decompositon.png
      :align: center
      :width: 75%
      :target: javascript:void(0);
  
  |
  
  The four-qubit :class:`~.DoubleExcitation()` and :class:`~.OrbitalRotation()` gates given here are equivalent to the
  :math:`\text{QNP}_{PX}(\theta)` and :math:`\text{QNP}_{OR}(\phi)` gates presented in
  `Anselmetti et al. (2021) <https://doi.org/10.1088/1367-2630/ac2cb3>`_,
  respectively. Moreover, regardless of the choice of :math:`\hat{\Pi}`, this gate fabric will exactly preserve the number of particles
  and total spin of the state.
  
  Args:
      weights (tensor_like): Array of weights of shape ``(D, L, 2)``\,
          where ``D`` is the number of gate fabric layers and ``L = N/2-1``
          is the number of :math:`\hat{Q}(\theta, \phi)` gates per layer with N being the total number of qubits.
      wires (Iterable): wires that the template acts on
      init_state (tensor_like): init_state (tensor_like): iterable of shape ``(len(wires),)``\, representing the input Hartree-Fock state
          in the Jordan-Wigner representation.
      include_pi (boolean): If True, the optional constant :math:`\hat{\Pi}` gate  is set to :math:`\text{OrbitalRotation}(\pi)`.
          Default value is :math:`\hat{I}`.
  
  .. details::
      :title: Usage Details
  
      #. The number of wires :math:`N` has to be equal to the number of
         spin-orbitals included in the active space, and should be even.
  
      #. The number of trainable parameters scales linearly with the number of layers as
         :math:`2 D (N/2-1)`.
  
      An example of how to use this template is shown below:
  
      .. code-block:: python
  
          import pennylane as qml
          from pennylane import numpy as np
  
          # Build the electronic Hamiltonian
          symbols = ["H", "H"]
          coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])
          H, qubits = qml.qchem.molecular_hamiltonian(symbols, coordinates)
  
          # Define the Hartree-Fock state
          electrons = 2
          ref_state = qml.qchem.hf_state(electrons, qubits)
  
          # Define the device
          dev = qml.device('default.qubit', wires=qubits)
  
          # Define the ansatz
          @qml.qnode(dev)
          def ansatz(weights):
              qml.GateFabric(weights, wires=[0,1,2,3],
                          init_state=ref_state, include_pi=True)
              return qml.expval(H)
  
          # Get the shape of the weights for this template
          layers = 2
          shape = qml.GateFabric.shape(n_layers=layers, n_wires=qubits)
  
          # Initialize the weight tensors
          np.random.seed(42)
          weights = np.random.random(size=shape)
  
          # Define the optimizer
          opt = qml.GradientDescentOptimizer(stepsize=0.4)
  
          # Store the values of the cost function
          energy = [ansatz(weights)]
  
          # Store the values of the circuit weights
          angle = [weights]
  
          max_iterations = 100
          conv_tol = 1e-06
  
          for n in range(max_iterations):
              weights, prev_energy = opt.step_and_cost(ansatz, weights)
              energy.append(ansatz(weights))
              angle.append(weights)
              conv = np.abs(energy[-1] - prev_energy)
  
              if n % 2 == 0:
                  print(f"Step = {n},  Energy = {energy[-1]:.8f} Ha")
  
              if conv <= conv_tol:
                  break
  
          print("\n" f"Final value of the ground-state energy = {energy[-1]:.8f} Ha")
          print("\n" f"Optimal value of the circuit parameters = {angle[-1]}")
  
      .. code-block:: none
  
          Step = 0,  Energy = -0.87007254 Ha
          Step = 2,  Energy = -1.13107530 Ha
          Step = 4,  Energy = -1.13611971 Ha
          Step = 6,  Energy = -1.13618810 Ha
  
          Final value of the ground-state energy = -1.13618903 Ha
  
          Optimal value of the circuit parameters = [[[ 0.60328427  0.41850407]]
          [[ 0.85581129 -0.24522642]]]
  
  
      **Parameter shape**
  
      The shape of the weights argument can be computed by the static method
      :meth:`~.GateFabric.shape` and used when creating randomly
      initialised weight tensors:
  
      .. code-block:: python
  
          shape = GateFabric.shape(n_layers=2, n_wires=4)
          weights = np.random.random(size=shape)
  
      >>> weights.shape
      (2, 1, 2)
code: def num_params(self):
      return 1
  
file_path: pennylane/pennylane/templates/layers/gate_fabric.py
imports: import numpy
  import pennylane
  from pennylane.operation import Operation, AnyWires
label_desc: Use image node_id 2 for calling the GateFabric obj's underlying member method code with example usage: obj.num_params() and returns: int