<NME> Reranker.java
<BEF> package edu.neu.ccs.pyramid.calibration;

import edu.neu.ccs.pyramid.dataset.LabelTranslator;
import edu.neu.ccs.pyramid.dataset.MultiLabel;
import edu.neu.ccs.pyramid.feature.FeatureList;
import edu.neu.ccs.pyramid.multilabel_classification.DynamicProgramming;
import edu.neu.ccs.pyramid.multilabel_classification.MultiLabelClassifier;
import edu.neu.ccs.pyramid.multilabel_classification.cbm.BMDistribution;
import edu.neu.ccs.pyramid.multilabel_classification.cbm.CBM;
import edu.neu.ccs.pyramid.multilabel_classification.plugin_rule.GeneralF1Predictor;
import edu.neu.ccs.pyramid.regression.Regressor;
import edu.neu.ccs.pyramid.util.Pair;
import org.apache.mahout.math.Vector;


import java.util.*;
import java.util.stream.Collectors;

public class Reranker implements MultiLabelClassifier, VectorCalibrator {
    private static final long serialVersionUID = 2L;
    int numCandidate;
    private PredictionFeatureExtractor predictionFeatureExtractor;
    private LabelCalibrator labelCalibrator;
    private transient boolean allowEmpty = true;


    public Reranker(Regressor regressor, ClassProbEstimator classProbEstimator, int numCandidate,

    public Reranker(Regressor regressor, ClassProbEstimator classProbEstimator, int numCandidate,
                    PredictionFeatureExtractor predictionFeatureExtractor, LabelCalibrator labelCalibrator) {
        this.regressor = regressor;
        this.classProbEstimator = classProbEstimator;
        this.numCandidate = numCandidate;
        this.predictionFeatureExtractor = predictionFeatureExtractor;
        this.labelCalibrator = labelCalibrator;
    }

    }


    public boolean allowEmpty() {
        return allowEmpty;
    }

    public void setAllowEmpty(boolean allowEmpty) {
        this.allowEmpty = allowEmpty;
    }

    @Override

    @Override
    public int getNumClasses() {
        return classProbEstimator.getNumClasses();
    }

    public double prob(Vector vector, MultiLabel multiLabel){
        double[] marginals = labelCalibrator.calibratedClassProbs(classProbEstimator.predictClassProbs(vector));
        DynamicProgramming dynamicProgramming = new DynamicProgramming(marginals);
        List<Pair<MultiLabel,Double>> topK = dynamicProgramming.topK(numCandidate);

        PredictionCandidate predictionCandidate = new PredictionCandidate();
        predictionCandidate.x = vector;
        predictionCandidate.labelProbs = marginals;
        predictionCandidate.multiLabel = multiLabel;
        predictionCandidate.sparseJoint = topK;
        Vector feature = predictionFeatureExtractor.extractFeatures(predictionCandidate);
        double score = regressor.predict(feature);
        if (score>1){
            score=1;
        }

        if (score<0){
            score=0;
        }
        return score;
    }

        for (int i=0;i<numCandidate;i++){
            MultiLabel candidate = dynamicProgramming.nextHighestVector();

            if (!allowEmpty&&candidate.getNumMatchedLabels()==0){
                continue;
            }

    public MultiLabel predict(Vector vector, double[] uncalibratedLabelScores) {
        double[] marginals = labelCalibrator.calibratedClassProbs(uncalibratedLabelScores);

        DynamicProgramming dynamicProgramming = new DynamicProgramming(marginals);
        List<Pair<MultiLabel,Double>> sparseJoint = dynamicProgramming.topK(numCandidate);

            double score = regressor.predict(feature);
            candidates.add(new Pair<>(candidate,score));
        }
        //todo
//        AccPredictor accPredictor = new AccPredictor(cbm);
//        accPredictor.setComponentContributionThreshold(0.001);
//        MultiLabel cbmPre = accPredictor.predict(vector);
//        Vector feature = predictionVectorizer.feature(bmDistribution, cbmPre,marginals,Optional.of(positionMap));
//        double score = regressor.predict(feature);
//        candidates.add(new Pair<>(cbmPre,score));


        Comparator<Pair<MultiLabel,Double>> comparator = Comparator.comparing(pair->pair.getSecond());
            Vector feature = predictionFeatureExtractor.extractFeatures(predictionCandidate);
            double score = regressor.predict(feature);
            candidates.add(new Pair<>(candidate,score));
        }
//            System.out.println("number of ties = "+ties.size()+", "+ties);
//        }

        return candidates.stream().max(comparator).map(pair->pair.getFirst()).get();
    }


//        double[] marginals = labelCalibrator.calibratedClassProbs(classProbEstimator.predictClassProbs(vector));
//        DynamicProgramming dynamicProgramming = new DynamicProgramming(marginals);
//        List<MultiLabel> multiLabels = new ArrayList<>();
//        List<Double> probabilities = new ArrayList<>();
//
//        for (int i=0;i<numCandidate;i++){
//            MultiLabel candidate = dynamicProgramming.nextHighestVector();
//
//            PredictionCandidate predictionCandidate = new PredictionCandidate();
//            predictionCandidate.x = vector;
//            predictionCandidate.labelProbs = marginals;
//            predictionCandidate.multiLabel = candidate;
//
//            Vector feature = predictionFeatureExtractor.extractFeatures(predictionCandidate);
//            double score = regressor.predict(feature);
//            multiLabels.add(candidate);
//            probabilities.add(score);
//        }
//        GeneralF1Predictor generalF1Predictor = new GeneralF1Predictor();
//        return generalF1Predictor.predict(classProbEstimator.getNumClasses(),multiLabels,probabilities);
//    }



