using System; using System.Diagnostics; using miew.Debugging; using miew.Enumerable; namespace agree { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// TFS subsumption checking for (e.g.) packing purposes /// </summary> /// <reference> /// Stephan Oepen, John Carroll. 2000. "Ambiguity Packing in Constraint-based Parsing--Practical Results." /// In Proceedings of the 1st North American chapter of the Association for Computational Linguistics /// conference. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 162-169. /// </reference> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public unsafe struct Subsumption { TypeMgr tm; byte[] restrictor; Tfs tfs0, tfs1; sbyte subsumption; byte* rgb0, rgb1; byte b_next; ushort*[] rgpfix; public Subsumption(Tfs tfs0, Tfs tfs1) { this.tm = tfs0.tm; this.restrictor = tm.config.parser.packing_restrictor_map; this.rgpfix = tm.rgpfix_allft; this.tfs0 = tfs0; this.tfs1 = tfs1; this.subsumption = Equivalent; this.rgb0 = this.rgb1 = null; this.b_next = 0; } public const sbyte None = 0; public const sbyte FirstSubsumesSecond = 1; public const sbyte SecondSubsumesFirst = 2; public const sbyte Equivalent = 3; public const sbyte Bottom = -4; // note: doesn't interfere with subsumption bit-testing public void _check(int tid, int m0, int m1) { ushort* pfix = rgpfix[tid]; ushort* pfix_end = *pfix++ + pfix; while (pfix < pfix_end) { int i_feat = *pfix++; if (restrictor[i_feat] == 1) continue; int nm0, nm1; Edge.Flag f0 = tfs0.TryGetFlagsMark(i_feat, m0, out nm0); Edge.Flag f1 = tfs1.TryGetFlagsMark(i_feat, m1, out nm1); if (f0 == 0 && f1 == 0) continue; else if (f0 == 0) subsumption &= unchecked((sbyte)0xFD); else if (f1 == 0) subsumption &= unchecked((sbyte)0xFE); /// check for a re-entrancy that is present in one TFS but not the other byte* pb0, pb1; if (nm0 < 0 && nm1 < 0) { byte b0 = *(pb0 = rgb0 + ~nm0), b1 = *(pb1 = rgb1 + ~nm1); if (b0 + b1 == 0) *pb0 = *pb1 = ++b_next; else if (b0 == 0) { subsumption &= unchecked((sbyte)0xFD); *pb0 = b1; } else if (b1 == 0) { subsumption &= unchecked((sbyte)0xFE); *pb1 = b0; } else if (b0 != b1) subsumption = None; } else if (nm0 < 0) { subsumption &= unchecked((sbyte)0xFE); if (*(pb0 = rgb0 + ~nm0) == 0) *pb0 = ++b_next; } else if (nm1 < 0) { subsumption &= unchecked((sbyte)0xFD); if (*(pb1 = rgb1 + ~nm1) == 0) *pb1 = ++b_next; } if (subsumption <= 0) return; /// check type subsumption Edge.Flag f; f0 &= ~(Edge.Flag.Coreference | Edge.Flag.PrunedDuringParsing); f1 &= ~(Edge.Flag.Coreference | Edge.Flag.PrunedDuringParsing); if (f0 == f1) f = f0; else { if (f1 == 0) f = f0; else if (f0 == 0) f = f1; else if ((f = tm.UnifyTypes(f0, f1)) == Edge.Flag.Bottom) { subsumption = Bottom; return; } if (f == f0) subsumption &= unchecked((sbyte)0xFE); else if (f == f1) subsumption &= unchecked((sbyte)0xFD); else { #if DEBUG Nop.CodeCoverage((f & Edge.Flag.EtmString) != 0); #endif subsumption = None; } if (subsumption <= 0) return; } if (nm0 != 0 && nm1 != 0 && (f & Edge.Flag.EtmNonBareType) != 0) { _check((int)(f & Edge.Flag.MultiIdMask), nm0, nm1); if (subsumption <= 0) return; } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// -1 : tfs0 ⊓ tfs1 = ⊥ /// 0 : no subsumption relationship (possibly ⊥) /// 1 : tfs0 ⊑ tfs1 /// 2 : tfs1 ⊑ tfs0 /// 3 : tfs0 == tfs1 /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public sbyte Check() { Edge.Flag f, f0 = tfs0.Edge.FlagsId, f1 = tfs1.Edge.FlagsId; Debug.Assert(((f0 | f1) & (Edge.Flag.Coreference | Edge.Flag.PrunedDuringParsing)) == 0); if (f0 == f1) f = f0; else { if (f1 == 0) f = f0; else if (f0 == 0) f = f1; else if ((f = tm.UnifyTypes(f0, f1)) == Edge.Flag.Bottom) return Bottom; throw new Exception(); //Nop.CodeCoverage(); //if (f == f0) // subsumption &= unchecked((sbyte)0xFE); //else if (f == f1) // subsumption &= unchecked((sbyte)0xFD); //else //{ // Nop.CodeCoverage(); // this is wrong I think // return TfsSubsumptionNone; //} } int c = -(tfs0.next_coref_mark + 1); byte* _pp = stackalloc byte[c - (tfs1.next_coref_mark + 1)]; rgb0 = _pp; rgb1 = _pp + c; int m0 = tfs0.Edge.Mark, m1 = tfs1.Edge.Mark; if (m0 != 0 && m1 != 0 && (f & Edge.Flag.EtmNonBareType) != 0) _check((int)(f & Edge.Flag.MultiIdMask), m0, m1); return subsumption; } }; }