/// <summary>
 /// <inheritDoc/>
 ///
 /// </summary>
 public virtual int Length()
 {
     if (models != null)
     {
         return(models[0].Length());
     }
     return(model1.Length());
 }
예제 #2
0
 public static int[] GetRandomSequence(ISequenceModel model)
 {
     int[] result = new int[model.Length()];
     for (int i = 0; i < result.Length; i++)
     {
         int[] classes = model.GetPossibleValues(i);
         result[i] = classes[random.NextInt(classes.Length)];
     }
     return(result);
 }
 public FactoredSequenceModel(ISequenceModel model1, ISequenceModel model2)
 {
     //if (model1.leftWindow() != model2.leftWindow()) throw new RuntimeException("Two models must have same window size");
     if (model1.GetPossibleValues(0).Length != model2.GetPossibleValues(0).Length)
     {
         throw new Exception("Two models must have the same number of classes");
     }
     if (model1.Length() != model2.Length())
     {
         throw new Exception("Two models must have the same sequence length");
     }
     this.model1 = model1;
     this.model2 = model2;
 }
예제 #4
0
 /// <summary>Samples each label in turn from left to right.</summary>
 /// <returns>an array containing the int tags of the best sequence</returns>
 public virtual int[] BestSequence(ISequenceModel ts)
 {
     // Also allocate space for rightWindow, just in case sequence model uses
     // it, even though this implementation doesn't. Probably it shouldn't,
     // or the left-to-right sampling is invalid, but our test classes do.
     int[] sample = new int[ts.Length() + ts.LeftWindow() + ts.RightWindow()];
     for (int pos = ts.LeftWindow(); pos < sample.Length - ts.RightWindow(); pos++)
     {
         double[] scores = ts.ScoresOf(sample, pos);
         for (int i = 0; i < scores.Length; i++)
         {
             scores[i] = Math.Exp(scores[i]);
         }
         ArrayMath.Normalize(scores);
         int l = ArrayMath.SampleFromDistribution(scores);
         sample[pos] = ts.GetPossibleValues(pos)[l];
     }
     return(sample);
 }
        public virtual int[] BestSequence(ISequenceModel ts, int size)
        {
            int length = ts.Length();
            int leftWindow = ts.LeftWindow();
            int rightWindow = ts.RightWindow();
            int padLength = length + leftWindow + rightWindow;
            int[][] tags = new int[padLength][];
            int[] tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos] = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }

            var newBeam = new Beam<TagSeq>(beamSize, ScoredComparator.ASCENDING_COMPARATOR);
            TagSeq initSeq = new TagSeq();
            newBeam.Add(initSeq);
            for (int pos = 0; pos < padLength; pos++)
            {
                var oldBeam = newBeam;
                if (pos < leftWindow + rightWindow && exhaustiveStart)
                {
                    newBeam = new Beam<TagSeq>(100000, ScoredComparator.ASCENDING_COMPARATOR);
                }
                else
                {
                    newBeam = new Beam<TagSeq>(beamSize, ScoredComparator.ASCENDING_COMPARATOR);
                }

                for (IEnumerator beamI = oldBeam.GetEnumerator(); beamI.MoveNext(); )
                {
                    Console.Out.Write(@"#");
                    Console.Out.Flush();
                    TagSeq tagSeq = (TagSeq)beamI.Current;
                    for (int nextTagNum = 0; nextTagNum < tagNum[pos]; nextTagNum++)
                    {
                        TagSeq nextSeq = tagSeq.Tclone();
                        if (pos >= leftWindow + rightWindow)
                        {
                            nextSeq.ExtendWith(tags[pos][nextTagNum], ts, size);
                        }
                        else
                        {
                            nextSeq.ExtendWith(tags[pos][nextTagNum]);
                        }

                        newBeam.Add(nextSeq);
                    }
                }

                Console.Out.WriteLine(@" done");
                if (recenter)
                {
                    double max = Double.NegativeInfinity;
                    for (IEnumerator beamI = newBeam.GetEnumerator(); beamI.MoveNext(); )
                    {
                        TagSeq tagSeq = (TagSeq)beamI.Current;
                        if (tagSeq.score > max)
                        {
                            max = tagSeq.score;
                        }
                    }

                    for (IEnumerator beamI = newBeam.GetEnumerator(); beamI.MoveNext(); )
                    {
                        TagSeq tagSeq = (TagSeq)beamI.Current;
                        tagSeq.score -= max;
                    }
                }
            }

            try
            {
                var enumerator = newBeam.GetEnumerator();
                if (enumerator.MoveNext())
                {
                    TagSeq bestSeq = enumerator.Current;
                    int[] seq = bestSeq.Tags();
                    return seq;
                }
                else
                    return null;
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(@"Beam empty -- no best sequence.");
                return null;
            }
        }
        /// <summary>
        /// Runs the Viterbi algorithm on the sequence model, and then proceeds to efficiently
        /// backwards decode the best k label sequence assignments.
        /// </summary>
        /// <remarks>
        /// Runs the Viterbi algorithm on the sequence model, and then proceeds to efficiently
        /// backwards decode the best k label sequence assignments.
        /// This sequence finder only works on SequenceModel's with rightWindow == 0.
        /// </remarks>
        /// <param name="ts">The SequenceModel to find the best k label sequence assignments of</param>
        /// <param name="k">The number of top-scoring assignments to find.</param>
        /// <returns>A Counter with k entries that map from a sequence assignment (int array) to a double score</returns>
        public virtual ICounter <int[]> KBestSequences(ISequenceModel ts, int k)
        {
            // Set up tag options
            int length      = ts.Length();
            int leftWindow  = ts.LeftWindow();
            int rightWindow = ts.RightWindow();

            if (rightWindow != 0)
            {
                throw new ArgumentException("KBestSequenceFinder only works with rightWindow == 0 not " + rightWindow);
            }
            int padLength = length + leftWindow + rightWindow;

            int[][] tags   = new int[padLength][];
            int[]   tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos]   = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }
            int[] tempTags = new int[padLength];
            // Set up product space sizes
            int[] productSizes = new int[padLength];
            int   curProduct   = 1;

            for (int i = 0; i < leftWindow; i++)
            {
                curProduct *= tagNum[i];
            }
            for (int pos_1 = leftWindow; pos_1 < padLength; pos_1++)
            {
                if (pos_1 > leftWindow + rightWindow)
                {
                    curProduct /= tagNum[pos_1 - leftWindow - rightWindow - 1];
                }
                // shift off
                curProduct *= tagNum[pos_1];
                // shift on
                productSizes[pos_1 - rightWindow] = curProduct;
            }
            double[][] windowScore = new double[padLength][];
            // Score all of each window's options
            for (int pos_2 = leftWindow; pos_2 < leftWindow + length; pos_2++)
            {
                windowScore[pos_2] = new double[productSizes[pos_2]];
                Arrays.Fill(tempTags, tags[0][0]);
                for (int product = 0; product < productSizes[pos_2]; product++)
                {
                    int p     = product;
                    int shift = 1;
                    for (int curPos = pos_2; curPos >= pos_2 - leftWindow; curPos--)
                    {
                        tempTags[curPos] = tags[curPos][p % tagNum[curPos]];
                        p /= tagNum[curPos];
                        if (curPos > pos_2)
                        {
                            shift *= tagNum[curPos];
                        }
                    }
                    if (tempTags[pos_2] == tags[pos_2][0])
                    {
                        // get all tags at once
                        double[] scores = ts.ScoresOf(tempTags, pos_2);
                        // fill in the relevant windowScores
                        for (int t = 0; t < tagNum[pos_2]; t++)
                        {
                            windowScore[pos_2][product + t * shift] = scores[t];
                        }
                    }
                }
            }
            // Set up score and backtrace arrays
            double[][][] score         = new double[padLength][][];
            int[][][][]  trace         = new int[padLength][][][];
            int[][]      numWaysToMake = new int[padLength][];
            for (int pos_3 = 0; pos_3 < padLength; pos_3++)
            {
                score[pos_3] = new double[productSizes[pos_3]][];
                trace[pos_3] = new int[productSizes[pos_3]][][];
                // the 2 is for backtrace, and which of the k best for that backtrace
                numWaysToMake[pos_3] = new int[productSizes[pos_3]];
                Arrays.Fill(numWaysToMake[pos_3], 1);
                for (int product = 0; product < productSizes[pos_3]; product++)
                {
                    if (pos_3 > leftWindow)
                    {
                        // loop over possible predecessor types
                        int sharedProduct = product / tagNum[pos_3];
                        int factor        = productSizes[pos_3] / tagNum[pos_3];
                        numWaysToMake[pos_3][product] = 0;
                        for (int newTagNum = 0; newTagNum < tagNum[pos_3 - leftWindow - 1] && numWaysToMake[pos_3][product] < k; newTagNum++)
                        {
                            int predProduct = newTagNum * factor + sharedProduct;
                            numWaysToMake[pos_3][product] += numWaysToMake[pos_3 - 1][predProduct];
                        }
                        if (numWaysToMake[pos_3][product] > k)
                        {
                            numWaysToMake[pos_3][product] = k;
                        }
                    }
                    score[pos_3][product] = new double[numWaysToMake[pos_3][product]];
                    Arrays.Fill(score[pos_3][product], double.NegativeInfinity);
                    trace[pos_3][product] = new int[numWaysToMake[pos_3][product]][];
                    Arrays.Fill(trace[pos_3][product], new int[] { -1, -1 });
                }
            }
            // Do forward Viterbi algorithm
            // this is the hottest loop, so cache loop control variables hoping for a little speed....
            // loop over the classification spot
            for (int pos_4 = leftWindow; pos_4 < posMax; pos_4++)
            {
                // loop over window product types
                for (int product = 0; product < productMax; product++)
                {
                    // check for initial spot
                    double[] scorePos = score[pos_4][product];
                    int[][]  tracePos = trace[pos_4][product];
                    if (pos_4 == leftWindow)
                    {
                        // no predecessor type
                        scorePos[0] = windowScore[pos_4][product];
                    }
                    else
                    {
                        // loop over possible predecessor types/k-best
                        int sharedProduct = product / tagNum[pos_4 + rightWindow];
                        int factor        = productSizes[pos_4] / tagNum[pos_4 + rightWindow];
                        for (int newTagNum = 0; newTagNum < maxTagNum; newTagNum++)
                        {
                            int      predProduct  = newTagNum * factor + sharedProduct;
                            double[] scorePosPrev = score[pos_4 - 1][predProduct];
                            for (int k1 = 0; k1 < scorePosPrev.Length; k1++)
                            {
                                double predScore = scorePosPrev[k1] + windowScore[pos_4][product];
                                if (predScore > scorePos[0])
                                {
                                    // new value higher then lowest value we should keep
                                    int k2 = Arrays.BinarySearch(scorePos, predScore);
                                    k2 = k2 < 0 ? -k2 - 2 : k2 - 1;
                                    // open a spot at k2 by shifting off the lowest value
                                    System.Array.Copy(scorePos, 1, scorePos, 0, k2);
                                    System.Array.Copy(tracePos, 1, tracePos, 0, k2);
                                    scorePos[k2] = predScore;
                                    tracePos[k2] = new int[] { predProduct, k1 };
                                }
                            }
                        }
                    }
                }
            }
            // Project the actual tag sequence
            int[]    whichDerivation     = new int[k];
            int[]    bestCurrentProducts = new int[k];
            double[] bestFinalScores     = new double[k];
            Arrays.Fill(bestFinalScores, double.NegativeInfinity);
            // just the last guy
            for (int product_1 = 0; product_1 < productSizes[padLength - 1]; product_1++)
            {
                double[] scorePos = score[padLength - 1][product_1];
                for (int k1 = scorePos.Length - 1; k1 >= 0 && scorePos[k1] > bestFinalScores[0]; k1--)
                {
                    int k2 = Arrays.BinarySearch(bestFinalScores, scorePos[k1]);
                    k2 = k2 < 0 ? -k2 - 2 : k2 - 1;
                    // open a spot at k2 by shifting off the lowest value
                    System.Array.Copy(bestFinalScores, 1, bestFinalScores, 0, k2);
                    System.Array.Copy(whichDerivation, 1, whichDerivation, 0, k2);
                    System.Array.Copy(bestCurrentProducts, 1, bestCurrentProducts, 0, k2);
                    bestCurrentProducts[k2] = product_1;
                    whichDerivation[k2]     = k1;
                    bestFinalScores[k2]     = scorePos[k1];
                }
            }
            ClassicCounter <int[]> kBestWithScores = new ClassicCounter <int[]>();

            for (int k1_1 = k - 1; k1_1 >= 0 && bestFinalScores[k1_1] > double.NegativeInfinity; k1_1--)
            {
                int lastProduct = bestCurrentProducts[k1_1];
                for (int last = padLength - 1; last >= length - 1 && last >= 0; last--)
                {
                    tempTags[last] = tags[last][lastProduct % tagNum[last]];
                    lastProduct   /= tagNum[last];
                }
                for (int pos_5 = leftWindow + length - 2; pos_5 >= leftWindow; pos_5--)
                {
                    int bestNextProduct = bestCurrentProducts[k1_1];
                    bestCurrentProducts[k1_1]    = trace[pos_5 + 1][bestNextProduct][whichDerivation[k1_1]][0];
                    whichDerivation[k1_1]        = trace[pos_5 + 1][bestNextProduct][whichDerivation[k1_1]][1];
                    tempTags[pos_5 - leftWindow] = tags[pos_5 - leftWindow][bestCurrentProducts[k1_1] / (productSizes[pos_5] / tagNum[pos_5 - leftWindow])];
                }
                kBestWithScores.SetCount(Arrays.CopyOf(tempTags, tempTags.Length), bestFinalScores[k1_1]);
            }
            return(kBestWithScores);
        }
        private static int[] BestSequenceOld(ISequenceModel ts)
        {
            int length = ts.Length();
            int leftWindow = ts.LeftWindow();
            int rightWindow = ts.RightWindow();
            int padLength = length + leftWindow + rightWindow;
            int[][] tags = new int[padLength][];
            int[] tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos] = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }

            int[] tempTags = new int[padLength];
            int[] productSizes = new int[padLength];
            int curProduct = 1;
            for (int i = 0; i < leftWindow + rightWindow; i++)
                curProduct *= tagNum[i];
            for (int pos = leftWindow + rightWindow; pos < padLength; pos++)
            {
                if (pos > leftWindow + rightWindow)
                    curProduct /= tagNum[pos - leftWindow - rightWindow - 1];
                curProduct *= tagNum[pos];
                productSizes[pos - rightWindow] = curProduct;
            }

            double[][] windowScore = new double[padLength][];
            for (int pos = leftWindow; pos < leftWindow + length; pos++)
            {
                windowScore[pos] = new double[productSizes[pos]];
                Arrays.Fill(tempTags, tags[0][0]);
                for (int product = 0; product < productSizes[pos]; product++)
                {
                    int p = product;
                    for (int curPos = pos + rightWindow; curPos >= pos - leftWindow; curPos--)
                    {
                        tempTags[curPos] = tags[curPos][p % tagNum[curPos]];
                        p /= tagNum[curPos];
                    }

                    windowScore[pos][product] = ts.ScoreOf(tempTags, pos);
                }
            }

            double[][] score = new double[padLength][];
            int[][] trace = new int[padLength][];
            for (int pos = 0; pos < padLength; pos++)
            {
                score[pos] = new double[productSizes[pos]];
                trace[pos] = new int[productSizes[pos]];
            }

            for (int pos = leftWindow; pos < length + leftWindow; pos++)
            {
                for (int product = 0; product < productSizes[pos]; product++)
                {
                    if (pos == leftWindow)
                    {
                        score[pos][product] = windowScore[pos][product];
                        trace[pos][product] = -1;
                    }
                    else
                    {
                        score[pos][product] = Double.NegativeInfinity;
                        trace[pos][product] = -1;
                        int sharedProduct = product / tagNum[pos + rightWindow];
                        int factor = productSizes[pos] / tagNum[pos + rightWindow];
                        for (int newTagNum = 0; newTagNum < tagNum[pos - leftWindow - 1]; newTagNum++)
                        {
                            int predProduct = newTagNum * factor + sharedProduct;
                            double predScore = score[pos - 1][predProduct] + windowScore[pos][product];
                            if (predScore > score[pos][product])
                            {
                                score[pos][product] = predScore;
                                trace[pos][product] = predProduct;
                            }
                        }
                    }
                }
            }

            double bestFinalScore = Double.NegativeInfinity;
            int bestCurrentProduct = -1;
            for (int product = 0; product < productSizes[leftWindow + length - 1]; product++)
            {
                if (score[leftWindow + length - 1][product] > bestFinalScore)
                {
                    bestCurrentProduct = product;
                    bestFinalScore = score[leftWindow + length - 1][product];
                }
            }

            int lastProduct = bestCurrentProduct;
            for (int last = padLength - 1; last >= length - 1; last--)
            {
                tempTags[last] = tags[last][lastProduct % tagNum[last]];
                lastProduct /= tagNum[last];
            }

            for (int pos = leftWindow + length - 2; pos >= leftWindow; pos--)
            {
                int bestNextProduct = bestCurrentProduct;
                bestCurrentProduct = trace[pos + 1][bestNextProduct];
                tempTags[pos - leftWindow] = tags[pos - leftWindow][bestCurrentProduct / (productSizes[pos] / tagNum[pos - leftWindow])];
            }

            return tempTags;
        }
        private static Pair<int[], Double> BestSequenceNew(ISequenceModel ts, double[][] linearConstraints)
        {
            int length = ts.Length();
            int leftWindow = ts.LeftWindow();
            int rightWindow = ts.RightWindow();
            int padLength = length + leftWindow + rightWindow;
            if (linearConstraints != null && linearConstraints.Length != padLength)
                throw new Exception(@"linearConstraints.length (" + linearConstraints.Length + @") does not match padLength (" + padLength + @") of SequenceModel" + @", length==" + length + @", leftW=" + leftWindow + @", rightW=" + rightWindow);
            int[][] tags = new int[padLength][];
            int[] tagNum = new int[padLength];
            if (DEBUG)
            {
                Console.Error.WriteLine(@"Doing bestSequence length " + length + @"; leftWin " + leftWindow + @"; rightWin " + rightWindow + @"; padLength " + padLength);
            }

            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos] = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
                if (DEBUG)
                {
                    Console.Error.WriteLine(@"There are " + tagNum[pos] + @" values at position " + pos + @": " + Arrays.ToString(tags[pos]));
                }
            }

            int[] tempTags = new int[padLength];
            int[] productSizes = new int[padLength];
            int curProduct = 1;
            for (int i = 0; i < leftWindow + rightWindow; i++)
            {
                curProduct *= tagNum[i];
            }

            for (int pos = leftWindow + rightWindow; pos < padLength; pos++)
            {
                if (pos > leftWindow + rightWindow)
                {
                    curProduct /= tagNum[pos - leftWindow - rightWindow - 1];
                }

                curProduct *= tagNum[pos];
                productSizes[pos - rightWindow] = curProduct;
            }

            double[][] windowScore = new double[padLength][];
            for (int pos = leftWindow; pos < leftWindow + length; pos++)
            {
                if (DEBUG)
                {
                    Console.Error.WriteLine(@"scoring word " + pos + @" / " + (leftWindow + length) + @", productSizes =  " + productSizes[pos] + @", tagNum = " + tagNum[pos] + @"...");
                }

                windowScore[pos] = new double[productSizes[pos]];
                Arrays.Fill(tempTags, tags[0][0]);
                if (DEBUG)
                {
                    Console.Error.WriteLine(@"windowScore[" + pos + @"] has size (productSizes[pos]) " + windowScore[pos].Length);
                }

                for (int product = 0; product < productSizes[pos]; product++)
                {
                    int p = product;
                    int shift = 1;
                    for (int curPos = pos + rightWindow; curPos >= pos - leftWindow; curPos--)
                    {
                        tempTags[curPos] = tags[curPos][p % tagNum[curPos]];
                        p /= tagNum[curPos];
                        if (curPos > pos)
                        {
                            shift *= tagNum[curPos];
                        }
                    }

                    if (tempTags[pos] == tags[pos][0])
                    {
                        double[] scores = ts.ScoresOf(tempTags, pos);
                        if (DEBUG)
                        {
                            Console.Error.WriteLine(@"Matched at array index [product] " + product + @"; tempTags[pos] == tags[pos][0] == " + tempTags[pos]);
                        }

                        if (DEBUG)
                        {
                            Console.Error.WriteLine(@"For pos " + pos + @" scores.length is " + scores.Length + @"; tagNum[pos] = " + tagNum[pos] + @"; windowScore[pos].length = " + windowScore[pos].Length);
                        }

                        if (DEBUG)
                        {
                            Console.Error.WriteLine(@"scores: " + Arrays.ToString(scores));
                        }

                        for (int t = 0; t < tagNum[pos]; t++)
                        {
                            if (DEBUG)
                            {
                                Console.Error.WriteLine(@"Setting value of windowScore[" + pos + @"][" + product + @"+" + t + @"*" + shift + @"] = " + scores[t]);
                            }

                            windowScore[pos][product + t * shift] = scores[t];
                        }
                    }
                }
            }

            double[][] score = new double[padLength][];
            int[][] trace = new int[padLength][];
            for (int pos = 0; pos < padLength; pos++)
            {
                score[pos] = new double[productSizes[pos]];
                trace[pos] = new int[productSizes[pos]];
            }

            for (int pos = leftWindow; pos < length + leftWindow; pos++)
            {
                for (int product = 0; product < productSizes[pos]; product++)
                {
                    if (pos == leftWindow)
                    {
                        score[pos][product] = windowScore[pos][product];
                        if (linearConstraints != null)
                        {
                            if (DEBUG && linearConstraints[pos][product % tagNum[pos]] != 0)
                                Console.Error.WriteLine(@"Applying linear constraints=" + linearConstraints[pos][product % tagNum[pos]] + @" to preScore=" + windowScore[pos][product] + @" at pos=" + pos + @" for tag=" + (product % tagNum[pos]));
                            score[pos][product] += linearConstraints[pos][product % tagNum[pos]];
                        }

                        trace[pos][product] = -1;
                    }
                    else
                    {
                        score[pos][product] = Double.NegativeInfinity;
                        trace[pos][product] = -1;
                        int sharedProduct = product / tagNum[pos + rightWindow];
                        int factor = productSizes[pos] / tagNum[pos + rightWindow];
                        for (int newTagNum = 0; newTagNum < tagNum[pos - leftWindow - 1]; newTagNum++)
                        {
                            int predProduct = newTagNum * factor + sharedProduct;
                            double predScore = score[pos - 1][predProduct] + windowScore[pos][product];
                            if (linearConstraints != null)
                            {
                                if (DEBUG && pos == 2 && linearConstraints[pos][product % tagNum[pos]] != 0)
                                {
                                    Console.Error.WriteLine(@"Applying linear constraints=" + linearConstraints[pos][product % tagNum[pos]] + @" to preScore=" + predScore + @" at pos=" + pos + @" for tag=" + (product % tagNum[pos]));
                                    Console.Error.WriteLine(@"predScore:" + predScore + @" = score[" + (pos - 1) + @"][" + predProduct + @"]:" + score[pos - 1][predProduct] + @" + windowScore[" + pos + @"][" + product + @"]:" + windowScore[pos][product]);
                                }

                                predScore += linearConstraints[pos][product % tagNum[pos]];
                            }

                            if (predScore > score[pos][product])
                            {
                                score[pos][product] = predScore;
                                trace[pos][product] = predProduct;
                            }
                        }
                    }
                }
            }

            double bestFinalScore = Double.NegativeInfinity;
            int bestCurrentProduct = -1;
            for (int product = 0; product < productSizes[leftWindow + length - 1]; product++)
            {
                if (score[leftWindow + length - 1][product] > bestFinalScore)
                {
                    bestCurrentProduct = product;
                    bestFinalScore = score[leftWindow + length - 1][product];
                }
            }

            int lastProduct = bestCurrentProduct;
            for (int last = padLength - 1; last >= length - 1 && last >= 0; last--)
            {
                tempTags[last] = tags[last][lastProduct % tagNum[last]];
                lastProduct /= tagNum[last];
            }

            for (int pos = leftWindow + length - 2; pos >= leftWindow; pos--)
            {
                int bestNextProduct = bestCurrentProduct;
                bestCurrentProduct = trace[pos + 1][bestNextProduct];
                tempTags[pos - leftWindow] = tags[pos - leftWindow][bestCurrentProduct / (productSizes[pos] / tagNum[pos - leftWindow])];
            }

            return new Pair<int[], Double>(tempTags, bestFinalScore);
        }
        public virtual int[] BestSequence(ISequenceModel ts, int size)
        {
            // Set up tag options
            int length      = ts.Length();
            int leftWindow  = ts.LeftWindow();
            int rightWindow = ts.RightWindow();
            int padLength   = length + leftWindow + rightWindow;

            int[][] tags   = new int[padLength][];
            int[]   tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos]   = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }
            Beam newBeam = new Beam(beamSize, ScoredComparator.AscendingComparator);

            BeamBestSequenceFinder.TagSeq initSeq = new BeamBestSequenceFinder.TagSeq();
            newBeam.Add(initSeq);
            for (int pos_1 = 0; pos_1 < padLength; pos_1++)
            {
                if (Thread.Interrupted())
                {
                    // Allow interrupting
                    throw new RuntimeInterruptedException();
                }
                //System.out.println("scoring word " + pos + " / " + (leftWindow + length) + ", tagNum = " + tagNum[pos] + "...");
                //System.out.flush();
                Beam oldBeam = newBeam;
                if (pos_1 < leftWindow + rightWindow && exhaustiveStart)
                {
                    newBeam = new Beam(100000, ScoredComparator.AscendingComparator);
                }
                else
                {
                    newBeam = new Beam(beamSize, ScoredComparator.AscendingComparator);
                }
                // each hypothesis gets extended and beamed
                foreach (object anOldBeam in oldBeam)
                {
                    if (Thread.Interrupted())
                    {
                        // Allow interrupting
                        throw new RuntimeInterruptedException();
                    }
                    // System.out.print("#"); System.out.flush();
                    BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)anOldBeam;
                    for (int nextTagNum = 0; nextTagNum < tagNum[pos_1]; nextTagNum++)
                    {
                        BeamBestSequenceFinder.TagSeq nextSeq = tagSeq.Tclone();
                        if (pos_1 >= leftWindow + rightWindow)
                        {
                            nextSeq.ExtendWith(tags[pos_1][nextTagNum], ts, size);
                        }
                        else
                        {
                            nextSeq.ExtendWith(tags[pos_1][nextTagNum]);
                        }
                        //System.out.println("Created: "+nextSeq.score()+" %% "+arrayToString(nextSeq.tags(), nextSeq.size()));
                        newBeam.Add(nextSeq);
                    }
                }
                //		System.out.println("Beam size: "+newBeam.size()+" of "+beamSize);
                //System.out.println("Best is: "+((Scored)newBeam.iterator().next()).score());
                // System.out.println(" done");
                if (recenter)
                {
                    double max = double.NegativeInfinity;
                    foreach (object aNewBeam1 in newBeam)
                    {
                        BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)aNewBeam1;
                        if (tagSeq.score > max)
                        {
                            max = tagSeq.score;
                        }
                    }
                    foreach (object aNewBeam in newBeam)
                    {
                        BeamBestSequenceFinder.TagSeq tagSeq = (BeamBestSequenceFinder.TagSeq)aNewBeam;
                        tagSeq.score -= max;
                    }
                }
            }
            try
            {
                BeamBestSequenceFinder.TagSeq bestSeq = (BeamBestSequenceFinder.TagSeq)newBeam.GetEnumerator().Current;
                int[] seq = bestSeq.Tags();
                return(seq);
            }
            catch (NoSuchElementException)
            {
                log.Info("Beam empty -- no best sequence.");
                return(null);
            }
        }
