public virtual void TestBinarySide()
        {
            string[] words = new string[] { "This", "is", "a", "short", "test", "." };
            string[] tags  = new string[] { "DT", "VBZ", "DT", "JJ", "NN", "." };
            NUnit.Framework.Assert.AreEqual(words.Length, tags.Length);
            IList <TaggedWord> sentence = SentenceUtils.ToTaggedList(Arrays.AsList(words), Arrays.AsList(tags));
            State           state       = ShiftReduceParser.InitialStateFromTaggedSentence(sentence);
            ShiftTransition shift       = new ShiftTransition();

            state = shift.Apply(shift.Apply(state));
            BinaryTransition transition = new BinaryTransition("NP", BinaryTransition.Side.Right);
            State            next       = transition.Apply(state);

            NUnit.Framework.Assert.AreEqual(BinaryTransition.Side.Right, ShiftReduceUtils.GetBinarySide(next.stack.Peek()));
            transition = new BinaryTransition("NP", BinaryTransition.Side.Left);
            next       = transition.Apply(state);
            NUnit.Framework.Assert.AreEqual(BinaryTransition.Side.Left, ShiftReduceUtils.GetBinarySide(next.stack.Peek()));
        }
        /// <summary>
        /// Shifting is legal as long as the state is not finished and there
        /// are more items on the queue to be shifted.
        /// </summary>
        /// <remarks>
        /// Shifting is legal as long as the state is not finished and there
        /// are more items on the queue to be shifted.
        /// TODO: go through the papers and make sure they don't mention any
        /// other conditions where one shouldn't shift
        /// </remarks>
        public virtual bool IsLegal(State state, IList <ParserConstraint> constraints)
        {
            if (state.finished)
            {
                return(false);
            }
            if (state.tokenPosition >= state.sentence.Count)
            {
                return(false);
            }
            // We disallow shifting when the previous transition was a right
            // head transition to a partial (binarized) state
            // TODO: I don't have an explanation for this, it was just stated
            // in Zhang & Clark 2009
            if (state.stack.Size() > 0)
            {
                Tree top = state.stack.Peek();
                // Temporary node, eg part of a binarized sequence
                if (top.Label().Value().StartsWith("@") && top.Children().Length == 2 && ShiftReduceUtils.GetBinarySide(top) == BinaryTransition.Side.Right)
                {
                    return(false);
                }
            }
            if (constraints == null || state.stack.Size() == 0)
            {
                return(true);
            }
            Tree top_1 = state.stack.Peek();

            // If there are ParserConstraints, you can only shift if shifting
            // will not make a constraint unsolvable.  This happens if we
            // shift beyond the right end of a constraint which is not solved.
            foreach (ParserConstraint constraint in constraints)
            {
                // either went past or haven't gotten to this constraint yet
                if (ShiftReduceUtils.RightIndex(top_1) != constraint.end - 1)
                {
                    continue;
                }
                int left = ShiftReduceUtils.LeftIndex(top_1);
                if (left < constraint.start)
                {
                    continue;
                }
                if (left > constraint.start)
                {
                    return(false);
                }
                if (!ShiftReduceUtils.ConstraintMatchesTreeTop(top_1, constraint))
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Returns an attempt at a "gold" transition given the current state
        /// while parsing a known gold tree.
        /// </summary>
        /// <remarks>
        /// Returns an attempt at a "gold" transition given the current state
        /// while parsing a known gold tree.
        /// Tree is passed in by index so the oracle can precompute various
        /// statistics about the tree.
        /// If we already finalized, then the correct transition is to idle.
        /// If the stack is empty, shift is the only possible answer.
        /// If the first item on the stack is a correct span, correctly
        /// labeled, and it has unaries transitions above it, then if we are
        /// not doing compound unaries, the next unary up is the correct
        /// answer.  If we are doing compound unaries, and the state does not
        /// already have a transition, then the correct answer is a compound
        /// unary transition to the top of the unary chain.
        /// If the first item is the entire tree, with no remaining unary
        /// transitions, then we need to finalize.
        /// If the first item is a correct span, with or without a correct
        /// label, and there are no unary transitions to be added, then we
        /// must look at the next parent.  If it has the same left side, then
        /// we return a shift transition.  If it has the same right side,
        /// then we look at the next subtree on the stack (which must exist).
        /// If it is also correct, then the transition is to combine the two
        /// subtrees with the correct label and side.
        /// TODO: suppose the correct label is not either child label and the
        /// children are binarized states?  We should see what the
        /// debinarizer does in that case.  Perhaps a post-processing step
        /// If the previous stack item is too small, then any binary reduce
        /// action is legal, with no gold transition.  TODO: can this be improved?
        /// If the previous stack item is too large, perhaps because of
        /// incorrectly attached PP/SBAR, for example, we still need to
        /// binary reduce.  TODO: is that correct?  TODO: we could look back
        /// further in the stack to find hints at a label that would work
        /// better, for example
        /// If the current item is an incorrect span, then look at the
        /// containing item.  If it has the same left side, shift.  If it has
        /// the same right side, binary reduce (producing an exact span if
        /// possible).  If neither edge is correct, then any of shift or
        /// binary reduce are acceptable, with no gold transition.  TODO: can
        /// this be improved?
        /// </remarks>
        internal virtual OracleTransition GoldTransition(int index, State state)
        {
            if (state.finished)
            {
                return(new OracleTransition(new IdleTransition(), false, false, false));
            }
            if (state.stack.Size() == 0)
            {
                return(new OracleTransition(new ShiftTransition(), false, false, false));
            }
            IDictionary <Tree, Tree> parents = parentMaps[index];
            Tree             gold            = binarizedTrees[index];
            IList <Tree>     leaves          = leafLists[index];
            Tree             S0          = state.stack.Peek();
            Tree             enclosingS0 = GetEnclosingTree(S0, parents, leaves);
            OracleTransition result      = GetUnaryTransition(S0, enclosingS0, parents, compoundUnaries);

            if (result != null)
            {
                return(result);
            }
            // TODO: we could interject that all trees must end with ROOT, for example
            if (state.tokenPosition >= state.sentence.Count && state.stack.Size() == 1)
            {
                return(new OracleTransition(new FinalizeTransition(rootStates), false, false, false));
            }
            if (state.stack.Size() == 1)
            {
                return(new OracleTransition(new ShiftTransition(), false, false, false));
            }
            if (SpansEqual(S0, enclosingS0))
            {
                Tree parent = parents[enclosingS0];
                // cannot be root
                while (SpansEqual(parent, enclosingS0))
                {
                    // in case we had missed unary transitions
                    enclosingS0 = parent;
                    parent      = parents[parent];
                }
                if (parent.Children()[0] == enclosingS0)
                {
                    // S0 is the left child of the correct tree
                    return(new OracleTransition(new ShiftTransition(), false, false, false));
                }
                // was the second (right) child.  there must be something else on the stack...
                Tree S1          = state.stack.Pop().Peek();
                Tree enclosingS1 = GetEnclosingTree(S1, parents, leaves);
                if (SpansEqual(S1, enclosingS1))
                {
                    // the two subtrees should be combined
                    return(new OracleTransition(new BinaryTransition(parent.Value(), ShiftReduceUtils.GetBinarySide(parent)), false, false, false));
                }
                return(new OracleTransition(null, false, true, false));
            }
            if (ShiftReduceUtils.LeftIndex(S0) == ShiftReduceUtils.LeftIndex(enclosingS0))
            {
                return(new OracleTransition(new ShiftTransition(), false, false, false));
            }
            if (ShiftReduceUtils.RightIndex(S0) == ShiftReduceUtils.RightIndex(enclosingS0))
            {
                Tree S1          = state.stack.Pop().Peek();
                Tree enclosingS1 = GetEnclosingTree(S1, parents, leaves);
                if (enclosingS0 == enclosingS1)
                {
                    // BinaryTransition with enclosingS0's label, either side, but preferring LEFT
                    return(new OracleTransition(new BinaryTransition(enclosingS0.Value(), BinaryTransition.Side.Left), false, false, true));
                }
                // S1 is smaller than the next tree S0 is supposed to be part of,
                // so we must have a BinaryTransition
                if (ShiftReduceUtils.LeftIndex(S1) > ShiftReduceUtils.LeftIndex(enclosingS0))
                {
                    return(new OracleTransition(null, false, true, true));
                }
                // S1 is larger than the next tree.  This is the worst case
                return(new OracleTransition(null, true, true, true));
            }
            // S0 doesn't match either endpoint of the enclosing tree
            return(new OracleTransition(null, true, true, true));
        }