using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.ListOperations;
using U.StringOperations;

namespace DiscreteChoiceModel
{
    // p(k) = CT(k).EXP[theta.V(k)] / SUM{l, CT(l).EXP[theta.V(l)]}
    public class Logit : ChoiceModel
    {
        public static string abbr = "Logit";

        private double theta;
        private double[] correctionTerms;//path-size

        private bool useCorrectionTerms;
        
        // CONSTRUCTORS
        public Logit(double theta) : base(ChoiceModel.Type.Logit)
        {
            this.theta = theta;
            this.useCorrectionTerms = false;
        }
        public Logit(double theta, double[] correctionTerms) : base(ChoiceModel.Type.Logit)
        {
            this.theta = theta;
            this.correctionTerms = correctionTerms;
            this.useCorrectionTerms = true;
        }

        
        // OVERRIDE
        public override double[] calcProbabilities(double[] V)
        {
            double[] P = new double[V.Length];
            double denominator = 0.0;
            if (this.useCorrectionTerms)
            {
                for (int k = 0; k < V.Length; k++)
                {
                    P[k] = correctionTerms[k] * Math.Exp(this.theta * V[k]);
                    denominator += P[k];
                }
            }
            else
            {
                for (int k = 0; k < V.Length; k++)
                {
                    P[k] = Math.Exp(this.theta * V[k]);
                    denominator += P[k];
                }
            }
            for (int k = 0; k < V.Length; k++)
            {
                P[k] = P[k] / denominator;
            }
            return P;
        }


        // SETTERS
        public void setCorrectionTerms(double[] correctionTerms) { this.correctionTerms = correctionTerms; }
        public void setUseCorrectionTerms(bool useCorrectionTerms) { this.useCorrectionTerms = true; }

        // GETTERS
        public double[] getCorrectionTerms() { return this.correctionTerms; }
        public double getTheta() { return this.theta; }


        // TOSTRING
        public override string ToString()
        {
            List<string> args = new List<string>() { theta.ToString() };
            if (this.correctionTerms != null) { args.Add(Str.inParenthesis(Str.combine(correctionTerms, Str.Delimiter.Semicolon), Str.ParenthesisTypes.Square)); }
            return StrFunc.getFuncString(abbr, args, CMStr.PAR, CMStr.DEL);
        }

        // CLONE
        public override ChoiceModel Clone() { return new Logit(this.theta, UArray.clone(this.correctionTerms)); }

    }
}