예제 #10
0
        public static DFSA <string, int> GetGraph(ISequenceModel ts, IIndex <string> classIndex)
        {
            DFSA <string, int> viterbiSearchGraph = new DFSA <string, int>(null);
            // Set up tag options
            int length      = ts.Length();
            int leftWindow  = ts.LeftWindow();
            int rightWindow = ts.RightWindow();

            System.Diagnostics.Debug.Assert((rightWindow == 0));
            int padLength = length + leftWindow + rightWindow;

            // NOTE: tags[i][j]  : i is index into pos, and j into product
            int[][] tags   = new int[padLength][];
            int[]   tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                tags[pos]   = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }
            // Set up Viterbi search graph:
            DFSAState <string, int>[][] graphStates = null;
            DFSAState <string, int>     startState  = null;
            DFSAState <string, int>     endState    = null;

            if (viterbiSearchGraph != null)
            {
                int stateId = -1;
                startState = new DFSAState <string, int>(++stateId, viterbiSearchGraph, 0.0);
                viterbiSearchGraph.SetInitialState(startState);
                graphStates = new DFSAState[length][];
                for (int pos_1 = 0; pos_1 < length; ++pos_1)
                {
                    //System.err.printf("%d states at pos %d\n",tags[pos].length,pos);
                    graphStates[pos_1] = new DFSAState[tags[pos_1].Length];
                    for (int product = 0; product < tags[pos_1].Length; ++product)
                    {
                        graphStates[pos_1][product] = new DFSAState <string, int>(++stateId, viterbiSearchGraph);
                    }
                }
                // Accepting state:
                endState = new DFSAState <string, int>(++stateId, viterbiSearchGraph, 0.0);
                endState.SetAccepting(true);
            }
            int[] tempTags = new int[padLength];
            // Set up product space sizes
            int[] productSizes = new int[padLength];
            int   curProduct   = 1;

            for (int i = 0; i < leftWindow; i++)
            {
                curProduct *= tagNum[i];
            }
            for (int pos_2 = leftWindow; pos_2 < padLength; pos_2++)
            {
                if (pos_2 > leftWindow + rightWindow)
                {
                    curProduct /= tagNum[pos_2 - leftWindow - rightWindow - 1];
                }
                // shift off
                curProduct *= tagNum[pos_2];
                // shift on
                productSizes[pos_2 - rightWindow] = curProduct;
            }
            double[][] windowScore = new double[padLength][];
            // Score all of each window's options
            for (int pos_3 = leftWindow; pos_3 < leftWindow + length; pos_3++)
            {
                windowScore[pos_3] = new double[productSizes[pos_3]];
                Arrays.Fill(tempTags, tags[0][0]);
                for (int product = 0; product < productSizes[pos_3]; product++)
                {
                    int p     = product;
                    int shift = 1;
                    for (int curPos = pos_3; curPos >= pos_3 - leftWindow; curPos--)
                    {
                        tempTags[curPos] = tags[curPos][p % tagNum[curPos]];
                        p /= tagNum[curPos];
                        if (curPos > pos_3)
                        {
                            shift *= tagNum[curPos];
                        }
                    }
                    if (tempTags[pos_3] == tags[pos_3][0])
                    {
                        // get all tags at once
                        double[] scores = ts.ScoresOf(tempTags, pos_3);
                        // fill in the relevant windowScores
                        for (int t = 0; t < tagNum[pos_3]; t++)
                        {
                            windowScore[pos_3][product + t * shift] = scores[t];
                        }
                    }
                }
            }
            // loop over the classification spot
            for (int pos_4 = leftWindow; pos_4 < length + leftWindow; pos_4++)
            {
                // loop over window product types
                for (int product = 0; product < productSizes[pos_4]; product++)
                {
                    if (pos_4 == leftWindow)
                    {
                        // all nodes in the first spot link to startState:
                        int curTag = tags[pos_4][product % tagNum[pos_4]];
                        //System.err.printf("pos=%d, product=%d, tag=%d score=%.3f\n",pos,product,curTag,windowScore[pos][product]);
                        DFSATransition <string, int> tr = new DFSATransition <string, int>(string.Empty, startState, graphStates[pos_4][product], classIndex.Get(curTag), string.Empty, -windowScore[pos_4][product]);
                        startState.AddTransition(tr);
                    }
                    else
                    {
                        int sharedProduct = product / tagNum[pos_4 + rightWindow];
                        int factor        = productSizes[pos_4] / tagNum[pos_4 + rightWindow];
                        for (int newTagNum = 0; newTagNum < tagNum[pos_4 - leftWindow - 1]; newTagNum++)
                        {
                            int predProduct = newTagNum * factor + sharedProduct;
                            int predTag     = tags[pos_4 - 1][predProduct % tagNum[pos_4 - 1]];
                            int curTag      = tags[pos_4][product % tagNum[pos_4]];
                            //log.info("pos: "+pos);
                            //log.info("product: "+product);
                            //System.err.printf("pos=%d-%d, product=%d-%d, tag=%d-%d score=%.3f\n",pos-1,pos,predProduct,product,predTag,curTag,
                            //  windowScore[pos][product]);
                            DFSAState <string, int>      sourceState = graphStates[pos_4 - leftWindow][predTag];
                            DFSAState <string, int>      destState   = (pos_4 - leftWindow + 1 == graphStates.Length) ? endState : graphStates[pos_4 - leftWindow + 1][curTag];
                            DFSATransition <string, int> tr          = new DFSATransition <string, int>(string.Empty, sourceState, destState, classIndex.Get(curTag), string.Empty, -windowScore[pos_4][product]);
                            graphStates[pos_4 - leftWindow][predTag].AddTransition(tr);
                        }
                    }
                }
            }
            return(viterbiSearchGraph);
        }
        private static Pair <int[], double> BestSequence(ISequenceModel ts, double[][] linearConstraints)
        {
            // Set up tag options
            int length      = ts.Length();
            int leftWindow  = ts.LeftWindow();
            int rightWindow = ts.RightWindow();
            int padLength   = length + leftWindow + rightWindow;

            if (linearConstraints != null && linearConstraints.Length != padLength)
            {
                throw new Exception("linearConstraints.length (" + linearConstraints.Length + ") does not match padLength (" + padLength + ") of SequenceModel" + ", length==" + length + ", leftW=" + leftWindow + ", rightW=" + rightWindow);
            }
            int[][] tags   = new int[padLength][];
            int[]   tagNum = new int[padLength];
            for (int pos = 0; pos < padLength; pos++)
            {
                if (Thread.Interrupted())
                {
                    // Allow interrupting
                    throw new RuntimeInterruptedException();
                }
                tags[pos]   = ts.GetPossibleValues(pos);
                tagNum[pos] = tags[pos].Length;
            }
            int[] tempTags = new int[padLength];
            // Set up product space sizes
            int[] productSizes = new int[padLength];
            int   curProduct   = 1;

            for (int i = 0; i < leftWindow + rightWindow; i++)
            {
                curProduct *= tagNum[i];
            }
            for (int pos_1 = leftWindow + rightWindow; pos_1 < padLength; pos_1++)
            {
                if (Thread.Interrupted())
                {
                    // Allow interrupting
                    throw new RuntimeInterruptedException();
                }
                if (pos_1 > leftWindow + rightWindow)
                {
                    curProduct /= tagNum[pos_1 - leftWindow - rightWindow - 1];
                }
                // shift off
                curProduct *= tagNum[pos_1];
                // shift on
                productSizes[pos_1 - rightWindow] = curProduct;
            }
            // Score all of each window's options
            double[][] windowScore = new double[padLength][];
            for (int pos_2 = leftWindow; pos_2 < leftWindow + length; pos_2++)
            {
                if (Thread.Interrupted())
                {
                    // Allow interrupting
                    throw new RuntimeInterruptedException();
                }
                windowScore[pos_2] = new double[productSizes[pos_2]];
                Arrays.Fill(tempTags, tags[0][0]);
                for (int product = 0; product < productSizes[pos_2]; product++)
                {
                    if (Thread.Interrupted())
                    {
                        // Allow interrupting
                        throw new RuntimeInterruptedException();
                    }
                    int p     = product;
                    int shift = 1;
                    for (int curPos = pos_2 + rightWindow; curPos >= pos_2 - leftWindow; curPos--)
                    {
                        tempTags[curPos] = tags[curPos][p % tagNum[curPos]];
                        p /= tagNum[curPos];
                        if (curPos > pos_2)
                        {
                            shift *= tagNum[curPos];
                        }
                    }
                    // Here now you get ts.scoresOf() for all classifications at a position at once, whereas the old code called ts.scoreOf() on each item.
                    // CDM May 2007: The way this is done gives incorrect results if there are repeated values in the values of ts.getPossibleValues(pos) -- in particular if the first value of the array is repeated later.  I tried replacing it with the modulo version, but that only worked for left-to-right, not bidirectional inference, but I still think that if you sorted things out, you should be able to do it with modulos and the result would be conceptually simpler and robust to repeated values.  But in the meantime, I fixed the POS tagger to not give repeated values (which was a bug in the tagger).
                    if (tempTags[pos_2] == tags[pos_2][0])
                    {
                        // get all tags at once
                        double[] scores = ts.ScoresOf(tempTags, pos_2);
                        // fill in the relevant windowScores
                        for (int t = 0; t < tagNum[pos_2]; t++)
                        {
                            windowScore[pos_2][product + t * shift] = scores[t];
                        }
                    }
                }
            }
            // Set up score and backtrace arrays
            double[][] score = new double[padLength][];
            int[][]    trace = new int[padLength][];
            for (int pos_3 = 0; pos_3 < padLength; pos_3++)
            {
                if (Thread.Interrupted())
                {
                    // Allow interrupting
                    throw new RuntimeInterruptedException();
                }
                score[pos_3] = new double[productSizes[pos_3]];
                trace[pos_3] = new int[productSizes[pos_3]];
            }
            // Do forward Viterbi algorithm
            // loop over the classification spot
            //log.info();
            for (int pos_4 = leftWindow; pos_4 < length + leftWindow; pos_4++)
            {
                //log.info(".");
                // loop over window product types
                for (int product = 0; product < productSizes[pos_4]; product++)
                {
                    if (Thread.Interrupted())
                    {
                        // Allow interrupting
                        throw new RuntimeInterruptedException();
                    }
                    // check for initial spot
                    if (pos_4 == leftWindow)
                    {
                        // no predecessor type
                        score[pos_4][product] = windowScore[pos_4][product];
                        if (linearConstraints != null)
                        {
                            score[pos_4][product] += linearConstraints[pos_4][product % tagNum[pos_4]];
                        }
                        trace[pos_4][product] = -1;
                    }
                    else
                    {
                        // loop over possible predecessor types
                        score[pos_4][product] = double.NegativeInfinity;
                        trace[pos_4][product] = -1;
                        int sharedProduct = product / tagNum[pos_4 + rightWindow];
                        int factor        = productSizes[pos_4] / tagNum[pos_4 + rightWindow];
                        for (int newTagNum = 0; newTagNum < tagNum[pos_4 - leftWindow - 1]; newTagNum++)
                        {
                            int    predProduct = newTagNum * factor + sharedProduct;
                            double predScore   = score[pos_4 - 1][predProduct] + windowScore[pos_4][product];
                            if (linearConstraints != null)
                            {
                                predScore += linearConstraints[pos_4][product % tagNum[pos_4]];
                            }
                            if (predScore > score[pos_4][product])
                            {
                                score[pos_4][product] = predScore;
                                trace[pos_4][product] = predProduct;
                            }
                        }
                    }
                }
            }
            // Project the actual tag sequence
            double bestFinalScore     = double.NegativeInfinity;
            int    bestCurrentProduct = -1;

            for (int product_1 = 0; product_1 < productSizes[leftWindow + length - 1]; product_1++)
            {
                if (score[leftWindow + length - 1][product_1] > bestFinalScore)
                {
                    bestCurrentProduct = product_1;
                    bestFinalScore     = score[leftWindow + length - 1][product_1];
                }
            }
            int lastProduct = bestCurrentProduct;

            for (int last = padLength - 1; last >= length - 1 && last >= 0; last--)
            {
                tempTags[last] = tags[last][lastProduct % tagNum[last]];
                lastProduct   /= tagNum[last];
            }
            for (int pos_5 = leftWindow + length - 2; pos_5 >= leftWindow; pos_5--)
            {
                int bestNextProduct = bestCurrentProduct;
                bestCurrentProduct           = trace[pos_5 + 1][bestNextProduct];
                tempTags[pos_5 - leftWindow] = tags[pos_5 - leftWindow][bestCurrentProduct / (productSizes[pos_5] / tagNum[pos_5 - leftWindow])];
            }
            return(new Pair <int[], double>(tempTags, bestFinalScore));
        }