code: public StaticFactor addStaticNormalizedFactor(int[] neighborIndices, int[] neighborDimensions, Function<int[], Double> assignmentFeaturizer) {
      NDArrayDoubles doubleArray = new NDArrayDoubles(neighborDimensions);
      double localPartitionFunction = 0.0;
      for (int[] assignment : doubleArray) {
        localPartitionFunction += Math.exp(assignmentFeaturizer.apply(assignment));
      }
      for (int[] assignment : doubleArray) {
        doubleArray.setAssignmentValue(assignment, assignmentFeaturizer.apply(assignment) - Math.log(localPartitionFunction));
      }
      return addStaticFactor(doubleArray, neighborIndices);
    }
docs: This adds a static factor to the model, which will always produce the same value regardless of the assignment of
  weights during inference.
  This additionally normalizes the factor, so that it will maintain a normalized partition function; e.g.,
  after a call to {@link CliqueTree#compileNormalizedModel()}.
  
  @param neighborIndices the names of the variables, as indices
  @param assignmentFeaturizer a function that maps from an assignment to the variables, represented as an array of
  assignments in the same order as presented in neighborIndices, to a constant value.
  
  @return a reference to the created factor. This can be safely ignored, as the factor is already saved in the model