@Override
  public double getSummaryForInstance(GraphicalModel model, ConcatVector weights, ConcatVector gradient) {
    double logLikelihood = 0.0;

    CliqueTree.MarginalResult result = new CliqueTree(model, weights).calculateMarginals();

    // Select just the VectorFactors, since those are the only ones that generate gradients

    List<GraphicalModel.VectorFactor> vectorFactors = new ArrayList<>();
    for (GraphicalModel.Factor factor : model.factors) {
      if (factor instanceof GraphicalModel.VectorFactor) {
        vectorFactors.add((GraphicalModel.VectorFactor)factor);
      }
    }

    // Cache everything in preparation for multiple redundant requests for feature vectors

    for (GraphicalModel.VectorFactor factor : vectorFactors) {
      factor.featuresTable.cacheVectors();
    }

    // Subtract log partition function

    logLikelihood -= Math.log(result.partitionFunction);

    // Quit if we have an infinite partition function

    if (Double.isInfinite(logLikelihood)) return 0.0;

    // Add the determined assignment by training values

    for (GraphicalModel.VectorFactor factor : vectorFactors) {
      // Find the assignment, taking both fixed and training observed variables into account
      int[] assignment = new int[factor.neigborIndices.length];
      for (int i = 0; i < assignment.length; i++) {
        int deterministicValue = getDeterministicAssignment(result.marginals[factor.neigborIndices[i]]);
        if (deterministicValue != -1) {
          assignment[i] = deterministicValue;
        } else {
          int trainingObservation = Integer.parseInt(model.getVariableMetaDataByReference(factor.neigborIndices[i]).get(LogLikelihoodDifferentiableFunction.VARIABLE_TRAINING_VALUE));
          assignment[i] = trainingObservation;
        }
        if (assignment[i] < 0 || assignment[i] >= factor.featuresTable.getDimensions()[i]) {
          throw new IllegalStateException("Model isn't fully or correctly labeled. Have that variable " + i + " has assignment " + assignment[i] + " (-1 means no label was present).\n" +
              "To solve this problem, make sure you set model.getVariableMetaDataByReference(i).put(LogLikelihoodDifferentiableFunction.VARIABLE_TRAINING_VALUE, \"\"+variableTrainingLabel) for all the" +
              " variables represented in the model before using it as a training example.");
        }
      }
      ConcatVector features = factor.featuresTable.getAssignmentValue(assignment).get();
      // Add the log-likelihood from this observation to the log-likelihood
      logLikelihood += features.dotProduct(weights);
      // Add the vector from this observation to the gradient
      gradient.addVectorInPlace(features, 1.0);
    }

    // Take expectations over features given marginals
    // NOTE: This is extremely expensive. Not sure what to do about that

    for (GraphicalModel.VectorFactor factor : vectorFactors) {
      // OPTIMIZATION:
      // Rather than use the standard iterator, which creates lots of int[] arrays on the heap, which need to be GC'd,
      // we use the fast version that just mutates one array. Since this is read once for us here, this is ideal.
      Iterator<int[]> fastPassByReferenceIterator = factor.featuresTable.fastPassByReferenceIterator();
      int[] assignment = fastPassByReferenceIterator.next();
      while (true) {
        // calculate assignment prob
        double assignmentProb = result.jointMarginals.get(factor).getAssignmentValue(assignment);
        // subtract this feature set, weighted by the probability of the assignment
        if (assignmentProb > 0) {
          gradient.addVectorInPlace(factor.featuresTable.getAssignmentValue(assignment).get(), -assignmentProb);
        }
        // This mutates the assignment[] array, rather than creating a new one
        if (fastPassByReferenceIterator.hasNext()) fastPassByReferenceIterator.next();
        else break;
      }
    }

    // Uncache everything, now that the computations have completed

    for (GraphicalModel.VectorFactor factor : vectorFactors) {
      factor.featuresTable.releaseCache();
    }

    return logLikelihood;
  }
@ Override public double getSummaryForInstance ( GraphicalModel model , ConcatVector weights , ConcatVector gradient ) { double logLikelihood = 0.0 ; CliqueTree . MarginalResult result = new CliqueTree ( model , weights ) . calculateMarginals ( ) ; List < GraphicalModel . VectorFactor > vectorFactors = new ArrayList < > ( ) ; for ( GraphicalModel . Factor factor : model . factors ) { if ( factor instanceof GraphicalModel . VectorFactor ) { vectorFactors . add ( ( GraphicalModel . VectorFactor ) factor ) ; } } for ( GraphicalModel . VectorFactor factor : vectorFactors ) { factor . featuresTable . cacheVectors ( ) ; } logLikelihood -= Math . log ( result . partitionFunction ) ; if ( Double . isInfinite ( logLikelihood ) ) return 0.0 ; for ( GraphicalModel . VectorFactor factor : vectorFactors ) { int [ ] assignment = new int [ factor . neigborIndices . length ] ; for ( int i = 0 ; i < assignment . length ; i ++ ) { int deterministicValue = getDeterministicAssignment ( result . marginals [ factor . neigborIndices [ i ] ] ) ; if ( deterministicValue != - 1 ) { assignment [ i ] = deterministicValue ; } else { int trainingObservation = Integer . parseInt ( model . getVariableMetaDataByReference ( factor . neigborIndices [ i ] ) . get ( LogLikelihoodDifferentiableFunction . VARIABLE_TRAINING_VALUE ) ) ; assignment [ i ] = trainingObservation ; } if ( assignment [ i ] < 0 || assignment [ i ] >= factor . featuresTable . getDimensions ( ) [ i ] ) { throw new IllegalStateException ( "Model isn't fully or correctly labeled. Have that variable " + i + " has assignment " + assignment [ i ] + " (-1 means no label was present).\n" + "To solve this problem, make sure you set model.getVariableMetaDataByReference(i).put(LogLikelihoodDifferentiableFunction.VARIABLE_TRAINING_VALUE, \"\"+variableTrainingLabel) for all the" + " variables represented in the model before using it as a training example." ) ; } } ConcatVector features = factor . featuresTable . getAssignmentValue ( assignment ) . get ( ) ; logLikelihood += features . dotProduct ( weights ) ; gradient . addVectorInPlace ( features , 1.0 ) ; } for ( GraphicalModel . VectorFactor factor : vectorFactors ) { Iterator < int [ ] > fastPassByReferenceIterator = factor . featuresTable . fastPassByReferenceIterator ( ) ; int [ ] assignment = fastPassByReferenceIterator . next ( ) ; while ( true ) { double assignmentProb = result . jointMarginals . get ( factor ) . getAssignmentValue ( assignment ) ; if ( assignmentProb > 0 ) { gradient . addVectorInPlace ( factor . featuresTable . getAssignmentValue ( assignment ) . get ( ) , - assignmentProb ) ; } if ( fastPassByReferenceIterator . hasNext ( ) ) fastPassByReferenceIterator . next ( ) ; else break ; } } for ( GraphicalModel . VectorFactor factor : vectorFactors ) { factor . featuresTable . releaseCache ( ) ; } return logLikelihood ; }
Gets a summary of the log-likelihood of a singe model at a point
<p>
It assumes that the models have observations for training set as metadata in
LogLikelihoodDifferentiableFunction.OBSERVATION_FOR_TRAINING. The models can also have observations fixed in
CliqueTree.VARIABLE_OBSERVED_VALUE, but these will be considered fixed and will not be learned against.

@param model   the model to find the log-likelihood of
@param weights the weights to use
@return the gradient and value of the function at that point