<> <> DIRECTORY Basics, Collections, Convert, LichenArrayStuff, LichenDataOps, LichenDataStructure, List, LRUCache, PairCollections, Rope; LichenNewArrayImpl1: CEDAR PROGRAM IMPORTS Collections, Convert, LichenDataOps, LichenDataStructure, List, LRUCache, PairCollections, Rope EXPORTS LichenArrayStuff, LichenDataStructure = BEGIN OPEN LichenDataOps, LichenDataStructure, LichenArrayStuff, PairColls:PairCollections, Colls:Collections; Array: TYPE ~ LichenDataStructure.Array; CreateArrayRep: PUBLIC PROC [eltType: CellType, size2, basePeriod: Size2] RETURNS [Array] ~ { statrep: StatRep ~ CreateStatRep[]; a: Array = NEW [ArrayPrivate _ [ eltType: eltType, prevArray: NIL, nextArray: NIL, size2: size2, size: size2[Foo]*size2[Bar], basePeriod: basePeriod, dumrep: NIL, statrep: statrep ]]; RETURN [a]}; CreateStatRep: PUBLIC PROC RETURNS [sr: StatRep] ~ { sr _ NEW [StatRepPrivate _ [ edges: Colls.CreateHashSet[], portEdge: [ FALSE: PairColls.CreateHashReln[functional: [FALSE, TRUE], mappable: [TRUE, FALSE]], TRUE: PairColls.CreateHashReln[functional: [FALSE, TRUE], mappable: [TRUE, FALSE]]] ]]; RETURN}; flushSelves: BOOL _ TRUE; MakeArrayNewConnection: PUBLIC PROC [act: CellType, rangeA: Range2, delta: Int2, epA, epB: Port] ~ { a: Array ~ act.asArray; fullRangeA: Range2 ~ Range2Intersection[SizeRange[a.size2], Range2Off[SizeRange[a.size2], Int2Neg[delta]]]; rangeB: Range2 ~ Range2Off[rangeA, delta]; IF a.buildPhase#buildingStatrep THEN ERROR; IF ABS[delta[Foo]]>1 OR ABS[delta[Bar]]>1 THEN ERROR; IF epA=epB AND delta=[0, 0] THEN --this self-connection is always implicitly present, let's not make it explicit-- IF flushSelves THEN RETURN; IF rangeA # fullRangeA THEN ERROR; FOR svA: StatVertex ~ NEW [StatVertexPrivate _ [epA, svB: StatVertex ~ NEW [StatVertexPrivate _ [epB, IF NOT StatEdgeRedundant[a, [vs: [svA, svB], delta]]; act _ act; ENDLOOP ENDLOOP; RETURN}; AddStatEdge: PUBLIC PROC [sr: StatRep, sep: StatEdgePrivate] RETURNS [se: StatEdge] ~ { se _ NEW [StatEdgePrivate _ sep]; sr.portEdge[FALSE].AddNewPair[[sep.vs[FALSE].port, se]]; sr.portEdge[TRUE].AddNewPair[[sep.vs[TRUE].port, se]]; IF NOT sr.edges.AddElt[se] THEN ERROR; RETURN}; StatEdgeRedundant: PUBLIC PROC [a: Array, sep: StatEdgePrivate, avoid: StatEdge _ NIL] RETURNS [redundant: BOOL] ~ { seen: Set--of PortAtIndex-- ~ Colls.CreateHashSet[portsAtIndices]; frontier: Set--of PortAtIndex-- ~ Colls.CreateHashSet[portsAtIndices]; c1: Int2 ~ WidenNat2[sep.vs[FALSE].phase]; c2: Int2 ~ Int2Add[c1, sep. bounds: Range2 ~ Int2sRange[c1, c2]; IF sep.vs[TRUE].phase # Nat2AddMod[sep.vs[FALSE].phase, sep. IF NOT frontier.AddElt[NEW [PortAtIndexPrivate _ [sep.vs[FALSE].port, c1]]] THEN ERROR; WHILE NOT frontier.Empty[] DO pai: PortAtIndex ~ NARROW[frontier.Pop.val]; IF NOT seen.AddElt[pai] THEN LOOP; IF pai.port = sep.vs[TRUE].port AND pai.ai = c2 THEN RETURN [TRUE]; {sv: StatVertex ~ NEW [StatVertexPrivate _ [pai.port, Int2Mod[pai.ai, a.basePeriod]]]; TestEdge: PROC [se: StatEdge, ob: BOOL] RETURNS [BOOL] ~ { oai: ArrayIndex ~ Int2Add[pai.ai, IF se#avoid AND Int2InRange[oai, bounds] THEN [] _ frontier.AddElt[NEW [PortAtIndexPrivate _ [se.vs[ob].port, oai]]]; RETURN [FALSE]}; [] _ ScanStatEdgesFrom[a.statrep, sv, TestEdge]; }ENDLOOP; RETURN [FALSE]}; FindStatEdge: PUBLIC PROC [sr: StatRep, sep: StatEdgePrivate] RETURNS [fse: StatEdge] ~ { TestEdge: PROC [se: StatEdge, ob: BOOL] RETURNS [BOOL] ~ { RETURN [statVerts.SpaceEqual[se.vs[ob], sep.vs[TRUE]] AND sep. fse _ ScanStatEdgesFrom[sr, sep.vs[FALSE], TestEdge].se; RETURN}; FinishedMakingArrayConnections: PUBLIC PROC [act: CellType] ~ { a: Array ~ act.asArray; dumrep: DumRep ~ NEW [DumRepPrivate _ [ topWires: Colls.CreateHashSet[], epToTopWire: PairColls.CreateHashFn[invable: FALSE], apToWire: PairColls.CreateHashFn[invable: TRUE] ]]; PerStatEdge: PROC [ra: REF ANY] ~ { se: StatEdge ~ NARROW[ra]; DumbifyStatEdge[a, se]; RETURN}; IF a.buildPhase#buildingStatrep THEN ERROR; a.buildPhase _ statrepFixed; IF a.dumrep#NIL THEN ERROR; a.dumrep _ dumrep; a.statrep.edges.Enumerate[PerStatEdge]; RETURN}; SetStatRep: PUBLIC PROC [act: CellType, statrep: StatRep, reset: BOOL] ~ { a: Array ~ act.asArray; IF a.buildPhase # (IF reset THEN statrepFixed ELSE buildingStatrep) THEN ERROR; a.buildPhase _ buildingStatrep; a.statrep _ statrep; FinishedMakingArrayConnections[act]; RETURN}; DumbifyStatEdge: PROC [a: Array, se: StatEdge] ~ { epA: Port ~ se.vs[FALSE].port; epB: Port ~ se.vs[TRUE].port; fullRangeA: Range2 ~ Range2Intersection[SizeRange[a.size2], Range2Off[SizeRange[a.size2], Int2Neg[se. iRangeA: Range2 ~ Range2Div[fullRangeA, a.basePeriod, se.vs[FALSE].phase]; dwsA: RefSeq--cai dwsB: RefSeq--cai FOR if: INT IN [iRangeA[Foo].min .. iRangeA[Foo].maxPlusOne) DO FOR ib: INT IN [iRangeA[Bar].min .. iRangeA[Bar].maxPlusOne) DO aiA: Int2 ~ [ if*a.basePeriod[Foo]+se.vs[FALSE].phase[Foo], ib*a.basePeriod[Bar]+se.vs[FALSE].phase[Bar]]; aiB: ArrayIndex ~ Int2Add[se. caiA: CompositeArrayIndex ~ ComposeAI[a, aiA]; caiB: CompositeArrayIndex ~ ComposeAI[a, aiB]; dwA: TopDumbWire ~ NARROW[dwsA[caiA]]; dwB: TopDumbWire ~ NARROW[dwsB[caiB]]; IF dwA=dwB THEN {IF dwA=NIL THEN { dw: TopDumbWire ~ NEW [DumbWirePrivate[top] _ [ children: PairColls.CreateHashFn[invable: FALSE], variant: top[eps: PairColls.CreateHashFn[invable: FALSE]] ]]; IF NOT a.dumrep.topWires.AddElt[dw] THEN ERROR; AddDumbElt[a, dw, epA, aiA]; AddDumbElt[a, dw, epB, aiB]}} ELSE IF dwA=NIL THEN AddDumbElt[a, dwB, epA, aiA] ELSE IF dwB=NIL THEN AddDumbElt[a, dwA, epB, aiB] ELSE JoinDumbWires[a, dwA, dwB]; a _ a; ENDLOOP ENDLOOP; RETURN}; AddDumbElt: PROC [a: Array, dw: TopDumbWire, ep: Port, ai: ArrayIndex] ~ { cai: CompositeArrayIndex ~ ComposeAI[a, ai]; dws: RefSeq--CompositeArrayIndex mems: BoolSeq--CompositeArrayIndex IF mems=NIL THEN dw.eps.AddNewPair[[ep, mems _ CreateBoolSeq[a.size, FALSE]]]; dws[cai] _ dw; mems[cai] _ TRUE; RETURN}; JoinDumbWires: PROC [a: Array, dwA, dwB: TopDumbWire] ~ { MoveElt: PROC [pair: PairColls.Pair] ~ { ep: Port ~ NARROW[pair[left]]; dws: RefSeq--CompositeArrayIndex memsB: BoolSeq ~ NARROW[pair[right]]; memsA: BoolSeq ~ NARROW[dwA.eps.Apply[ep].DVal]; IF memsA=NIL THEN { dwA.eps.AddNewPair[[ep, memsB]]; FOR cai: CompositeArrayIndex IN [0 .. a.size) DO IF memsB[cai] THEN dws[cai] _ dwA; ENDLOOP; } ELSE { FOR cai: CompositeArrayIndex IN [0 .. a.size) DO IF memsB[cai] THEN { memsA[cai] _ TRUE; dws[cai] _ dwA}; ENDLOOP; }; RETURN}; MoveExport: PROC [ra: REF ANY] ~ { ap: Port ~ NARROW[ra]; [] _ a.dumrep.apToWire.AddPair[[ap, dwA]]; RETURN}; IF NOT a.dumrep.topWires.RemoveElt[dwB] THEN ERROR; dwB.eps.Enumerate[MoveElt]; a.dumrep.apToWire.Mapping[dwB, rightToLeft].Enumerate[MoveExport]; RETURN}; GetDumbWires: PROC [a: Array, ep: Port, mayAdd: BOOL] RETURNS [dws: RefSeq--cai dws _ NARROW[a.dumrep.epToTopWire.Apply[ep].DVal]; IF dws=NIL AND mayAdd THEN a.dumrep.epToTopWire.AddNewPair[[ep, dws _ CreateRefSeq[a.size]]]; RETURN}; GetDumbWire: PUBLIC PROC [a: Array, ep: Port, ai: ArrayIndex] RETURNS [dw: DumbWire] ~ { cai: CompositeArrayIndex ~ ComposeAI[a, ai]; Work: PROC [ep: Port] RETURNS [dw: DumbWire] ~ { dws: RefSeq--cai IF dws#NIL THEN dw _ NARROW[dws[cai]]; IF dw#NIL THEN RETURN; IF ep.parent # a.eltType.port THEN { pdw: DumbWire ~ Work[NARROW[ep.parent]]; IF pdw#NIL THEN RETURN [GetDumbChild[pdw, ep]]; }; RETURN}; IF a.buildPhase#statrepFixed THEN ERROR; RETURN Work[ep]}; GetDumbChild: PROC [pdw: DumbWire, port: Port] RETURNS [cdw: ChildDumbWire] ~ { cdw _ NARROW[pdw.children.Apply[port].DVal]; IF cdw#NIL THEN RETURN; pdw.children.AddNewPair[[port, cdw _ NEW [DumbWirePrivate[child] _ [ children: PairColls.CreateHashFn[invable: FALSE], variant: child[pdw, port] ]] ]]; RETURN}; ArrayEltPortsConnected: PUBLIC PROC [a: Array, ai1, ai2: ArrayIndex, ep1, ep2: Port] RETURNS [BOOL] ~ { dw1: DumbWire ~ GetDumbWire[a, ep1, ai1]; dw2: DumbWire ~ GetDumbWire[a, ep2, ai2]; IF a.buildPhase#statrepFixed THEN ERROR; RETURN [dw1=dw2 AND dw1#NIL]}; EnumerateConnectedEltPorts: PUBLIC PROC [a: Array, ep: Port, Consume: PROC [Port]] ~ { seenPorts: Set--of elt Port-- ~ Colls.CreateHashSet[]; PerWire: PROC [dw: DumbWire] ~ { [] _ ScanPortsInDumbWire[a, dw, PassPort]; RETURN}; PassPort: PROC [ep: Port] RETURNS [BOOL] ~ { IF seenPorts.AddElt[ep] THEN Consume[ep]; RETURN [FALSE]}; IF a.buildPhase#statrepFixed THEN ERROR; EnumerateDumbWiresForPort[a, ep, PerWire]; RETURN}; EnumerateDumbWiresForPort: PUBLIC PROC [a: Array, ep: Port, Consume: PROC [DumbWire]] ~ { seenWires: Set--of TopDumbWire-- ~ Colls.CreateHashSet[]; Work: PROC [port: Port, Consume: PROC [DumbWire]] ~ { dws: RefSeq--CompositeArrayIndex IF dws#NIL THEN { FOR cai: CompositeArrayIndex IN [0 .. a.size) DO dw: TopDumbWire ~ NARROW[dws[cai]]; IF seenWires.AddElt[dw] THEN Consume[dw]; ENDLOOP; }; WITH port.parent SELECT FROM parent: Port => { Pass: PROC [parent: DumbWire] ~ { child: ChildDumbWire ~ GetDumbChild[parent, port]; Consume[child]; RETURN}; Work[parent, Pass]; }; x: CellType => NULL; ENDCASE => ERROR; RETURN}; IF a.buildPhase#statrepFixed THEN ERROR; Work[ep, Consume]; RETURN}; ScanPortsInDumbWire: PUBLIC PROC [a: Array, dw: DumbWire, Test: PROC [Port] RETURNS [BOOL]] RETURNS [found: BOOL, ep: Port] ~ { ScanWire: PROC [dw: DumbWire, Test: PROC [Port] RETURNS [BOOL]] RETURNS [found: BOOL, ep: Port] ~ { WITH dw SELECT FROM tdw: TopDumbWire => { TestPort: PROC [pair: PairColls.Pair] RETURNS [pass: BOOL _ FALSE] ~ { port: Port ~ NARROW[pair[left]]; IF (pass _ Test[port]) THEN ep _ port; RETURN}; found _ tdw.eps.Scan[TestPort].found; RETURN}; cdw: ChildDumbWire => { index: NATURAL ~ cdw.port.PortIndex; TestPort: PROC [parent: Port] RETURNS [pass: BOOL _ FALSE] ~ { child: Port ~ parent.SubPort[index]; IF (pass _ Test[child]) THEN ep _ child; RETURN}; found _ ScanWire[cdw.parent, TestPort].found; RETURN}; ENDCASE => ERROR; }; RETURN ScanWire[dw, Test]}; GetInstForPortInDumbWire: PUBLIC PROC [a: Array, dw: DumbWire, ep: Port] RETURNS [ArrayIndex] ~ { WITH dw SELECT FROM tdw: TopDumbWire => { mems: BoolSeq--CompositeArrayIndex FOR cai: NATURAL IN [0 .. a.size) DO IF mems[cai] THEN RETURN DecomposeAI[a, cai]; ENDLOOP; RETURN [ALL[-1]]}; cdw: ChildDumbWire => RETURN GetInstForPortInDumbWire[a, cdw.parent, NARROW[ep.parent]]; ENDCASE => ERROR; }; ScanPortsAtIndicesForDumbWire: PUBLIC PROC [a: Array, dw: DumbWire, Test: PROC [port: Port, ai: ArrayIndex] RETURNS [BOOL]] RETURNS [found: BOOL, pai: PortAtIndexPrivate] ~ { WITH dw SELECT FROM tdw: TopDumbWire => { PerPort: PROC [pair: PairColls.Pair] RETURNS [pass: BOOL] ~ { ep: Port ~ NARROW[pair[left]]; mems: BoolSeq--CompositeArrayIndex FOR f: INT IN [0 .. a.size2[Foo]) DO FOR b: INT IN [0 .. a.size2[Bar]) DO cai: CompositeArrayIndex ~ ComposeAI[a, [f, b]]; IF mems[cai] THEN IF (pass _ Test[ep, [f, b]]) THEN {pai _ [ep, [f, b]]; RETURN}; ENDLOOP ENDLOOP; RETURN [FALSE]}; found _ tdw.eps.Scan[PerPort].found; RETURN}; cdw: ChildDumbWire => { index: NATURAL ~ cdw.port.PortIndex; Pass: PROC [port: Port, ai: ArrayIndex] RETURNS [pass: BOOL] ~ { child: Port ~ port.SubPort[index]; IF (pass _ Test[child, ai]) THEN pai _ [child, ai]; RETURN}; found _ ScanPortsAtIndicesForDumbWire[a, cdw.parent, Pass].found; RETURN}; ENDCASE => ERROR; }; ScanStatVertices: PUBLIC PROC [a: Array, Test: PROC [StatVertex] RETURNS [BOOL]] RETURNS [found: BOOL _ FALSE, sv: StatVertex _ NIL] ~ { seen: Set--of StatVertex-- ~ Colls.CreateHashSet[statVerts]; PerEdge: PROC [ra: REF ANY] ~ { se: StatEdge ~ NARROW[ra]; IF seen.AddElt[se.vs[FALSE]] AND Test[se.vs[FALSE]] THEN {found _ TRUE; sv _ se.vs[FALSE]; RETURN}; IF seen.AddElt[se.vs[TRUE]] AND Test[se.vs[TRUE]] THEN {found _ TRUE; sv _ se.vs[TRUE]}; RETURN}; a.statrep.edges.Enumerate[PerEdge]; RETURN}; ScanStatEdgesFrom: PUBLIC PROC [sr: StatRep, from: StatVertex, Test: PROC [se: StatEdge, ob: BOOL] RETURNS [BOOL]] RETURNS [found: BOOL _ FALSE, se: StatEdge _ NIL, ob: BOOL _ FALSE] ~ { FOR ob IN BOOL DO sb: BOOL ~ NOT ob; TestEdge: PROC [ra: REF ANY] RETURNS [pass: BOOL] ~ { se: StatEdge ~ NARROW[ra]; pass _ se.vs[sb].phase = from.phase AND Test[se, ob]; RETURN}; mp: PairColls.MaybePair ~ sr.portEdge[sb].ScanMapping[from.port, TestEdge]; IF mp.found THEN RETURN [TRUE, NARROW[mp.pair[right]], ob]; ENDLOOP; RETURN}; GetArrayPortForPort: PUBLIC PROC [act: CellType, index: ArrayIndex, ep: Port, mayAdd: BOOL] RETURNS [arrayPort: Port] ~ { a: Array ~ act.asArray; dw: DumbWire ~ GetDumbWire[a, ep, index]; IF a.buildPhase#statrepFixed THEN ERROR; IF dw=NIL THEN {IF mayAdd THEN ERROR--trying to export a composite wire that doesn't really exist-- ELSE RETURN [NIL]}; {ports: Set--of array Port-- ~ a.dumrep.apToWire.Mapping[dw, rightToLeft]; IF NOT ports.Empty THEN RETURN [NARROW[ports.First[].val]]; IF NOT mayAdd THEN RETURN [NIL]; {portName: SteppyName ~ List.Append[NameIndex[a, index], SteppyDescribe[ep, a.eltType.port]]; arrayPort _ FullyAddPort[[parent: act.port, names: CreateSteppyNames[LIST[portName]]]].port; a.dumrep.apToWire.AddNewPair[[arrayPort, dw]]; RETURN}}}; NoteNewEltPort: PUBLIC PROC [a: Array, ep: Port] ~ { RETURN}; IsIncompleteArray: PUBLIC PROC [act: CellType] RETURNS [BOOL] ~ {RETURN [FALSE]}; ComposeAI: PROC [a: Array, ai: ArrayIndex] RETURNS [CompositeArrayIndex] ~ INLINE {RETURN [a.size2[Bar]*ai[Foo]+ai[Bar]]}; DecomposeAI: PROC [a: Array, cai: CompositeArrayIndex] RETURNS [ArrayIndex] ~ { f: NATURAL ~ cai/a.size2[Bar]; RETURN [[f, cai - f*a.size2[Bar]]]}; NameIndex: PUBLIC PROC [a: Array, index: ArrayIndex] RETURNS [SteppyName] = { SELECT TRUE FROM a.size2[Foo]=1 => RETURN [LIST[NewInt[index[Bar]]]]; a.size2[Bar]=1 => RETURN [LIST[NewInt[index[Foo]]]]; ENDCASE => RETURN [LIST[NewInt[index[Foo]], NewInt[index[Bar]]]]; }; FmtIndex: PUBLIC PROC [a: Array, index: ArrayIndex] RETURNS [asRope: ROPE] = { asRope _ SELECT TRUE FROM a.size2[Foo]=1 => Subscript[NIL, index[Bar]], a.size2[Bar]=1 => Subscript[NIL, index[Foo]], ENDCASE => Subscript2[NIL, index]; }; sublen: NATURAL ~ 64; subs: ARRAY [0 .. sublen) OF ROPE _ ALL[NIL]; Subscript: PUBLIC PROC [base: ROPE, index: INT] RETURNS [sub: ROPE] ~ { sub _ IF index < sublen THEN sub _ subs[index] ELSE sub _ Convert.RopeFromInt[index].Concat["/"]; IF base.Length#0 THEN sub _ base.Cat["/", sub]; RETURN}; sub2len: NATURAL _ 2050; sub2Ps: LRUCache.Handle _ LRUCache.Create[sub2len, HashAI, EqualAI]; sub2Rs: RefSeq _ CreateRefSeq[sub2len]; s2probes, s2misses: CARD _ 0; HashAI: PROC [ra: REF ANY] RETURNS [CARDINAL] --LRUCache.HashProc-- ~ { rai: REF ArrayIndex ~ NARROW[ra]; lnF: Basics.LongNumber ~ [li[rai[Foo]]]; lnB: Basics.LongNumber ~ [li[rai[Bar]]]; ln: Basics.LongNumber ~ [lc[lnF.lo + lnF.hi*3 + lnB.lo*5 + lnB.hi*7]]; RETURN [ln.lo+ln.hi]; }; EqualAI: PROC [r1, r2: REF ANY] RETURNS [BOOL] --LRUCache.EqualProc-- ~ { rai1: REF ArrayIndex ~ NARROW[r1]; rai2: REF ArrayIndex ~ NARROW[r2]; RETURN [rai1^ = rai2^]}; Subscript2: PUBLIC PROC [base: ROPE, index: ArrayIndex] RETURNS [sub: ROPE] ~ { rai: REF ArrayIndex ~ NEW [ArrayIndex _ index]; p: NATURAL; news: BOOL; [p, news, ] _ sub2Ps.Include[rai]; s2probes _ s2probes+1; IF news THEN { sub2Rs[p] _ Rope.Cat[Convert.RopeFromInt[index[Foo]], "/", Convert.RopeFromInt[index[Bar]], "/"]; s2misses _ s2misses+1; }; sub _ NARROW[sub2Rs[p]]; IF base.Length#0 THEN sub _ base.Cat["/", sub]; RETURN}; statVerts: PUBLIC Colls.Space ~ NEW [Colls.SpacePrivate _ [ Equal: StatVertsEqual, Hash: HashStatVert, Compare: CompareStatVerts, other: List.PutAssoc[$Name, "stat verts", NIL] ]]; StatVertsEqual: PROC [data, elt1, elt2: REF ANY] RETURNS [BOOL] ~ { RETURN [CompareStatVerts[data, elt1, elt2]=equal]}; HashStatVert: PROC [data, elt: REF ANY] RETURNS [CARDINAL] ~ { sv: StatVertex ~ NARROW[elt]; RETURN [Colls.HashRefI[sv.port] + Colls.HashIntI[sv.phase[Foo]]*137 + Colls.HashIntI[sv.phase[Bar]]]}; CompareStatVerts: PROC [data, elt1, elt2: REF ANY] RETURNS [c: Basics.Comparison] ~ { sv1: StatVertex ~ NARROW[elt1]; sv2: StatVertex ~ NARROW[elt2]; IF (c _ Colls.CompareRefI[sv1.port, sv2.port]) = equal THEN IF (c _ Colls.CompareIntI[sv1.phase[Foo], sv2.phase[Foo]]) = equal THEN c _ Colls.CompareIntI[sv1.phase[Bar], sv2.phase[Bar]]; RETURN}; portsAtIndices: PUBLIC Colls.Space ~ NEW [Colls.SpacePrivate _ [ Equal: PortAtIndexEqual, Hash: HashPortAtIndex, Compare: ComparePortAtIndex, other: List.PutAssoc[$Name, "ports at indices", NIL] ]]; PortAtIndexEqual: PROC [data, elt1, elt2: REF ANY] RETURNS [BOOL] ~ { RETURN [ComparePortAtIndex[data, elt1, elt2]=equal]}; HashPortAtIndex: PROC [data, elt: REF ANY] RETURNS [CARDINAL] ~ { pai: PortAtIndex ~ NARROW[elt]; RETURN [Colls.HashRefI[pai.port] + Colls.HashIntI[pai.ai[Foo]]*137 + Colls.HashIntI[pai.ai[Bar]]]}; ComparePortAtIndex: PROC [data, elt1, elt2: REF ANY] RETURNS [c: Basics.Comparison] ~ { pai1: PortAtIndex ~ NARROW[elt1]; pai2: PortAtIndex ~ NARROW[elt2]; IF (c _ Colls.CompareRefI[pai1.port, pai2.port]) = equal THEN IF (c _ Colls.CompareIntI[pai1.ai[Foo], pai2.ai[Foo]]) = equal THEN c _ Colls.CompareIntI[pai1.ai[Bar], pai2.ai[Bar]]; RETURN}; Range2Div: PUBLIC PROC [r: Range2, rr _ [ Foo: [ min: CeilDiv[r[Foo].min- maxPlusOne: FloorDiv[r[Foo].maxPlusOne-1- Bar: [ min: CeilDiv[r[Bar].min- maxPlusOne: FloorDiv[r[Bar].maxPlusOne-1- }; Range1Div: PUBLIC PROC [r: Range, rr _ [ min: CeilDiv[r.min- maxPlusOne: FloorDiv[r.maxPlusOne-1- }; Range2MulA: PUBLIC PROC [r: Range2, rr _ [ Foo: [ min: r[Foo].min* maxPlusOne: (r[Foo].maxPlusOne-1)* Bar: [ min: r[Bar].min* maxPlusOne: (r[Bar].maxPlusOne-1)* }; Range2MulB: PUBLIC PROC [r: Range2, rr _ [ Foo: [ min: r[Foo].min* maxPlusOne: r[Foo].maxPlusOne* Bar: [ min: r[Bar].min* maxPlusOne: r[Bar].maxPlusOne* }; Range1MulB: PUBLIC PROC [r: Range, rr _ [ min: r.min* maxPlusOne: r.maxPlusOne* }; Start: PROC ~ { FOR index: NATURAL IN [0 .. sublen) DO subs[index] _ Convert.RopeFromInt[index].Concat["/"]; ENDLOOP; RETURN}; Start[]; END.