//    public boolean isInTopK(Vector vector,  MultiLabel groundTruth){
//        double[] marginals = predictionVectorizer.getLabelCalibrator().calibratedClassProbs(classProbEstimator.predictClassProbs(vector));
//        DynamicProgramming dynamicProgramming = new DynamicProgramming(marginals);
//        for (int i=0;i<numCandidate;i++) {
//            MultiLabel candidate = dynamicProgramming.nextHighestVector();
//            if (candidate.equals(groundTruth)){
//                return true;
//            }
//        }
//        return false;
//    }

    @Override
    public FeatureList getFeatureList() {
        return null;
    }

    @Override
    public LabelTranslator getLabelTranslator() {
        return null;
    }

    @Override
    public double calibrate(Vector vector) {
        double score = regressor.predict(vector);
        if (score>1){
            score=1;
        }

        if (score<0){
            score=0;
        }
        return score;
    }


    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Reranker{");
        sb.append("regressor=").append(regressor);
        sb.append('}');
        return sb.toString();
    }
}

<MSG> set predict.minSize and predict.maxSize

<DFF> @@ -9,6 +9,7 @@ import edu.neu.ccs.pyramid.multilabel_classification.cbm.BMDistribution;
 import edu.neu.ccs.pyramid.multilabel_classification.cbm.CBM;
 import edu.neu.ccs.pyramid.multilabel_classification.plugin_rule.GeneralF1Predictor;
 import edu.neu.ccs.pyramid.regression.Regressor;
+import edu.neu.ccs.pyramid.util.ArgMax;
 import edu.neu.ccs.pyramid.util.Pair;
 import org.apache.mahout.math.Vector;
 
@@ -21,7 +22,9 @@ public class Reranker implements MultiLabelClassifier, VectorCalibrator {
     int numCandidate;
     private PredictionFeatureExtractor predictionFeatureExtractor;
     private LabelCalibrator labelCalibrator;
-    private transient boolean allowEmpty = true;
+    private transient int minPredictionSize = 0;
+    private transient int maxPredictionSize = Integer.MAX_VALUE;
+
 
 
     public Reranker(Regressor regressor, ClassProbEstimator classProbEstimator, int numCandidate,
@@ -38,12 +41,12 @@ public class Reranker implements MultiLabelClassifier, VectorCalibrator {
     }
 
 
-    public boolean allowEmpty() {
-        return allowEmpty;
+    public void setMinPredictionSize(int minPredictionSize) {
+        this.minPredictionSize = minPredictionSize;
     }
 
-    public void setAllowEmpty(boolean allowEmpty) {
-        this.allowEmpty = allowEmpty;
+    public void setMaxPredictionSize(int maxPredictionSize) {
+        this.maxPredictionSize = maxPredictionSize;
     }
 
     @Override
@@ -78,7 +81,7 @@ public class Reranker implements MultiLabelClassifier, VectorCalibrator {
         for (int i=0;i<numCandidate;i++){
             MultiLabel candidate = dynamicProgramming.nextHighestVector();
 
-            if (!allowEmpty&&candidate.getNumMatchedLabels()==0){
+            if (candidate.getNumMatchedLabels()<minPredictionSize||candidate.getNumMatchedLabels()>maxPredictionSize){
                 continue;
             }
 
@@ -91,13 +94,20 @@ public class Reranker implements MultiLabelClassifier, VectorCalibrator {
             double score = regressor.predict(feature);
             candidates.add(new Pair<>(candidate,score));
         }
-        //todo
-//        AccPredictor accPredictor = new AccPredictor(cbm);
-//        accPredictor.setComponentContributionThreshold(0.001);
-//        MultiLabel cbmPre = accPredictor.predict(vector);
-//        Vector feature = predictionVectorizer.feature(bmDistribution, cbmPre,marginals,Optional.of(positionMap));
-//        double score = regressor.predict(feature);
-//        candidates.add(new Pair<>(cbmPre,score));
+        // if all top candidates are invalid, at the most probable single label
+        if (candidates.isEmpty()){
+            int mostProbable = ArgMax.argMax(marginals);
+            MultiLabel candidate = new MultiLabel();
+            candidate.addLabel(mostProbable);
+            PredictionCandidate predictionCandidate = new PredictionCandidate();
+            predictionCandidate.x = vector;
+            predictionCandidate.labelProbs = marginals;
+            predictionCandidate.multiLabel = candidate;
+
+            Vector feature = predictionFeatureExtractor.extractFeatures(predictionCandidate);
+            double score = regressor.predict(feature);
+            candidates.add(new Pair<>(candidate,score));
+        }
 
 
         Comparator<Pair<MultiLabel,Double>> comparator = Comparator.comparing(pair->pair.getSecond());
@@ -108,7 +118,7 @@ public class Reranker implements MultiLabelClassifier, VectorCalibrator {
 //            System.out.println("number of ties = "+ties.size()+", "+ties);
 //        }
 
-        return candidates.stream().max(comparator).map(pair->pair.getFirst()).get();
+        return candidates.stream().max(comparator).map(Pair::getFirst).get();
     }
 
 

set predict.minSize and predict.maxSize