internal virtual bool IsCorrect(ITransition other)
 {
     if (transition != null && transition.Equals(other))
     {
         return(true);
     }
     if (allowsShift && (other is ShiftTransition))
     {
         return(true);
     }
     if (allowsBinary && (other is BinaryTransition))
     {
         return(true);
     }
     if (allowsEitherSide && (other is BinaryTransition) && (transition is BinaryTransition))
     {
         if (((BinaryTransition)other).label.Equals(((BinaryTransition)transition).label))
         {
             return(true);
         }
     }
     return(false);
 }
        /// <summary>
        /// Given a predicted transition and a state, this method rearranges
        /// the list of transitions and returns whether or not training can
        /// continue.
        /// </summary>
        internal virtual bool Reorder(State state, ITransition chosenTransition, IList <ITransition> transitions)
        {
            if (transitions.Count == 0)
            {
                throw new AssertionError();
            }
            ITransition goldTransition = transitions[0];

            // If the transition is gold, we are already satisfied.
            if (chosenTransition.Equals(goldTransition))
            {
                transitions.Remove(0);
                return(true);
            }
            // If the transition should have been a Unary/CompoundUnary
            // transition and it was something else or a different Unary
            // transition, see if the transition sequence can be continued
            // after skipping past the unary
            if ((goldTransition is UnaryTransition) || (goldTransition is CompoundUnaryTransition))
            {
                transitions.Remove(0);
                return(Reorder(state, chosenTransition, transitions));
            }
            // If the chosen transition was an incorrect Unary/CompoundUnary
            // transition, skip past it and hope to continue the gold
            // transition sequence.  However, if we have Unary/CompoundUnary
            // in a row, we have to return false to prevent loops.
            // Also, if the state stack size is 0, can't keep going
            if ((chosenTransition is UnaryTransition) || (chosenTransition is CompoundUnaryTransition))
            {
                if (state.transitions.Size() > 0)
                {
                    ITransition previous = state.transitions.Peek();
                    if ((previous is UnaryTransition) || (previous is CompoundUnaryTransition))
                    {
                        return(false);
                    }
                }
                if (state.stack.Size() == 0)
                {
                    return(false);
                }
                return(true);
            }
            if (chosenTransition is BinaryTransition)
            {
                if (state.stack.Size() < 2)
                {
                    return(false);
                }
                if (goldTransition is ShiftTransition)
                {
                    // Helps, but adds quite a bit of size to the model and only helps a tiny bit
                    return(op.TrainOptions().oracleBinaryToShift&& ReorderIncorrectBinaryTransition(transitions));
                }
                if (!(goldTransition is BinaryTransition))
                {
                    return(false);
                }
                BinaryTransition chosenBinary = (BinaryTransition)chosenTransition;
                BinaryTransition goldBinary   = (BinaryTransition)goldTransition;
                if (chosenBinary.IsBinarized())
                {
                    // Binarized labels only work (for now, at least) if the side
                    // is wrong but the label itself is correct
                    if (goldBinary.IsBinarized() && chosenBinary.label.Equals(goldBinary.label))
                    {
                        transitions.Remove(0);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                // In all other binarized situations, essentially what has
                // happened is we added a bracket error, but future brackets can
                // still wind up being correct
                transitions.Remove(0);
                return(true);
            }
            if ((chosenTransition is ShiftTransition) && (goldTransition is BinaryTransition))
            {
                // can't shift at the end of the queue
                if (state.EndOfQueue())
                {
                    return(false);
                }
                // doesn't help, sadly
                BinaryTransition goldBinary = (BinaryTransition)goldTransition;
                if (!goldBinary.IsBinarized())
                {
                    return(op.TrainOptions().oracleShiftToBinary&& ReorderIncorrectShiftTransition(transitions));
                }
            }
            return(false);
        }