/*-
 * #%L
 * This file is part of "Apromore Community".
 *
 * Copyright (C) 2017 Alireza Ostovar.
 * %%
 * Copyright (C) 2018 - 2020 The University of Melbourne.
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */
package org.apromore.prodrift.main;

import com.aliasi.matrix.DenseVector;
import com.aliasi.matrix.Vector;

import com.aliasi.stats.AnnealingSchedule;
import com.aliasi.stats.LogisticRegression;
import com.aliasi.stats.RegressionPrior;

public class WalletProblem {

    public static void main(String[] args) {
        System.out.println("Computing Wallet Problem Logistic Regression");
        LogisticRegression regression
            = LogisticRegression.estimate(INPUTS,
                                          OUTPUTS,
                                          RegressionPrior.noninformative(),
                                          AnnealingSchedule.inverse(.05,100),
                                          null, // reporter with no feedback
                                          0.000000001, // min improve
                                          1, // min epochs
                                          5000); // max epochs
        
        Vector[] betas = regression.weightVectors();
        for (int outcome = 0; outcome < betas.length; ++outcome) {
            System.out.print("Outcome=" + outcome);
            for (int i = 0; i < betas[outcome].numDimensions(); ++i)
                System.out.printf(" %6.2f",betas[outcome].value(i));
            System.out.println();
        }

	System.out.println("\nInput Vector         Outcome Conditional Probabilities");
        for (Vector testCase : TEST_INPUTS) {
            double[] conditionalProbs = regression.classify(testCase);
            for (int i = 0; i < testCase.numDimensions(); ++i) {
                System.out.printf("%3.1f ",testCase.value(i));
            }
            for (int k = 0; k < conditionalProbs.length; ++k) {
                System.out.printf(" p(%d|input)=%4.2f ",k,conditionalProbs[k]);
            }
            System.out.println();
        }

    }


    // parallel to inputs
    public static final int[] OUTPUTS = new int[] {
        1,
        1,
        2,
        2,
        0,
        2,
        2,
        2,
        2,
        2,
        1,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        0,
        1,
        1,
        2,
        2,
        2,
        2,
        1,
        1,
        0,
        2,
        2,
        2,
        2,
        0,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        2,
        2,
        2,
        2,
        2,
        0,
        2,
        2,
        0,
        2,
        1,
        0,
        0,
        2,
        2,
        1,
        1,
        1,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        2,
        2,
        1,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        2,
        2,
        1,
        2,
        0,
        2,
        1,
        2,
        2,
        1,
        2,
        2,
        0,
        1,
        1,
        0,
        0,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        1,
        2,
        1,
        2,
        1,
        2,
        2,
        0,
        2,
        2,
        2,
        2,
        1,
        2,
        1,
        2,
        1,
        2,
        2,
        2,
        2,
        1,
        2,
        2,
        1,
        2,
        2,
        1,
        2,
        1,
        2,
        0,
        2,
        1,
        0,
        1,
        2,
        1,
        2,
        1,
        1,
        0,
        1,
        1,
        0,
        1,
        1,
        2,
        2,
        1,
        0,
        1,
        2,
        1,
        2,
        0,
        1,
        2,
        1,
        2,
        2,
        2,
        2,
        2,
        1, 
    };

    // parallel to outputs
    public static final Vector[] INPUTS = new Vector[] {
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 3, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 1, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 3, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 3, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 3, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 0, 1, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 3, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 0, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 2, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 0 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 0 }),
        new DenseVector(new double[] { 1, 0, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 2, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 3, 1 }),
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 1, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 1, 0, 1, 1 }),
    };

    public static final Vector[] TEST_INPUTS = new Vector[] {
        new DenseVector(new double[] { 1, 0, 0, 1, 1 }),
        new DenseVector(new double[] { 1, 0, 1, 0, 0 }),        
        new DenseVector(new double[] { 1, 0, 1, 3, 1 }),        
    };

}