public class Consts {

    // GENERALS
	public static final String SPACE = " ";
    public static final String TAB = "\t";
    public static final String COMMA_NOTE = ",";
	public static final String CLASSIFICATION_SPLITTER = "-";
	public static final String COLON_SPLITTER = ":";
    public static final String PARAMS_SPLITTER = ";";
	public static final String NEW_LINE = "line.separator";
    public static final int ERROR_NUMBER = -1;

    // DUMMY
    public static final int MIN_GAP_START_DUMMY = 3;
    public static final int MIN_GAP_END_DUMMY = 3;

    // VOWEL DURATION
    public static final int MIN_VOWEL = 9;  //min training set: 45 frames
	public static final int MAX_VOWEL = 92; //max training set: 459 frames
    public static final int MIN_GAP_START = 10;
    public static final int MIN_GAP_END = 10;

    public static final double MEAN_VOWEL_LENGTH = 41.787; //pre calculated from the training set
    public static final double STD_VOWEL_LENGTH = 12.918; //pre calculated from the training set
    public static final double MAX_VOWEL_LENGTH = 38; //pre calculated from the training set

    // MODELS NUMBER OF PARAMETERS
    public static final int PA_PARAMS_SIZE = 1; //The number params 4 PA
    public static final int SVM_PARAMS_SIZE = 2; //The number params 4 SVM
    public static final int DL_PARAMS_SIZE = 2; //The number params 4 Direct Loss
    public static final int CRF_PARAMS_SIZE = 2; //The number params 4 CRF
    public static final int RL_PARAMS_SIZE = 2; //The number params 4 Ramp Loss
    public static final int PL_PARAMS_SIZE = 6; //The number params 4 Probit Loss
    public static final int SP_PARAMS_SIZE = 0; //The number params 0 Perceptron
    public static final int ORBIT_PARAMS_SIZE = 2; //The number params 4 orbit
    public static final int MULTICLASS_REGECT_SIZE = 4; //The number params 4 multiclass regect

    // KERNEL DEFAULT PARAMETERS
    public static double SIGMA = 1;

