GENERIC MODULE TestVector(Vec) (* EXPORTS Main *); (* Tests instances of the "Vector" interface. WHERE Vec = Vector(VRep) *) IMPORT Wr, Fmt, Thread, CPUTime; FROM Vec IMPORT Get, Set; FROM Stdio IMPORT stderr; CONST N = Vec.N; Microsecond = 1.0d-6; TYPE T = Vec.T; ElemT = Vec.ElemT; PROCEDURE DoIt() = VAR tare, time: LONGREAL; nCalls: CARDINAL; <* FATAL Wr.Failure, Thread.Alerted *> BEGIN FOR s := 0 TO LAST(TestTable) DO WITH t = TestTable[s] DO (* Check it: *) Wr.PutText(stderr, "--- testing " & t.name & " -------------------------\n"); Wr.PutText(stderr, "Consistency checks...\n"); EVAL t.proc(t.nCheck, skip := FALSE, check := TRUE); (* Clock empty loop: *) Wr.PutText(stderr, "Calibrating clock...\n"); tare := CPUTime.Now(); EVAL t.proc(t.nClock, skip := TRUE, check := FALSE); tare := CPUTime.Now() - tare; (* Clock full loop: *) Wr.PutText(stderr, "Computing cost (nCalls = " & Fmt.Int(t.nClock) & ")...\n"); time := CPUTime.Now(); nCalls := t.proc(t.nClock, skip := FALSE, check := FALSE); time := CPUTime.Now() - time; WITH fn = FLOAT(nCalls, LONGREAL), ucost = (time - tare)/fn, ucfmt = Fmt.LongReal(ucost/Microsecond, prec := 1, style := Fmt.Style.Fix), utare = tare/fn, utfmt = Fmt.LongReal(utare/Microsecond, prec := 1, style := Fmt.Style.Fix) DO Wr.PutText(stderr, " cost = " & ucfmt & " usec (tare = " & utfmt & " usecs)\n" ); END END END END DoIt; TYPE TTEntry = RECORD proc: TestProc; name: TEXT; nCheck: CARDINAL; nClock: CARDINAL END; TYPE TestProc = PROCEDURE (nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL; (* Should perform some operation aproximately "nCalls" times. If "check", should also check the results. If "skip", should do everything except the call itself. In any case, should return the actual number of calls done (or skipped), for timing analysis. *) CONST TestTable = ARRAY OF TTEntry{ TTEntry{TestGet, "Get", 1, 200000}, TTEntry{TestSet, "Set", 1, 200000}, TTEntry{TestZero, "Zero", 1, 200000}, TTEntry{TestAll, "All", 1, 200000}, TTEntry{TestAxis, "Axis", 1, 200000}, TTEntry{TestAdd, "Add", 1, 200000}, TTEntry{TestSub, "Sub", 1, 200000}, TTEntry{TestNeg, "Neg", 1, 200000}, TTEntry{TestScale, "Scale", 1, 200000}, TTEntry{TestWeigh, "Weigh", 1, 200000}, TTEntry{TestMix, "Mix", 1, 200000} (* , TTEntry{TestNorm, "Norm", 1, 200000}, TTEntry{TestLInfNorm, "LInfNorm", 1, 200000}, TTEntry{TestNormSqr, "NormSqr", 1, 200000}, TTEntry{TestDist, "Dist", 1, 200000}, TTEntry{TestDistSqr, "DistSqr", 1, 200000}, TTEntry{TestLInfDist, "LInfDist", 1, 200000}, TTEntry{TestDir, "Dir", 1, 200000}, TTEntry{TestLInfDir, "LInfDir", 1, 200000}, TTEntry{TestDot, "Dot", 1, 200000}, TTEntry{TestProject, "Project", 1, 200000}, TTEntry{TestOrthize, "Orthize", 1, 200000}, TTEntry{TestToReal, "ToReal", 1, 200000}, TTEntry{TestToLongReal, "ToLongReal", 1, 200000}, TTEntry{TestFromReal, "FromReal", 1, 200000}, TTEntry{TestFromLongReal, "FromLongReal", 1, 200000}, TTEntry{TestURandom, "URandom", 1, 200000}, TTEntry{TestNRandom, "NRandom", 1, 200000}, TTEntry{TestPrint, "Print", 1, 200000}, TTEntry{TestToText, "ToText", 1, 200000} *) }; PROCEDURE TestGet(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR z: Vec.T; r: LONGREAL; BEGIN FOR i := 0 TO N-1 DO Set(z, i, FLOAT(i, LONGREAL)) END; WITH nLoop = nCalls DIV N DO FOR k := 0 TO nLoop-1 DO FOR i := 0 TO N-1 DO IF NOT skip THEN r := Vec.Get(z, i) END; IF check THEN <* ASSERT r = FLOAT(i, LONGREAL) *> END END END; RETURN nLoop*N END END TestGet; PROCEDURE TestSet(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR z: Vec.T; r: LONGREAL; BEGIN z := Vec.Zero(); WITH nLoop = nCalls DIV N DO FOR k := 0 TO nLoop-1 DO FOR i := 0 TO N-1 DO r := FLOAT(k + i, LONGREAL); IF NOT skip THEN Vec.Set(z, i, r) END; IF check THEN <* ASSERT Vec.Get(z, i) = r *> END END END; RETURN nLoop*N END END TestSet; PROCEDURE TestZero(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR z: Vec.T; BEGIN FOR k := 0 TO nCalls-1 DO IF NOT skip THEN z := Vec.Zero() END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Vec.Get(z, i) = 0.0d0 *> END END END; RETURN nCalls; END TestZero; PROCEDURE TestAll(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR z: Vec.T; r: LONGREAL; BEGIN FOR k := 0 TO nCalls-1 DO r := FLOAT(k, LONGREAL); IF NOT skip THEN z := Vec.All(r) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Vec.Get(z, i) = r *> END END END; RETURN nCalls; END TestAll; PROCEDURE TestAxis(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR z: Vec.T; BEGIN WITH nLoop = nCalls DIV N DO FOR k := 0 TO nLoop-1 DO FOR i := 0 TO N-1 DO IF NOT skip THEN z := Vec.Axis(i) END; IF check THEN FOR j := 0 TO N-1 DO IF i = j THEN <* ASSERT Get(z, j) = 1.0d0 *> ELSE <* ASSERT Get(z, j) = 0.0d0 *> END END END END END; RETURN nLoop*N END END TestAxis; PROCEDURE TestAdd(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, b, c: Vec.T; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); Set(b, i, FLOAT(100-10*i, LONGREAL)); END; FOR k := 0 TO nCalls-1 DO IF NOT skip THEN c := Vec.Add(a, b) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = FLOAT(100-9*i, LONGREAL) *> END END END; RETURN nCalls END TestAdd; PROCEDURE TestSub(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, b, c: Vec.T; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); Set(b, i, FLOAT(100-10*i, LONGREAL)); END; FOR k := 0 TO nCalls-1 DO IF NOT skip THEN c := Vec.Sub(a, b) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = FLOAT(-100+11*i, LONGREAL) *> END END END; RETURN nCalls END TestSub; PROCEDURE TestNeg(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, c: Vec.T; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); END; FOR k := 0 TO nCalls-1 DO IF NOT skip THEN c := Vec.Neg(a) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = FLOAT(-i, LONGREAL) *> END END END; RETURN nCalls END TestNeg; PROCEDURE TestScale(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, c: Vec.T; r: LONGREAL; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); END; FOR k := 0 TO nCalls-1 DO r := FLOAT(k, LONGREAL); IF NOT skip THEN c := Vec.Scale(r, a) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = FLOAT(k, LONGREAL)*FLOAT(i, LONGREAL) *> END END END; RETURN nCalls END TestScale; PROCEDURE TestWeigh(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, c: Vec.T; b: ARRAY [0..N-1] OF LONGREAL; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); b[i] := FLOAT(N-i, LONGREAL); END; FOR k := 0 TO nCalls-1 DO IF NOT skip THEN c := Vec.Weigh(b, a) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = FLOAT(i, LONGREAL)*FLOAT(N-i, LONGREAL) *> END END END; RETURN nCalls END TestWeigh; PROCEDURE TestMix(nCalls: CARDINAL; check, skip: BOOLEAN): CARDINAL = VAR a, b, c: Vec.T; r, s: LONGREAL; BEGIN FOR i := 0 TO N-1 DO Set(a, i, FLOAT(i, LONGREAL)); Set(b, i, FLOAT(N-i, LONGREAL)); END; FOR k := 0 TO nCalls-1 DO r := FLOAT(k, LONGREAL); s := FLOAT(k-3, LONGREAL); IF NOT skip THEN c := Vec.Mix(r, a, s, b) END; IF check THEN FOR i := 0 TO N-1 DO <* ASSERT Get(c, i) = + FLOAT(k, LONGREAL)*FLOAT(i, LONGREAL) + FLOAT(k-3, LONGREAL)*FLOAT(N-i, LONGREAL) *> END END END; RETURN nCalls END TestMix; BEGIN DoIt() END TestVector.