package edu.neu.ccs.pyramid.experiment;

import edu.neu.ccs.pyramid.classification.logistic_regression.LogisticRegression;
import edu.neu.ccs.pyramid.classification.logistic_regression.LogisticRegressionInspector;
import edu.neu.ccs.pyramid.configuration.Config;
import edu.neu.ccs.pyramid.dataset.*;
import edu.neu.ccs.pyramid.eval.Accuracy;
import edu.neu.ccs.pyramid.eval.Overlap;
import edu.neu.ccs.pyramid.eval.PerClassMeasures;
import edu.neu.ccs.pyramid.feature.FeatureUtility;
import edu.neu.ccs.pyramid.multilabel_classification.multi_label_logistic_regression.MLLogisticLoss;
import edu.neu.ccs.pyramid.multilabel_classification.multi_label_logistic_regression.MLLogisticRegression;
import edu.neu.ccs.pyramid.multilabel_classification.multi_label_logistic_regression.MLLogisticRegressionInspector;
import edu.neu.ccs.pyramid.multilabel_classification.multi_label_logistic_regression.MLLogisticTrainer;
import edu.neu.ccs.pyramid.optimization.LBFGS;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.mahout.math.Vector;

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

/**
 * multi-label logistic regression
 * Created by chengli on 12/23/14.
 */
public class Exp41 {
    public static void main(String[] args) throws Exception{
        if (args.length !=1){
            throw new IllegalArgumentException("please specify the config file");
        }

        Config config = new Config(args[0]);
        System.out.println(config);

        if (config.getBoolean("train")){
            train(config);
        }

        if (config.getBoolean("test")){
            test(config);
        }

        if (config.getBoolean("verify")){
            verify(config);
        }



    }

    static MultiLabelClfDataSet loadTrainData(Config config) throws Exception{
        String trainFile = new File(config.getString("input.folder"),
                config.getString("input.trainData")).getAbsolutePath();
        MultiLabelClfDataSet dataSet;
        dataSet= TRECFormat.loadMultiLabelClfDataSet(new File(trainFile), DataSetType.ML_CLF_SPARSE,
                    true);
        return dataSet;
    }

    static MultiLabelClfDataSet loadTestData(Config config) throws Exception{
        String trainFile = new File(config.getString("input.folder"),
                config.getString("input.testData")).getAbsolutePath();
        MultiLabelClfDataSet dataSet;
        dataSet= TRECFormat.loadMultiLabelClfDataSet(new File(trainFile), DataSetType.ML_CLF_SPARSE,
                    true);

        return dataSet;
    }

    static void train(Config config) throws Exception{
        String archive = config.getString("archive.folder");
        String modelName = config.getString("archive.model");

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        MultiLabelClfDataSet dataSet = loadTrainData(config);
        MultiLabelClfDataSet testSet = loadTestData(config);
        System.out.println("training data set loaded");
        System.out.println(dataSet.getMetaInfo());
        List<MultiLabel> assignments = DataSetUtil.gatherLabels(dataSet).stream()
                .collect(Collectors.toList());


        MLLogisticRegression mlLogisticRegression = new MLLogisticRegression(dataSet.getNumClasses(),dataSet.getNumFeatures(),
                assignments);
        for (int j=0;j<dataSet.getNumFeatures();j++){
            mlLogisticRegression.setFeatureName(j,dataSet.getFeatureSetting(j).getFeatureName());
        }

        mlLogisticRegression.setFeatureExtraction(false);
        MLLogisticLoss function = new MLLogisticLoss(mlLogisticRegression,dataSet,config.getDouble("train.gaussianPriorVariance"));
        LBFGS lbfgs = new LBFGS(function);
        lbfgs.setEpsilon(config.getDouble("train.epsilon"));
        lbfgs.setHistory(5);
        LinkedList<Double> valueQueue = new LinkedList<>();
        valueQueue.add(function.getValue(function.getParameters()));
        lbfgs.iterate();
        valueQueue.add(function.getValue(function.getParameters()));
        int iteration=0;
        while(true){
            System.out.println("iteration ="+iteration);
            System.out.println("objective = "+valueQueue.getLast());
            System.out.println("training accuracy = "+Accuracy.accuracy(mlLogisticRegression,dataSet));
            System.out.println("test accuracy = "+Accuracy.accuracy(mlLogisticRegression,testSet));
            if (Math.abs(valueQueue.getFirst()-valueQueue.getLast())<config.getDouble("train.epsilon")){
                break;
            }
            lbfgs.iterate();
            valueQueue.remove();
            valueQueue.add(function.getValue(function.getParameters()));
            iteration += 1;
        }
        
//        MLLogisticRegression mlLogisticRegression = trainer.train(dataSet,assignments);
        File serializedModel =  new File(archive,modelName);
        mlLogisticRegression.serialize(serializedModel);
        System.out.println("time spent = " + stopWatch);
        System.out.println("accuracy on training set = " +Accuracy.accuracy(mlLogisticRegression,dataSet));
        System.out.println("overlap on training set = "+ Overlap.overlap(mlLogisticRegression,dataSet));
    }

    static void test(Config config) throws Exception{
        String archive = config.getString("archive.folder");
        String modelName = config.getString("archive.model");

        MLLogisticRegression mlLogisticRegression = MLLogisticRegression.deserialize(new File(archive,modelName));
        System.out.println("test data set loaded");
        MultiLabelClfDataSet dataSet = loadTestData(config);
        System.out.println(dataSet.getMetaInfo());
        System.out.println("accuracy on test set = "+Accuracy.accuracy(mlLogisticRegression,dataSet));
        System.out.println("overlap on test set = "+ Overlap.overlap(mlLogisticRegression,dataSet));

    }

    private static void verify(Config config) throws Exception{
        String input = config.getString("input.folder");
        MultiLabelClfDataSet dataSet = TRECFormat.loadMultiLabelClfDataSet(new File(input,"train.trec"),
                DataSetType.ML_CLF_SPARSE, true);
        LabelTranslator labelTranslator = dataSet.getSetting().getLabelTranslator();
        File modelFile = new File(config.getString("archive.folder"),config.getString("archive.model"));
        MLLogisticRegression mlLogisticRegression = MLLogisticRegression.deserialize(modelFile);


        int limit = config.getInt("verify.topFeature.limit");
        for (int k=0;k<mlLogisticRegression.getNumClasses();k++){
            System.out.println("top feature for class "+k+"("+labelTranslator.toExtLabel(k)+")");
            System.out.println(MLLogisticRegressionInspector.topFeatures(mlLogisticRegression, k)
                    .stream().limit(limit).map(FeatureUtility::getName).collect(Collectors.toList()));
        }
    }


}

@@ -2872,32 +2872,88 @@
 inData(config);%0A
+        System.out.println(%22training data set loaded%22);%0A
         MultiLab
@@ -3018,39 +3018,35 @@
 m.out.println(%22t
-raining
+est
  data set loaded
@@ -3041,32 +3041,33 @@
 a set loaded%22);%0A
+%0A
         System.o
@@ -3996,32 +3996,57 @@
 Parameters()));%0A
+        int iteration=0;%0A
         lbfgs.it
@@ -4123,36 +4123,32 @@
 rs()));%0A        
-int 
 iteration=0;%0A   
@@ -4132,34 +4132,35 @@
        iteration
-=0
++=1
 ;%0A        while(

change output