RealVecImpl.mesa, an implementation for dealing with vectors of real numbers
Last Modified On December 16, 1983 2:00 pm By Paul Rovner
DIRECTORY
PriorityQueue USING[Ref, Predict, Insert, Empty, Remove],
Real USING[FixI, RoundI],
RealVec USING[Handle, Object];
RealVecImpl: MONITOR -- protects sortee
IMPORTS PriorityQueue, Real
EXPORTS RealVec =
{ OPEN RealVec;
PUBLIC SIGNALS
LengthFault: PUBLIC ERROR[vec: Handle, expectedLength: NAT] = CODE;
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 ← 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 ← 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 ← 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 ← 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 ← 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 ← 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 ← NEW[Object[length]];
FOR i: NAT IN [0..h.length)
DO PriorityQueue.Insert[q, 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 ← 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 ← 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 ← 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 ← 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 ← 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 ← 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 ← 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 ← 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]};
}.