/// <summary>
 /// Repositions the stream at the beginning and the previously seen object
 /// sequence will be repeated exactly. This method can be used to re-read the
 /// stream if multiple passes over the objects are required.
 /// </summary>
 public void Reset()
 {
     sequenceStream.Reset();
 }
        public AbstractModel TrainModel(int trainIterations, ISequenceStream trainStream, int cutoff,
            bool trainUseAverage) {
            iterations = trainIterations;
            useAverage = trainUseAverage;
            sequenceStream = trainStream;

            info.Append("Trained using Perceptron Sequence algorithm.\n\n");

            var di = new OnePassDataIndexer(new SequenceStreamEventStream(trainStream), cutoff, false);

            trainStream.Reset();

            numSequences = 0;

            while (trainStream.Read() != null) {
                numSequences++;
            }

            outcomeList = di.GetOutcomeList();
            predLabels = di.GetPredLabels();

            pMap = new IndexHashTable<string>(predLabels, 0.7d);

            // Incorporation indexed data for training...


            numEvents = di.GetNumEvents();

            outcomeLabels = di.GetOutcomeLabels();
            oMap = new Dictionary<string, int>();
            for (var i = 0; i < outcomeLabels.Length; i++) {
                oMap.Add(outcomeLabels[i], i);
            }

            outcomeList = di.GetOutcomeList();
            numPreds = predLabels.Length;
            numOutcomes = outcomeLabels.Length;

            if (trainUseAverage) {
                updates = new int[numPreds][][];
                for (var i = 0; i < numPreds; i++) {
                    updates[i] = new int[numOutcomes][];
                    for (var j = 0; j < numOutcomes; j++) {
                        updates[i][j] = new int[3];
                    }
                }
            }

            // done.
            Display("done.\n");

            info.Append("Number of Event Tokens: {0}\n" +
                        "    Number of Outcomes: {1}\n" +
                        "  Number of Predicates: {2}\n", numEvents, numOutcomes, numPreds);

            Display("\tNumber of Event Tokens: " + numEvents);
            Display("\t    Number of Outcomes: " + numOutcomes);
            Display("\t  Number of Predicates: " + numPreds);

            param = new MutableContext[numPreds];
            if (trainUseAverage)
                averageParams = new MutableContext[numPreds];

            allOutcomesPattern = new int[numOutcomes];
            for (var i = 0; i < numOutcomes; i++) {
                allOutcomesPattern[i] = i;
            }

            for (var pi = 0; pi < numPreds; pi++) {
                param[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]);
                if (trainUseAverage)
                    averageParams[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]);

                for (var aoi = 0; aoi < numOutcomes; aoi++) {
                    param[pi].SetParameter(aoi, 0.0d);
                    if (trainUseAverage)
                        averageParams[pi].SetParameter(aoi, 0.0d);
                }
            }

            Display("Computing model parameters...");
            FindParameters();
            Display("...done.");

            /*************** Create and return the model ******************/

            // ReSharper disable CoVariantArrayConversion
            if (trainUseAverage)
                return new PerceptronModel(averageParams, predLabels, outcomeLabels) {
                    info = info
                };

            return new PerceptronModel(param, predLabels, outcomeLabels) {               
                info = info
            };
            // ReSharper restore CoVariantArrayConversion
        }
        private void NextIteration(int iteration)
        {
            iteration--; //move to 0-based index

            var numCorrect    = 0;
            var oei           = 0;
            var si            = 0;
            var featureCounts = new Dictionary <int, Dictionary <string, float> >();

            for (var oi = 0; oi < numOutcomes; oi++)
            {
                featureCounts[oi] = new Dictionary <string, float>();
            }
            // ReSharper disable once CoVariantArrayConversion
            var model = new PerceptronModel(param, pMap, outcomeLabels);

            sequenceStream.Reset();

            Sequence sequence;

            while ((sequence = sequenceStream.Read()) != null)
            {
                var taggerEvents = sequenceStream.UpdateContext(sequence, model);
                var update       = false;
                for (var ei = 0; ei < sequence.Events.Length; ei++, oei++)
                {
                    if (!taggerEvents[ei].Outcome.Equals(sequence.Events[ei].Outcome))
                    {
                        update = true;
                        //break;
                    }
                    else
                    {
                        numCorrect++;
                    }
                }
                if (update)
                {
                    for (var oi = 0; oi < numOutcomes; oi++)
                    {
                        featureCounts[oi].Clear();
                    }

                    //training feature count computation
                    for (var ei = 0; ei < sequence.Events.Length; ei++, oei++)
                    {
                        var contextStrings = sequence.Events[ei].Context;
                        var values         = sequence.Events[ei].Values;
                        var oi             = oMap[sequence.Events[ei].Outcome];
                        for (var ci = 0; ci < contextStrings.Length; ci++)
                        {
                            float value = 1;
                            if (values != null)
                            {
                                value = values[ci];
                            }


                            if (featureCounts[oi].ContainsKey(contextStrings[ci]))
                            {
                                featureCounts[oi][contextStrings[ci]] += value;
                            }
                            else
                            {
                                featureCounts[oi][contextStrings[ci]] = value;
                            }
                        }
                    }

                    //evaluation feature count computation
                    foreach (var taggerEvent in taggerEvents)
                    {
                        var contextStrings = taggerEvent.Context;
                        var values         = taggerEvent.Values;
                        var oi             = oMap[taggerEvent.Outcome];
                        for (var ci = 0; ci < contextStrings.Length; ci++)
                        {
                            float value = 1;
                            if (values != null)
                            {
                                value = values[ci];
                            }

                            float c;
                            if (featureCounts[oi].ContainsKey(contextStrings[ci]))
                            {
                                c = featureCounts[oi][contextStrings[ci]] - value;
                            }
                            else
                            {
                                c = -1 * value;
                            }

                            if (c.Equals(0f))
                            {
                                featureCounts[oi].Remove(contextStrings[ci]);
                            }
                        }
                    }
                    for (var oi = 0; oi < numOutcomes; oi++)
                    {
                        foreach (var feature in featureCounts[oi].Keys)
                        {
                            var pi = pMap[feature];
                            if (pi != -1)
                            {
                                param[pi].UpdateParameter(oi, featureCounts[oi][feature]);
                                if (useAverage)
                                {
                                    if (updates[pi][oi][VALUE] != 0)
                                    {
                                        averageParams[pi].UpdateParameter(oi,
                                                                          updates[pi][oi][VALUE] *
                                                                          (numSequences * (iteration - updates[pi][oi][ITER]) +
                                                                           (si - updates[pi][oi][EVENT])));
                                    }
                                    updates[pi][oi][VALUE] = (int)param[pi].Parameters[oi];
                                    updates[pi][oi][ITER]  = iteration;
                                    updates[pi][oi][EVENT] = si;
                                }
                            }
                        }
                    }
                    // ReSharper disable once CoVariantArrayConversion
                    model = new PerceptronModel(param, pMap, outcomeLabels);
                }
                si++;
            }
            //finish average computation
            var totIterations = (double)iterations * si;

            if (useAverage && iteration == iterations - 1)
            {
                for (var pi = 0; pi < numPreds; pi++)
                {
                    var predParams = averageParams[pi].Parameters;
                    for (var oi = 0; oi < numOutcomes; oi++)
                    {
                        if (updates[pi][oi][VALUE] != 0)
                        {
                            predParams[oi] += updates[pi][oi][VALUE] *
                                              (numSequences * (iterations - updates[pi][oi][ITER]) -
                                               updates[pi][oi][EVENT]);
                        }

                        if (predParams[oi].Equals(0d))
                        {
                            continue;
                        }

                        predParams[oi] /= totIterations;
                        averageParams[pi].SetParameter(oi, predParams[oi]);
                    }
                }
            }

            trainingAccuracy = (double)numCorrect / numEvents;

            Display(string.Format("{0,-4} {1} of {2} - {3}",
                                  iteration,
                                  numCorrect,
                                  numEvents,
                                  trainingAccuracy));
        }
        public AbstractModel TrainModel(int trainIterations, ISequenceStream trainStream, int cutoff,
                                        bool trainUseAverage)
        {
            iterations     = trainIterations;
            useAverage     = trainUseAverage;
            sequenceStream = trainStream;

            info.Append("Trained using Perceptron Sequence algorithm.\n\n");

            var di = new OnePassDataIndexer(new SequenceStreamEventStream(trainStream), cutoff, false);

            trainStream.Reset();

            numSequences = 0;

            while (trainStream.Read() != null)
            {
                numSequences++;
            }

            outcomeList = di.GetOutcomeList();
            predLabels  = di.GetPredLabels();

            pMap = new IndexHashTable <string>(predLabels, 0.7d);

            // Incorporation indexed data for training...


            numEvents = di.GetNumEvents();

            outcomeLabels = di.GetOutcomeLabels();
            oMap          = new Dictionary <string, int>();
            for (var i = 0; i < outcomeLabels.Length; i++)
            {
                oMap.Add(outcomeLabels[i], i);
            }

            outcomeList = di.GetOutcomeList();
            numPreds    = predLabels.Length;
            numOutcomes = outcomeLabels.Length;

            if (trainUseAverage)
            {
                updates = new int[numPreds][][];
                for (var i = 0; i < numPreds; i++)
                {
                    updates[i] = new int[numOutcomes][];
                    for (var j = 0; j < numOutcomes; j++)
                    {
                        updates[i][j] = new int[3];
                    }
                }
            }

            // done.
            Display("done.\n");

            info.Append("Number of Event Tokens: {0}\n" +
                        "    Number of Outcomes: {1}\n" +
                        "  Number of Predicates: {2}\n", numEvents, numOutcomes, numPreds);

            Display("\tNumber of Event Tokens: " + numEvents);
            Display("\t    Number of Outcomes: " + numOutcomes);
            Display("\t  Number of Predicates: " + numPreds);

            param = new MutableContext[numPreds];
            if (trainUseAverage)
            {
                averageParams = new MutableContext[numPreds];
            }

            allOutcomesPattern = new int[numOutcomes];
            for (var i = 0; i < numOutcomes; i++)
            {
                allOutcomesPattern[i] = i;
            }

            for (var pi = 0; pi < numPreds; pi++)
            {
                param[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]);
                if (trainUseAverage)
                {
                    averageParams[pi] = new MutableContext(allOutcomesPattern, new double[numOutcomes]);
                }

                for (var aoi = 0; aoi < numOutcomes; aoi++)
                {
                    param[pi].SetParameter(aoi, 0.0d);
                    if (trainUseAverage)
                    {
                        averageParams[pi].SetParameter(aoi, 0.0d);
                    }
                }
            }

            Display("Computing model parameters...");
            FindParameters();
            Display("...done.");

            /*************** Create and return the model ******************/

            // ReSharper disable CoVariantArrayConversion
            if (trainUseAverage)
            {
                return new PerceptronModel(averageParams, predLabels, outcomeLabels)
                       {
                           info = info
                       }
            }
            ;

            return(new PerceptronModel(param, predLabels, outcomeLabels)
            {
                info = info
            });
            // ReSharper restore CoVariantArrayConversion
        }
 /// <summary>
 /// Repositions the stream at the beginning and the previously seen object
 /// sequence will be repeated exactly. This method can be used to re-read the
 /// stream if multiple passes over the objects are required.
 /// </summary>
 public void Reset()
 {
     enumerator = null;
     sequenceStream.Reset();
 }