-- RealVecImpl.mesa, an implementation for dealing with vectors of real numbers -- Last Modified On July 1, 1982 4:47 pm By Paul Rovner DIRECTORY PriorityQueue USING[Ref, Predict, Insert, Empty, Remove], Real USING[FixI, RoundI], RealVec USING[Handle, Object], SafeStorage USING[NewZone]; RealVecImpl: MONITOR -- protects sortee IMPORTS PriorityQueue, Real, SafeStorage EXPORTS RealVec = { OPEN RealVec; -- PUBLIC SIGNALS LengthFault: PUBLIC ERROR[vec: Handle, expectedLength: NAT] = CODE; -- module variables vecZone: ZONE = SafeStorage.NewZone[]; vecQZone: ZONE = SafeStorage.NewZone[quantized]; -- PUBLIC PROCs -- nElements <= h.length. -- Result has averaged values as per some reasonable algorithm Smooth: PUBLIC PROC[h: Handle, nElements: NAT] RETURNS[ans: Handle] = { IF nElements = h.length THEN RETURN[h]; --a, b, c... are in the old space, i, j, k ... in the new ans ← vecZone.NEW[Object[nElements]]; FOR j: NAT IN [0..nElements) DO x: REAL = j; startT: REAL ← x / nElements; endT: REAL ← (x + 1.0) / nElements; a: NAT ← Real.FixI[startT * h.length]; b: NAT ← Real.RoundI[endT * h.length]; -- may be too small by 1 dtOld: REAL ← 1.0/h.length; dtNew: REAL ← endT - startT; IF b*dtOld < endT THEN b ← b + 1; IF a = b THEN ERROR; ans.elements[j] ← 0.0; -- now add up the contributions of each old bucket that the new bucket -- overlaps FOR z: NAT IN [a..b) -- left edge index (from 0) identifies the bucket -- value DO --add in the value in the zth bucket times the fraction of the time -- covered by the zth bucket in the new bucket ans.elements[j] ← ans.elements[j] + h.elements[z] -- the value in the zth bucket * (MIN[dtOld, MIN[endT, (z + 1)*dtOld] - MAX[startT, z*dtOld]])/dtNew ENDLOOP; ENDLOOP}; -- convenient constructors All: PUBLIC PROC[length: NAT, value: REAL ← 0.0] RETURNS[ans: Handle] = {ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← value ENDLOOP}; -- h[0] = 0, h[n] = n IndexVec: PUBLIC PROC[length: NAT] RETURNS[ans: Handle] = {ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← i ENDLOOP}; -- convenient composition and extraction operations SubVec: PUBLIC PROC[h: Handle, firstIndex, lastIndex: NAT] RETURNS[ans: Handle] = {length: NAT ← (IF h = NIL THEN 0 ELSE h.length); IF lastIndex < firstIndex OR h = NIL OR lastIndex >= h.length THEN ERROR LengthFault[h, length]; length ← lastIndex - firstIndex + 1; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h.elements[firstIndex + i] ENDLOOP}; ConCat: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: Handle] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF LOOPHOLE[LOOPHOLE[h1.length, CARDINAL] + LOOPHOLE[h2.length, CARDINAL], INTEGER] < 0 THEN ERROR LengthFault[NIL, 0]; -- overflow check length ← h1.length + h2.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..h1.length) DO ans.elements[i] ← h1.elements[i] ENDLOOP; FOR i: NAT IN [0..h2.length) DO ans.elements[h1.length + i] ← h2.elements[i] ENDLOOP}; -- h.elements[FixI[perms.elements[i]]] is put into ans.elements[i] -- e.g., Permute[h, SortOrder[h]] produces a sorted version of h Permute: PUBLIC PROC[h: Handle, perms: Handle] RETURNS[ans: Handle] = { length: NAT ← perms.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO x: NAT = Real.FixI[perms.elements[i]]; IF x >= h.length THEN ERROR LengthFault[h, x+1]; ans.elements[i] ← h.elements[x]; ENDLOOP; }; sortee: Handle; sortPred: SAFE PROC[x, y: REF ANY, data: REF ANY] RETURNS[BOOLEAN] = TRUSTED {i: NAT = LOOPHOLE--NARROW--[x, REF NAT]↑; j: NAT = LOOPHOLE--NARROW--[y, REF NAT]↑; RETURN[sortee.elements[i] < sortee.elements[j]]}; -- perms[i] is the index in h of the ith smallest element -- i.e. (h.elements[perms[i]] <= h.elements[perms[i+1]]) SortOrder: PUBLIC ENTRY PROC[h: Handle] RETURNS[perms: Handle] = {ENABLE UNWIND => NULL; length: NAT ← h.length; q: PriorityQueue.Ref; sortee ← h; q ← PriorityQueue.Predict[pred: sortPred, size: h.length]; perms ← vecQZone.NEW[Object[length]]; FOR i: NAT IN [0..h.length) DO PriorityQueue.Insert[q, vecQZone.NEW[NAT ← i]] ENDLOOP; FOR i: NAT IN [0..h.length) DO perms.elements[i] ← NARROW[PriorityQueue.Remove[q], REF NAT]↑ ENDLOOP; IF NOT PriorityQueue.Empty[q] THEN ERROR; }; -- element-by-element operations Add: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: Handle] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF h1.length # h2.length THEN ERROR LengthFault[h2, h1.length]; length ← h1.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h1.elements[i] + h2.elements[i] ENDLOOP}; Subtract: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: Handle] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF h1.length # h2.length THEN ERROR LengthFault[h2, h1.length]; length ← h1.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h1.elements[i] - h2.elements[i] ENDLOOP}; Multiply: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: Handle] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF h1.length # h2.length THEN ERROR LengthFault[h2, h1.length]; length ← h1.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h1.elements[i] * h2.elements[i] ENDLOOP}; Divide: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: Handle] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF h1.length # h2.length THEN ERROR LengthFault[h2, h1.length]; length ← h1.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h1.elements[i] / h2.elements[i] ENDLOOP}; DotProduct: PUBLIC PROC[h1, h2: Handle] RETURNS[ans: REAL] = { length: NAT; IF h1 = NIL OR h2 = NIL THEN ERROR LengthFault[NIL, 0]; IF h1.length # h2.length THEN ERROR LengthFault[h2, h1.length]; length ← h1.length; ans ← 0.0; FOR i: NAT IN [0..length) DO ans ← ans + h1.elements[i] * h2.elements[i] ENDLOOP}; -- scalar element-by-element operations ScalarAdd: PUBLIC PROC[h: Handle, s: REAL] RETURNS[ans: Handle] = { length: NAT; IF h = NIL THEN RETURN[NIL]; length ← h.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h.elements[i] + s ENDLOOP}; ScalarSubtract: PUBLIC PROC[h: Handle, s: REAL] RETURNS[ans: Handle] = { length: NAT; IF h = NIL THEN RETURN[NIL]; length ← h.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h.elements[i] - s ENDLOOP}; ScalarMultiply: PUBLIC PROC[h: Handle, s: REAL] RETURNS[ans: Handle] = { length: NAT; IF h = NIL THEN RETURN[NIL]; length ← h.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h.elements[i] * s ENDLOOP}; ScalarDivide: PUBLIC PROC[h: Handle, s: REAL] RETURNS[ans: Handle] = { length: NAT; IF h = NIL THEN RETURN[NIL]; length ← h.length; ans ← vecZone.NEW[Object[length]]; FOR i: NAT IN [0..length) DO ans.elements[i] ← h.elements[i] / s ENDLOOP}; Equal: PUBLIC PROC[h1, h2: Handle] RETURNS[BOOLEAN] = { IF h1 = NIL OR h2 = NIL THEN RETURN[h1 = h2]; FOR i: NAT IN [0..h1.length) DO IF NOT almost[h1.elements[i], h2.elements[i]] THEN RETURN[FALSE] ENDLOOP; RETURN[TRUE]}; almost: PROC[p, q: REAL] RETURNS[BOOLEAN] = INLINE {RETURN[MAX[p, q] = 0.0 OR ABS[p - q]/MAX[p, q] < 0.00001]}; }.