code: def create_masks(input_dim,
                   hidden_dims,
                   input_order='left-to-right',
                   hidden_order='left-to-right'):
    
    degrees = create_degrees(input_dim, hidden_dims, input_order, hidden_order)
    masks = []
    # Create input-to-hidden and hidden-to-hidden masks.
    for input_degrees, output_degrees in zip(degrees[:-1], degrees[1:]):
      mask = tf.cast(input_degrees[:, np.newaxis] <= output_degrees, tf.float32)
      masks.append(mask)
  
    # Create hidden-to-output mask.
    mask = tf.cast(degrees[-1][:, np.newaxis] < degrees[0], tf.float32)
    masks.append(mask)
    return masks
docs: Returns a list of binary mask matrices respecting autoregressive ordering.
  
    Args:
      input_dim: Number of inputs.
      hidden_dims: list with the number of hidden units per layer. It does not
        include the output layer; those number of units will always be set to
        input_dim downstream. Each hidden unit size must be at least the size of
        length (otherwise autoregressivity is not possible).
      input_order: Order of degrees to the input units: 'random', 'left-to-right',
        'right-to-left', or an array of an explicit order. For example,
        'left-to-right' builds an autoregressive model
        p(x) = p(x1) p(x2 | x1) ... p(xD | x<D).
      hidden_order: Order of degrees to the hidden units: 'random',
        'left-to-right'. If 'left-to-right', hidden units are allocated equally
        (up to a remainder term) to each degree.