-- FeaturePSTImpl.mesa -- A generic package to organize list elements -- in a priority search tree by the intervals they cover, -- and to search by interval. -- last modified by E. McCreight, November 8, 1982 2:34 PM -- written by E. McCreight, November 3, 1981 11:08 AM DIRECTORY InlineDefs, MiscDefs, FeaturePST; FeaturePSTImpl: PROGRAM IMPORTS InlineDefs, MiscDefs, FeaturePST EXPORTS FeaturePST SHARES FeaturePST = BEGIN OPEN FeaturePST; -- Note: An Interval is [min..max). NewFeaturePST: PUBLIC PROCEDURE[zone: UNCOUNTED ZONE] RETURNS[PSTHandle] = {RETURN[zone.NEW[PSTObject _ [ zone: zone, root: zone.NEW[PSTNode _ [nil[]]]]]]}; DestroyFeaturePST: PUBLIC PROCEDURE[p: PSTHandle] RETURNS[PSTHandle] = BEGIN InternalDestroyPST: PROCEDURE[p: PSTNodePtr] = BEGIN WITH d: p SELECT FROM nil => NULL; leaf => p^ _ [nil[]]; internal => BEGIN pst: PSTBinNodePtr _ d.pst; InternalDestroyPST[@pst.halves[lower]]; InternalDestroyPST[@pst.halves[upper]]; zone.FREE[@pst]; p^ _ [nil[]]; END; ENDCASE; END; zone: UNCOUNTED ZONE _ p.zone; pi: PSTNodePtr _ p.root; InternalDestroyPST[pi]; zone.FREE[@p.root]; WHILE p.freeNodes#NIL DO node: PSTBinNodePtr _ NewNode[p]; zone.FREE[@node]; ENDLOOP; zone.FREE[@p]; RETURN[NIL]; END; -- of DestroyPST InsertFeaturePST: PUBLIC PROCEDURE[p: PSTHandle, item: Item] = BEGIN -- There can be many items with the same -- .y value. For now we shall simply let these -- form degenerate trees upward, so as not to -- overflow our stacks. pi: PSTNodePtr _ p.root; -- IF checkTree THEN CheckPST[p]; DO WITH f: pi SELECT FROM nil => {pi^ _ [leaf[item: item]]; EXIT}; leaf => pi^ _ [internal[pst: NewNode[p: p, init: [vMin: f.item, uLen: CommonLen[f.item, item, pt]]]]]; internal => BEGIN OPEN InlineDefs; son: PSTBinNodePtr _ f.pst; newULen: RadixIndex _ CommonLen[item, son.vMin, pt]; IF newULen SIGNAL CouldntDeleteFeaturePST; leaf => IF item=f.item THEN {pi^ _ [nil[]]; EXIT} ELSE SIGNAL CouldntDeleteFeaturePST; internal => BEGIN son: PSTBinNodePtr _ f.pst; IF item=son.vMin THEN {ExtractVMin[pi, p]; EXIT} ELSE pi _ @son.halves[TreeHalf[item, son.uLen]]; END; ENDCASE; ENDLOOP; -- IF checkTree THEN CheckPST[p]; END; -- of DeleteFeaturePST ExtractVMin: PROCEDURE[pi: PSTNodePtr, p: PSTHandle] = BEGIN DO WITH f: pi SELECT FROM nil => MiscDefs.CallDebugger[NIL]; leaf => {pi^ _ [nil[]]; RETURN}; internal => BEGIN t: PSTBinNodePtr _ f.pst; WITH l: t.halves[lower] SELECT FROM nil => WITH u: t.halves[upper] SELECT FROM nil => {FreeNode[p, t]; pi^ _[nil[]]; RETURN}; leaf => BEGIN pi^ _ [leaf[item: u.item]]; FreeNode[p, t]; RETURN; END; internal => {t.vMin _ u.pst.vMin; pi _ @u}; ENDCASE; -- u leaf => WITH u: t.halves[upper] SELECT FROM nil => BEGIN pi^ _ [leaf[item: l.item]]; FreeNode[p, t]; RETURN; END; leaf => IF Shallower[l.item, u.item] THEN {t.vMin _ l.item; pi _ @l} ELSE {t.vMin _ u.item; pi _ @u}; internal => IF Shallower[l.item, u.pst.vMin] THEN {t.vMin _ l.item; pi _ @l} ELSE {t.vMin _ u.pst.vMin; pi _ @u}; ENDCASE; -- u internal => WITH u: t.halves[upper] SELECT FROM nil => {t.vMin _ l.pst.vMin; pi _ @l}; leaf => IF Shallower[l.pst.vMin, u.item] THEN {t.vMin _ l.pst.vMin; pi _ @l} ELSE {t.vMin _ u.item; pi _ @u}; internal => IF Shallower[l.pst.vMin, u.pst.vMin] THEN {t.vMin _ l.pst.vMin; pi _ @l} ELSE {t.vMin _ u.pst.vMin; pi _ @u}; ENDCASE; -- u ENDCASE; -- l END; ENDCASE; -- f ENDLOOP; END; -- of ExtractVMin NewNode: PROCEDURE[p: PSTHandle, init: PSTBinNode _ [uLen: 0]] RETURNS[new: PSTBinNodePtr] = INLINE BEGIN IF (new _ p.freeNodes)#NIL THEN BEGIN WITH n: new.halves[lower] SELECT FROM internal => p.freeNodes _ n.pst; nil => p.freeNodes _ NIL; ENDCASE => ERROR; -- bad free list linkage new^ _ init; END ELSE new _ p.zone.NEW[PSTBinNode _ init]; END; -- of NewNode FreeNode: PROCEDURE[p: PSTHandle, old: PSTBinNodePtr] = INLINE BEGIN old.halves[lower] _ [internal[pst: p.freeNodes]]; p.freeNodes _ old; END; -- of FreeNode pqLim: INTEGER = 200; PSTPQEnt: TYPE = RECORD[min: Domain, p: PSTNodePtr]; PSTPQArray: TYPE = ARRAY [1..pqLim) OF PSTPQEnt; PSTPQPtr: TYPE = LONG POINTER TO PSTPQArray _ NIL; PSTPQs: ARRAY [0..10) OF PSTPQPtr; recursionDepth: [0..10) _ 0; SearchFeaturePST: PUBLIC PROCEDURE[p: PSTHandle, int: Interval, touch: PROCEDURE[item: Item]] = BEGIN -- enumerates in increasing order by Min[item] MakePSTPQEnt: PROCEDURE[p: PSTNodePtr] RETURNS[PSTPQEnt] = INLINE BEGIN WITH dp: p SELECT FROM internal => RETURN[[min: Min[dp.pst.vMin], p: p]]; leaf => RETURN[[min: Min[dp.item], p: p]]; ENDCASE => RETURN[[min: FIRST[Domain], p: p]]; END; yMin: Domain _ int.min; yMax: Domain _ int.max; -- yMax not in interval pqSize: [0..pqLim) _ 1; PSTPQ: PSTPQPtr _ IF PSTPQs[recursionDepth]#NIL THEN PSTPQs[recursionDepth] ELSE (PSTPQs[recursionDepth] _ p.zone.NEW[PSTPQArray]); recursionDepth _ recursionDepth+1; PSTPQ[1] _ MakePSTPQEnt[p.root]; WHILE 1<=pqSize DO RippleUp: PROCEDURE[] = INLINE BEGIN p: PSTPQEnt _ PSTPQ[hole]; FOR nextHole _ hole/2, hole/2 WHILE 1<=nextHole AND p.min FillHole[]; leaf => BEGIN OPEN f; IF next.min recursionDepth _ recursionDepth-1]; FillHole[]; END; internal => BEGIN OPEN InlineDefs; son: PSTBinNodePtr _ f.pst; IF next.min<=yMax THEN -- interval could touch this subtree BEGIN OPEN son; IF next.min recursionDepth _ recursionDepth-1]; PSTPQ[hole] _ MakePSTPQEnt[@halves[upper]]; RippleUp[]; WITH fLower: halves[lower] SELECT FROM nil => NULL; leaf => NewPSTPQ[@fLower]; internal => IF NOT Above[yMin, fLower.pst] THEN -- interval could touch lower subtree as well NewPSTPQ[@fLower]; ENDCASE; END ELSE FillHole[]; END; ENDCASE; ENDLOOP; recursionDepth _ recursionDepth-1; END; -- of SearchFeaturePST ClassifyFeaturePSTInterval: PUBLIC PROCEDURE[p: PSTHandle, int: Interval, covered: PROCEDURE[int: Interval, repItem: Item], gap: PROCEDURE[int: Interval]] = BEGIN OPEN MiscDefs; DoGap: PROCEDURE[int: Interval] = INLINE {IF gap#NullFeatureGap THEN gap[int]}; DoCovered: PROCEDURE[int: Interval, repItem: Item] = INLINE {IF covered#NullFeatureCovered THEN covered[int, repItem]}; Classify: PROCEDURE[pi: PSTNodePtr, w: Interval] RETURNS[r: Interval, minItem, maxItem: Item _ nullItem] = BEGIN -- The window w is not empty, so w.minw.min and r.max BEGIN DoGap[w]; r _ w; RETURN END; leaf => BEGIN item _ f.item; i _ [min: Min[item], max: Max[item]]; IF i.max<=w.min OR w.max<=i.min THEN {DoGap[w]; r _ w; RETURN}; -- no coverage i2 _ [w.max, w.max]; -- empty above w lSon _ NIL; END; -- leaf internal => BEGIN fint: PSTBinNodePtr _ f.pst; item _ fint.vMin; i _ [min: Min[item], max: Max[item]]; IF w.max<=i.min OR Above[w.min, fint] THEN {DoGap[w]; r _ w; RETURN}; -- no coverage possible lSon _ @fint.halves[lower]; rSon _ @fint.halves[upper]; WITH s: fint.halves[upper] SELECT FROM nil => BEGIN i2 _ [w.max, w.max]; -- empty above w END; leaf => BEGIN rtItem _ s.item; i2 _ [min: Min[rtItem], max: Max[rtItem]]; END; internal => BEGIN rtItem _ s.pst.vMin; i2 _ [min: Min[rtItem], max: Max[rtItem]]; END; ENDCASE; END; -- internal ENDCASE; -- Here i.min minItem _ item; IN [i2.min..i2.max) => minItem _ rtItem; ENDCASE => NULL; SELECT w.max FROM <=i.max => maxItem _ item; -- greatest element of w IN i IN (i2.min..i2.max] => maxItem _ rtItem; -- greatest element of w IN i2 ENDCASE => NULL; -- If i and i2 touch, we can extend i and i2 to -- cover each other's upper endpoints -- without altering their joint coverage. IF i2.min<=i.max THEN -- i.min<=i2.min by PST invariant BEGIN i.max _ i2.max _ MAX[i.max, i2.max]; END; IF -- i.max<= -- i2.max<=w.min THEN {[r, minItem, maxItem] _ Classify[rSon, w]; RETURN} -- w is beyond the effects of i, i2, and lSon ELSE IF -- i.max<= -- i2.max r.min _ MIN[w.max, i.max]; IN [i2.min..i2.max) => r.min _ MIN[w.max, i2.max]; ENDCASE => NULL; SELECT w.max FROM <=i.max => r.max _ MAX[w.min, i.min]; -- greatest element of w IN i IN (i2.min..i2.max] => r.max _ MAX[w.min, i2.min]; -- greatest element of w IN i2 ENDCASE => NULL; END; -- of Classify pi: PSTNodePtr _ p.root; IF int.min0 DO FOR k _ k, k-1 WHILE j<=k DO prefixTable[k] _ i; ENDLOOP; i _ i+1; ENDLOOP; prefixTable[0] _ 8; -- nobody should use this entry... END; InitPrefixTable[]; END. -- of FeaturePSTImpl