class_docstr: Class for NOTEARS MLP (Multi-layer Perceptron) model.
  The model weights consist of dag_layer and loc_lin_layer weights respectively.
  dag_layer weight is the weight of the first fully connected layer which determines the causal structure.
  loc_lin_layer weights are the weight of hidden layers after the first fully connected layer
class_docstr_tok: ["Class","for","NOTEARS","MLP","(","Multi-layer","Perceptron",")","model",".","The","model","weights","consist","of","dag_layer","and","loc_lin_layer","weights","respectively",".","dag_layer","weight","is","the","weight","of","the","first","fully","connected","layer","which","determines","the","causal","structure",".","loc_lin_layer","weights","are","the","weight","of","hidden","layers","after","the","first","fully","connected","layer"]
docstr: Constraint function of the NOTEARS algorithm.
  Constrain 2-norm-squared of dag_layer weights of the model along m1 dim to be a DAG
  
  Returns:
      DAGness of the adjacency matrix
docstr_tok: ["Constraint","function","of","the","NOTEARS","algorithm",".","Constrain","2-norm-squared","of","dag_layer","weights","of","the","model","along","m1","dim","to","be","a","DAG","Returns",":","DAGness","of","the","adjacency","matrix"]
code: def _h_func(self) -> torch.Tensor:
      """
      Constraint function of the NOTEARS algorithm.
      Constrain 2-norm-squared of dag_layer weights of the model along m1 dim to be a DAG
  
      Returns:
          DAGness of the adjacency matrix
      """
      d = self.dims[0]
  
      # only consider the dag_layer for h(W) for compute efficiency
      dag_layer_weight = self.dag_layer_weight.view(
          d, -1, d
      )  # [j, m1, i]
      square_weight_mat = torch.sum(
          dag_layer_weight * dag_layer_weight, dim=1
      ).t()  # [i, j]
  
      # modify the h(W) matrix to deal with expanded columns
      original_idxs = []
  
      for dist_type in self.dist_types:
          # modify the weight matrix to prevent spurious cycles with expended columns
          square_weight_mat = dist_type.modify_h(square_weight_mat)
          # gather the original idxs
          original_idxs.append(dist_type.idx)
  
      # original size is largest original index
      original_size = np.max(original_idxs) + 1
      # subselect the top LH corner of matrix which corresponds to original data
      square_weight_mat = square_weight_mat[
          :original_size, :original_size
      ]
      # update d and d_torch to match the new matrix size
      d = square_weight_mat.shape[0]
      d_torch = torch.tensor(d).to(self.device)
  
      # h = trace_expm(a) - d  # (Zheng et al. 2018)
      characteristic_poly_mat = (
          torch.eye(d).to(self.device) + square_weight_mat / d_torch
      )  # (Yu et al. 2019)
      polynomial_mat = torch.matrix_power(
          characteristic_poly_mat, d - 1
      )
      h = (polynomial_mat.t() * characteristic_poly_mat).sum() - d
      return h
  
imports: import logging
  from typing import Iterable, List, Tuple, Union
  import numpy
  import scipy.optimize
  import torch
  from sklearn.base import BaseEstimator
  from torch import nn
  from causalnex.structure.pytorch.dist_type._base import DistTypeBase
  from causalnex.structure.pytorch.nonlinear import LocallyConnected
label_desc: Use image node_id 11 for calling the NotearsMLP obj's underlying member method code with example usage: obj._h_func() and returns: h