    //OCR
    public static final String END_NOTE = "$";
} public interface Reader {
    ArrayList<ArrayList<String>> readFile(String path, String spliter);
    InstancesContainer readData(String path, String dataSpliter, String valueSpliter);
} public class InstancesContainer {

    ArrayList<Example> instances;
    ArrayList<ArrayList<String>> paths;
    int size;

    //C'tor
    public InstancesContainer() {
        instances = new ArrayList<Example>();
        paths = new ArrayList<ArrayList<String>>();
        size = 0;
    }

    //get the requested example
    public Example getInstance(int index)
    {
        try{
            return instances.get(index);
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    //======Setters and getters=====//
    public ArrayList<Example> getInstances() {
        return instances;
    }

    public void setInstances(ArrayList<Example> instances) {
        this.instances = instances;
        this.size = instances.size();
    }

    public ArrayList<ArrayList<String>> getPaths() {
        return paths;
    }

    public void setPaths(ArrayList<ArrayList<String>> paths) {
        this.paths = paths;
        this.size = paths.size();
    }


    public int getSize() {
        if(this.size != 0)
            return this.size;
        this.size = (instances.size() != 0) ? instances.size() : paths.size();
        return this.size;
    }
} public class Logger {

    private static final String directory = "log";
    private static final String log_file = "files.log";

    /**
     * Write the message into the standard output
     * @param message - the message to be written
     */
    public static void info(String message){
        System.out.print(System.getProperty(Consts.NEW_LINE) + message);
    }

    /**
     * Write the message into the standard output without new line at the end
     * @param message - the message to be written
     */
    public static void info_no_new_line(String message){
        System.out.print(message);
    }

    /**
     * Write the message into the standard output with the data and time attached
     * @param message - the message to be written
     */
    public static void infoTime(String message){
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        //get current date time with Date()
        Date date = new Date();
        if(message.isEmpty() || message.equals(""))
            message = "None,";
        System.out.print(System.getProperty(Consts.NEW_LINE) + message + " " + dateFormat.format(date));
    }

    /**
     * Writes only the data and time to the standard output
     */
    public static void time(){
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        //get current date time with Date()
        Date date = new Date();
        System.out.print(System.getProperty(Consts.NEW_LINE)  + dateFormat.format(date));
    }

    /**
     * Write the message into the standard output with the data and time attached
     * @param msg - the message to be written
     * @param example - a running id
     */
    public static void timeExampleStandard(String msg, int example){
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        //get current date time with Date()
        Date date = new Date();
        System.out.print(System.getProperty(Consts.NEW_LINE) + msg+example+", "+dateFormat.format(date));
    }

    /**
     * Write the message into the standard output as a progress bar
     * @param msg - the message to be written
     */
    public static void progressMessage(String msg){
        System.out.print("\r" + msg + " ");
    }

    /**
     * Write the message into the standard error
     * @param message - the message to be written
     */
    public static void error(String message){
        System.err.println("Error: "+message);
    }



    /**
     * Write the message into the files.log in the lod directory(if doesn't exists the program creates the dir)
     * @param message - tha message to ve written
     * @throws IOException
     */
    public static void log2File(String message) throws IOException
    {
        // create the log directory if does noe exists
        File dir = new File(directory);
        if(!dir.exists())
            dir.mkdir();

        // Create file stream
        File file = new File(directory+"/"+log_file);
        FileWriter fstream = new FileWriter(file,true);
        BufferedWriter out = new BufferedWriter(fstream);
        //writes the message
        out.write(message);
        out.write(System.getProperty(Consts.NEW_LINE));
        //close all the file descriptors
        out.close();
        fstream.close();
    }

    /**
     * clean the log directory
     */
    public static void clean(){
        File dir = new File(directory);
        if(dir.exists() && dir.isDirectory()) {
            String[]entries = dir.list();
            for(String s: entries){
                File currentFile = new File(dir.getPath(),s);
                currentFile.delete();
            }
            dir.delete();
        }

        dir.mkdir();
    }
} public class PredictedLabels extends TreeMap<String, Double>{

    //default c'tor
    public PredictedLabels(){
    }

    public PredictedLabels(MapValueComparatorAscending vc){
        super(vc);
    }

    public PredictedLabels(MapValueComparatorDescending vc){
        super(vc);
    }

    public PredictedLabels(MapKeyComparatorAscending vc){
        super(vc);
    }
} public class Vector extends HashMap<Integer, Double> implements Serializable{

    private static final long serialVersionUID = 1L;
    private int maxIndex;
    public Vector(){this.maxIndex = -1;}
    public Vector(Vector v){
        super(v);
    }

    @Override
    public Double put(Integer key, Double value){
        super.put(key, value);
        if(maxIndex < key) maxIndex = key;
        return value;
    }

    // getter
    public int getMaxIndex() {
        return maxIndex;
    }
    public void resetMaxIndex(){
        this.maxIndex = -1;
    }
} public class FeatureFunctionsDummy implements IFeatureFunctions {

    int sizeOfVector = 6;

	@Override
	//return null on error
	public Example convert(Example vector, String label, IKernel kernel) {

        try{
            Example newVector = Factory.getExample(0);
            newVector.sizeOfVector = sizeOfVector;

            String labelValues[] = label.split(Consts.CLASSIFICATION_SPLITTER);
            int i = Integer.parseInt(labelValues[0]);
            int j = Integer.parseInt(labelValues[1]);

            //compute the difference/gradients near the start and end points
            double diff_1_Start = Math.abs(vector.getFeatures().get(i)-vector.getFeatures().get(i-1));
            double diff_1_End = Math.abs(vector.getFeatures().get(j)-vector.getFeatures().get(j+1));

            //compute the difference/gradients near the start and end points
            double diff_2_Start = Math.abs(vector.getFeatures().get(i)-vector.getFeatures().get(i-2));
            double diff_2_End = Math.abs(vector.getFeatures().get(j)-vector.getFeatures().get(j+2));

            //compute the avg of the signal from start to end
            double avg = 0;
            for(int k=i ; k<j ; k++)
                avg+=vector.getFeatures().get(k);

            if(j-i <= 0){
                System.err.println("Convert single vector: "+ ErrorConstants.GENERAL_ERROR+ ErrorConstants.ZERO_DIVIDING);
                return null;
            }
            avg /= (double)(j-i);

            //compute the avg MIN_GAP_END_DUMMY after end
            double gapEnd = 0;
            for(int k=j ; k<j+Consts.MIN_GAP_END_DUMMY ; k++)
                gapEnd+=vector.getFeatures().get(k);

            gapEnd/=(double)Consts.MIN_GAP_END_DUMMY;

            //compute the avg MIN_GAP_START_DUMMY before start
            double gapStart = 0;
            for(int k=i-Consts.MIN_GAP_START_DUMMY+1 ; k<=i ; k++)
                gapStart+=vector.getFeatures().get(k);
            gapStart/=(double)Consts.MIN_GAP_START_DUMMY;

            //adding the feature functions
            Vector tmpVector = new Vector();
            tmpVector.put(0, diff_1_Start);
            tmpVector.put(1, diff_1_End);
            tmpVector.put(2, diff_2_Start);
            tmpVector.put(3, diff_2_End);
            tmpVector.put(4, avg-gapStart);
            tmpVector.put(5,avg-gapEnd);

            if(kernel !=null)
                tmpVector = kernel.convertVector(tmpVector, sizeOfVector);

            newVector.setFeatures(tmpVector);

            return newVector;

        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
	}

    @Override
    public int getSizeOfVector() {
        return this.sizeOfVector;
    }
} public class StructEDModel implements Serializable{

    // data members
    private Classifier classifier;
    private Vector W;
    private double cumulative_loss = 0;
    private boolean isShuffle;

    // C'tor
    public StructEDModel(Vector init_weights, IUpdateRule updateRule, ITaskLoss taskLoss, IInference inference,
                         IKernel kernel, IFeatureFunctions phi, ArrayList<Double> args){
        classifier = new Classifier();
        classifier.classifierData = new ClassifierData();
        updateRule.init(args);
        classifier.classifierData.updateRule = updateRule;
        classifier.classifierData.taskLoss = taskLoss;
        classifier.classifierData.inference = inference;
        classifier.classifierData.kernel = kernel;
        classifier.classifierData.phi = phi;
        W = init_weights;
        this.isShuffle = true;
    }
    // override constructor to support enable/disable shuffling
    public StructEDModel(Vector init_weights, IUpdateRule updateRule, ITaskLoss taskLoss, IInference inference,
                         IKernel kernel, IFeatureFunctions phi, ArrayList<Double> args, boolean isShuffle){
        classifier = new Classifier();
        classifier.classifierData = new ClassifierData();
        updateRule.init(args);
        classifier.classifierData.updateRule = updateRule;
        classifier.classifierData.taskLoss = taskLoss;
        classifier.classifierData.inference = inference;
        classifier.classifierData.kernel = kernel;
        classifier.classifierData.phi = phi;
        W = init_weights;
        this.isShuffle = isShuffle;
    }

    /**
     * Train the model on the train instances
     * @param epoch - the number of epochs to run over the data
     * @param trainInstances - the training instances(train set)
     * @param task_loss_params - the task loss parameters, if there are no parameters set this to null
     * @param developInstances - the develop instances(dev set), set this to null if there is no validation set
     * @param isAvg - an indicator whether or not to average the weights
     * @throws Exception
     */
    public void train(InstancesContainer trainInstances, ArrayList<Double> task_loss_params, InstancesContainer developInstances, int epoch, int isAvg, boolean verbose) throws Exception {
        //#############################################################################//
        //================================TRAIN========================================//
        //#############################################################################//
        //===================================//
        //print the start time of the program//
        Logger.infoTime("Start Training:");
        Logger.time();
        Logger.info("");
        long startTime = System.currentTimeMillis();
        //===================================//

        //loop over the training set epoch time
        for(int size = 0 ; size<epoch ; size++)
        {
            //===================================//
            //print the start time of the program//
            Logger.info("");
            Logger.info("==================================");
            Logger.timeExampleStandard("Epoch: ", (size + 1));
            Logger.info("==================================");
            Logger.info("");
            //===================================//
            if(isShuffle)
                //preform random shuffle for the next epoch
                trainInstances = ModelHandler.randomShuffle(trainInstances);

            //train the algorithm
            if (classifier == null) throw new AssertionError();
            W = classifier.train(W, trainInstances, task_loss_params, developInstances, isAvg, verbose);
            if(W == null)
                return;
        }

        if(isAvg == 1)
            this.W = classifier.getAvgWeights();
        //===================================//
        //print the start time of the program//
        Logger.time();
        long endTime   = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        long seconds = TimeUnit.MILLISECONDS.toSeconds(totalTime);
        Logger.info("Running time in seconds: " + seconds);
        //===================================//
    }

    /**
     * predict based on the model and return the scores of the best matches
     * @param instances - the test set
     * @param task_loss_params - the parameters for the task loss function, set to null if there are no task loss parameters
     * @param numPredictions2Return - the number of examples to return in the scores
     * @return ArrayList<PredictedLabels> - return the predicted labels as array
     */
    public ArrayList<PredictedLabels> predict(InstancesContainer instances, ArrayList<Double> task_loss_params, int numPredictions2Return, boolean verbose){
        Logger.info("");
        Logger.infoTime("Start Predicting:");
        Logger.time();
        Logger.info("");
        cumulative_loss = 0;
        ArrayList<PredictedLabels> scores = new ArrayList<PredictedLabels>();
        for(int i=0 ; i<instances.getSize() ; i++) {
            Example x = instances.getInstance(i);
            if (x == null)
                continue;
            PredictedLabels score = classifier.test(W, x, numPredictions2Return);

            String y_hat = score.firstKey();
            String y = x.getLabel();
            cumulative_loss += classifier.classifierData.taskLoss.computeTaskLoss(y, y_hat, task_loss_params);
            scores.add(score);
            if(verbose)
                Logger.info("file = "+x.path+", Y = "+y+", Y_Hat = "+y_hat);
        }
        cumulative_loss /= (double) (instances.getSize());
        Logger.info("Cumulative task loss: " + (cumulative_loss));
        Logger.info("");
        return scores;
    }

    /**
     * Plotting the error graph for the validation set
     * @param save flag which indicates whether to write the image or not
     */
    public void plotValidationError(boolean save){
        if(classifier.validationCumulativeLoss != null && classifier.validationCumulativeLoss.size() != 0) {
            Graph graph = new Graph();
            graph.drawGraph(classifier.validationCumulativeLoss, save);
        }
    }

    /**
     * save the model, notice: we save only the weight vector, the rest of the configuration should be predefined
     * @param path - the path to save the model
     * @throws IOException
     */
    public void saveModel(String path) throws IOException {
        FileOutputStream fout = new FileOutputStream(path);
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(W);
        oos.close();
    }

    /**
     * load the model, notice: we load only the weight vector, the rest of the configuration should be predefined
     * @param path - the model's path
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void loadModel(String path) throws IOException, ClassNotFoundException {
        FileInputStream fin = new FileInputStream(path);
        ObjectInputStream ois = new ObjectInputStream(fin);
        W = (Vector) ois.readObject();
        ois.close();
    }

    // Setters and Getters
    public Vector getWeights(){
        return this.W;
    }
    public double getCumulative_loss() {return cumulative_loss;}

    public void setUpdateRule(IUpdateRule updateRule){
        this.classifier.classifierData.updateRule = updateRule;
    }
    public void setTaskLoss(ITaskLoss taskLoss){
        this.classifier.classifierData.taskLoss = taskLoss;
    }
    public void setKernel(IKernel kernel){
        this.classifier.classifierData.kernel = kernel;
    }
    public void setInference(IInference inference){
        this.classifier.classifierData.inference = inference;
    }
    public void setFeatureFunctions(IFeatureFunctions phi){ this.classifier.classifierData.phi = phi; }
    public void setReShuffle(boolean isShuffle) { this.isShuffle = isShuffle; }
} public class CRF implements IUpdateRule {

    //data members
    double eta;
    double lambda;

	@Override
	public void init(ArrayList<Double> args) {
		if(args.size() != Consts.CRF_PARAMS_SIZE){
            Logger.error(ErrorConstants.UPDATE_ARGUMENTS_ERROR);
            return;
        }
        //initialize the parameters
        this.eta = args.get(0);
        this.lambda = args.get(1);
	}

	/**
	 * Implementation of the update rule
	 * @param currentWeights - the current weights
	 * @param example - a single example
	 * @param classifierData - all the additional data that needed such as: loss function, inference, etc.
     * @return the new set of weights
     */
	@Override
	//the first cell of the arguments attribute would be the mue value
	//the second cell of the arguments attribute would be the lambda
	public Vector update(Vector currentWeights, Example example, ClassifierData classifierData) {

		try{
            double algorithmIteration = classifierData.iteration;

            double newEta = eta/Math.sqrt(algorithmIteration);

			double denominator = 0;

            //the parameter 1 at the end is used to get all the predicted labels and not only the max one
            //it can be anything but -1 = Consts.ERROR_NUMBER
            PredictedLabels predictMap = classifierData.inference.predictForTest(example,currentWeights,example.getLabel(),classifierData,1);
			int k = -10;
			double maxVal = predictMap.firstEntry().getValue();

			for(Map.Entry<String, Double> entry : predictMap.entrySet()) {
				// keep the computation numerically stable
				double z = entry.getValue() - maxVal;
				if (z >= k)
					denominator += Math.pow(Math.E, (z));
			}

            Vector probExpectation = new Vector();
			boolean isFirst = true;

			for(Map.Entry<String, Double> entry : predictMap.entrySet())
			{
				// keep the computation numerically stable
				double prob = (entry.getValue() - maxVal) < k ? 0 : Math.pow(Math.E,(entry.getValue() - maxVal));
				prob = prob/denominator;
				if(isFirst){
					isFirst = false;
					probExpectation = MathHelpers.mulScalarWithVectors(classifierData.phi.convert(example, entry.getKey(), classifierData.kernel).getFeatures(), prob);
				} else
					probExpectation = MathHelpers.add2Vectors(probExpectation, MathHelpers.mulScalarWithVectors(classifierData.phi.convert(example,entry.getKey(),classifierData.kernel).getFeatures(), prob));
			}

            Vector updateArg = MathHelpers.subtract2Vectors(classifierData.phi.convert(example,example.getLabel(),classifierData.kernel).getFeatures(), probExpectation);
			updateArg = MathHelpers.mulScalarWithVectors(updateArg, newEta);
            Vector result = MathHelpers.mulScalarWithVectors(currentWeights, 1-lambda*newEta);

			result = MathHelpers.add2Vectors(result, updateArg);

			return result;

		}catch (Exception e){
			e.printStackTrace();
			return null;
		}
	}
} public class PassiveAggressive implements IUpdateRule {
    
    //data members
    double cValue;

    @Override
    public void init(ArrayList<Double> args){
        if(args.size() != Consts.PA_PARAMS_SIZE){
            Logger.error(ErrorConstants.UPDATE_ARGUMENTS_ERROR);
            return;
        }
        //initialize the parameters
        this.cValue = args.get(0);
    }

	/**
	 * Implementation of the update rule
	 * @param currentWeights - the current weights
	 * @param example - a single example
	 * @param classifierData - all the additional data that needed such as: loss function, inference, etc.
	 * @return the new set of weights
	 */
    @Override
	//the first cell of the arguments attribute would be the C value
	public Vector update(Vector currentWeights, Example example, ClassifierData classifierData) {
		
		try{
			//get the prediction
			String prediction = classifierData.inference.predictForTrain(example, currentWeights, example.getLabel(), classifierData,1).firstKey();

            Example phiRealLabel = classifierData.phi.convert(example, example.getLabel(), classifierData.kernel);
            Example phiPrediction = classifierData.phi.convert(example, prediction, classifierData.kernel);
			
			//compute the phi difference
            Vector phiDifference = MathHelpers.subtract2Vectors(phiRealLabel.getFeatures(), phiPrediction.getFeatures());
			
			double taskLossValue = classifierData.taskLoss.computeTaskLoss(prediction, example.getLabel(), classifierData.arguments);
			double multipleVectors = MathHelpers.multipleVectors(currentWeights , phiDifference);
			double denominator = MathHelpers.multipleVectors(phiDifference, phiDifference);

			double tau = 0;
			if(denominator != 0){
				tau = (taskLossValue - multipleVectors)/denominator;
			}

			if(tau > cValue)
				tau = cValue;

			classifierData.verbose = String.format(", Tau = %.3f", tau);

            if(tau < 0) {
				Logger.error("Y: "+example.getLabel()+" ,Y_hat: "+prediction);
				Logger.error("Loss < 0!, prediction search can't get to the target label.");
			}

            Vector updateVector = MathHelpers.mulScalarWithVectors(phiDifference, tau);
            Vector result = MathHelpers.add2Vectors(currentWeights, updateVector);

			return result;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
} public class InferenceDummyData implements IInference {

    @Override
    // predict function
    // argmax(yS,yE) (W*Phi(Xi,yS,yE)) + Task Loss
    // this function assumes that the argument vector has already been converted to phi vector
    // return null on error
    public PredictedLabels predictForTrain(Example vector, Vector W, String realClass, ClassifierData classifierData, double epsilonArgMax)
    {
        try{
            PredictedLabels tree = new PredictedLabels();

            //validation
            if(vector.sizeOfVector<=0)
            {
                System.err.println(ErrorConstants.PHI_VECTOR_DATA);
                return null;
            }

            //loop over all the classifications of this specific example
            for(int i=Consts.MIN_GAP_START_DUMMY-1 ; i<vector.sizeOfVector-Consts.MIN_GAP_END_DUMMY ; i++)
            {
                for(int j=i+1 ; j<vector.sizeOfVector- Consts.MIN_GAP_END_DUMMY ; j++)
                {
                    Example phiData = classifierData.phi.convert(vector,(i+1)+ Consts.CLASSIFICATION_SPLITTER+(j+1),classifierData.kernel);
                    //multiple the vectors
                    double tmp = MathHelpers.multipleVectors(W, phiData.getFeatures());

                    if(epsilonArgMax != 0){
                        //add the task loss
                        tmp += epsilonArgMax*classifierData.taskLoss.computeTaskLoss((i+1)+ Consts.CLASSIFICATION_SPLITTER+(j+1), realClass, classifierData.arguments);
                    }

                    //get the max value for the max classification
                    tree.put((i+1)+ Consts.CLASSIFICATION_SPLITTER+(j+1),tmp);
                }
            }

            MapValueComparatorDescending vc = new MapValueComparatorDescending(tree);
            PredictedLabels result = new PredictedLabels(vc);
            result.putAll(tree);

            return result;

        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public PredictedLabels predictForTest(Example vector, Vector W, String realClass, ClassifierData classifierData, int returnAll) {
        return predictForTrain(vector, W, realClass, classifierData, 0);
    }
} public class TaskLossDummyData implements ITaskLoss {

	@Override
	//max{0,|ys-ye - y's-y'e|-epsilon}
	public double computeTaskLoss(String predictClass, String actualClass, List<Double> params) {
		try {
			double epsilon = params.get(0);
			String predictValues[] = predictClass.split(Consts.CLASSIFICATION_SPLITTER);
			String actualClassValues[] = actualClass.split(Consts.CLASSIFICATION_SPLITTER);

			//calculate difference of each classification
			double predictRes = Double.parseDouble(predictValues[0]) - Double.parseDouble(predictValues[1]);
			double actualRes = Double.parseDouble(actualClassValues[0]) - Double.parseDouble(actualClassValues[1]);

			//subtract the epsilon
			double absRes = Math.abs(predictRes - actualRes) - epsilon;

			//get the max from the absolute result minus epsilon and 0
			if (absRes > 0)
				return absRes;
			return 0;
		} catch (Exception e) {
			Logger.error("Problem with the loss function parameters.");
			return 0;
		}
	}
} public static Reader getReader(int type){
       switch(type){
           case 0:
	        return new StandardReader();
           case 1:
               return new RankReader();
           case 2:
               return new LazyReader();
           case 3:
               return new OcrReader();
           default:
               return new StandardReader();
       }
}
import com.structed.data.entities.PredictedLabels;
import com.structed.data.entities.Vector;
import com.structed.data.featurefunctions.FeatureFunctionsDummy;
import com.structed.models.StructEDModel;
import com.structed.models.algorithms.CRF;
import com.structed.models.algorithms.PassiveAggressive;
import com.structed.models.inference.InferenceDummyData;
import com.structed.models.loss.TaskLossDummyData;
import java.util.ArrayList;
import static com.structed.data.Factory.getReader;
import com.structed.constants.Consts;
import com.structed.dal.Reader;
import com.structed.data.InstancesContainer;
import com.structed.data.Logger;
/*
 * The MIT License (MIT)
 *
 * StructED - Machine Learning Package for Structured Prediction
 *
 * Copyright (c) 2015 Yossi Adi, E-Mail: yossiadidrum@gmail.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.structed.tutorials;




/**
 * Created by yossiadi on 6/29/15.
 * Models tutorial using dummy data
 */
public class DummyTutorial {

    public static void main(String[] args) throws Exception {
        // ============================ DUMMY DATA ============================ //
        Logger.info("Dummy data example.");
        int readerType = 0;
        int epochNum = 3;
        int isAvg = 1;
        int numExamples2Display = 3;
        String trainPath = "tutorials-code/dummy/data/train.txt";
        String testPath = "tutorials-code/dummy/data/test.txt";

        // load the data
        Reader reader = getReader(readerType);
        InstancesContainer dummyTrainInstances = reader.readData(trainPath, Consts.SPACE, Consts.COLON_SPLITTER);
        InstancesContainer dummyTestInstances = reader.readData(testPath, Consts.SPACE, Consts.COLON_SPLITTER);
        if ( dummyTrainInstances.getSize() == 0 ) return;

        // ======= PASSIVE AGGRESSIVE ====== //
        Vector W = new Vector() {{put(0, 0.0);}}; // init the first weight vector
        ArrayList<Double> arguments = new ArrayList<Double>(){{add(3.0);}}; // model parameters
        ArrayList<Double> task_loss_params = new ArrayList<Double>(){{add(1.0);}}; // task loss parameters

        StructEDModel dummy_model = new StructEDModel(W, new PassiveAggressive(), new TaskLossDummyData(),