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]};
}.