Array2dInt.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. (* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
  2. (* Version 1, Update 2 *)
  3. MODULE Array2dInt; (**AUTHOR "adf, fof"; PURPOSE "Basic operations on type ARRAY OF ARRAY OF Int **)
  4. IMPORT SYSTEM, Array1dBytes, NbrInt, NbrRe, ArrayXd := ArrayXdInt, Array1d := Array1dInt, DataErrors;
  5. TYPE
  6. Value* = ArrayXd.Value; RealValue* = NbrRe.Real;
  7. Array* = POINTER TO ARRAY OF ARRAY OF Value;
  8. Index* = NbrInt.Integer;
  9. PROCEDURE Copy*( VAR src: ARRAY OF ARRAY OF Value; VAR dest: ARRAY OF ARRAY OF Value; srcx, srcy, destx, desty, w, h: Index );
  10. (** ccordinates: A[y,x] *)
  11. VAR y: Index;
  12. BEGIN
  13. Array1dBytes.RangeCheck2( srcx, srcy, w, h, LEN( src[0] ), LEN( src ) );
  14. Array1dBytes.RangeCheck2( destx, desty, w, h, LEN( dest[0] ), LEN( dest ) );
  15. IF (ADDRESSOF( src[0] ) = ADDRESSOF( dest[0] )) (* same array *) & (srcy < desty) THEN (*reverse copy order *)
  16. y := h - 1;
  17. WHILE (y >= 0) DO Array1d.Copy( src[srcy + y], dest[desty + y], srcx, destx, w ); DEC( y ) END;
  18. ELSE
  19. y := 0;
  20. WHILE (y < h) DO Array1d.Copy( src[srcy + y], dest[desty + y], srcx, destx, w ); INC( y ); END;
  21. END;
  22. END Copy;
  23. PROCEDURE Fill*( val: Value; VAR res: ARRAY OF ARRAY OF Value; x, y, w, h: Index );
  24. VAR i: Index;
  25. BEGIN
  26. Array1dBytes.RangeCheck2( x, y, w, h, LEN( res[0] ), LEN( res ) );
  27. i := 0;
  28. WHILE (i < h) DO Array1d.Fill( val, res[i + y], x, w ); INC( i ); END;
  29. END Fill;
  30. PROCEDURE MinMax*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index; VAR min, max: Value;
  31. VAR minx, miny, maxx, maxy: Index );
  32. VAR cmin, cmax: Value; cminpos, cmaxpos, i: Index;
  33. BEGIN
  34. Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
  35. min := s[y, x]; max := s[y, x]; minx := x; miny := y; maxx := x; maxy := y;
  36. FOR i := y TO y + h - 1 DO
  37. Array1d.MinMax( s[i], x, w, cmin, cmax, cminpos, cmaxpos );
  38. IF cmin < min THEN min := cmin; minx := cminpos; miny := i; END;
  39. IF cmax > max THEN max := cmax; maxx := cmaxpos; maxy := i; END
  40. END
  41. END MinMax;
  42. PROCEDURE kSmallest*( k: Index; VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index ): Value;
  43. (** does not modify S*)
  44. VAR values: ArrayXd.Array1; i: Index;
  45. BEGIN
  46. Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
  47. NEW( values, w * h );
  48. FOR i := y TO y + h - 1 DO Array1d.Copy( s[i], values^, x, i * w, w ); END;
  49. RETURN Array1d.kSmallestModify( k, values^, w * h )
  50. END kSmallest;
  51. PROCEDURE Median*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index ): Value;
  52. BEGIN
  53. RETURN kSmallest( w * h DIV 2, s, x, y, w, h )
  54. END Median;
  55. PROCEDURE MeanSsq*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index; VAR mean, ssq: RealValue );
  56. (* mean and ssq distance of mean by provisional means algorithm *)
  57. VAR d: RealValue; val: Value; i, j: Index;
  58. BEGIN
  59. Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
  60. mean := 0; ssq := 0;
  61. FOR i := 0 TO h - 1 DO
  62. FOR j := 0 TO w - 1 DO
  63. val := s[i + y, j + x]; d := val - mean; mean := mean + d / ((i * w + j) + 1); ssq := ssq + d * (val - mean);
  64. END
  65. END;
  66. END MeanSsq;
  67. PROCEDURE CopyRow*( y: Index; VAR s: ARRAY OF ARRAY OF Value; VAR res: ARRAY OF Value; srcoffset, destoffset, len: Index );
  68. BEGIN
  69. (* range check Array1d *)
  70. Array1d.Copy( s[y], res, srcoffset, destoffset, len );
  71. END CopyRow;
  72. PROCEDURE CopyCol*( x: Index; VAR s: ARRAY OF ARRAY OF Value; VAR res: ARRAY OF Value; srcoffset, destoffset, len: Index );
  73. BEGIN
  74. Array1dBytes.RangeCheck2( x, srcoffset, 1, len, LEN( s[0] ), LEN( s ) ); Array1dBytes.RangeCheck( destoffset, len, LEN( res ) );
  75. INC( len, srcoffset );
  76. WHILE (srcoffset < len) DO res[destoffset] := s[srcoffset, x]; INC( srcoffset ); INC( destoffset ); END;
  77. END CopyCol;
  78. PROCEDURE CopyToRow*( VAR s: ARRAY OF Value; y: Index; VAR res: ARRAY OF ARRAY OF Value;
  79. srcoffset, destoffset, len: Index );
  80. BEGIN
  81. (* asserts in Array1d *)
  82. Array1d.Copy( s, res[y], srcoffset, destoffset, len );
  83. END CopyToRow;
  84. PROCEDURE CopyToCol*( VAR s: ARRAY OF Value; x: Index; VAR res: ARRAY OF ARRAY OF Value; srcoffset, destoffset, len: Index );
  85. BEGIN
  86. Array1dBytes.RangeCheck2( x, destoffset, 1, len, LEN( res[0] ), LEN( res ) ); Array1dBytes.RangeCheck( srcoffset, len, LEN( s ) );
  87. INC( len, srcoffset );
  88. WHILE (srcoffset < len) DO res[destoffset, x] := s[srcoffset]; INC( srcoffset ); INC( destoffset ); END;
  89. END CopyToCol;
  90. PROCEDURE Row*( y: Index; VAR s: ARRAY OF ARRAY OF Value ): ArrayXd.Array1;
  91. VAR res: ArrayXd.Array1; len: Index;
  92. BEGIN
  93. len := LEN( s[0] ); NEW( res, len ); CopyRow( y, s, res^, 0, 0, len ); RETURN res;
  94. END Row;
  95. PROCEDURE Col*( x: Index; VAR s: ARRAY OF ARRAY OF Value ): ArrayXd.Array1;
  96. VAR res: ArrayXd.Array1; len: Index;
  97. BEGIN
  98. len := LEN( s ); NEW( res, len ); CopyCol( x, s, res^, 0, 0, len ); RETURN res;
  99. END Col;
  100. PROCEDURE Transposed*( VAR s: ARRAY OF ARRAY OF Value ): Array;
  101. VAR res: Array; x, y, w, h: Index;
  102. BEGIN
  103. h := LEN( s ); w := LEN( s[0] ); NEW( res, w, h );
  104. FOR y := 0 TO h - 1 DO
  105. FOR x := 0 TO w - 1 DO res[x, y] := s[y, x]; END;
  106. END;
  107. RETURN res;
  108. END Transposed;
  109. PROCEDURE SwapRows*( VAR s: ARRAY OF ARRAY OF Value; y1, y2: Index );
  110. VAR temp: Value; w, i: Index;
  111. BEGIN
  112. Array1dBytes.RangeCheck2( y1, y2, 0, 0, LEN( s ), LEN( s ) );
  113. w := LEN( s[0] );
  114. FOR i := 0 TO w - 1 DO temp := s[y1, i]; s[y1, i] := s[y2, i]; s[y2, i] := temp END
  115. END SwapRows;
  116. PROCEDURE SwapCols*( VAR s: ARRAY OF ARRAY OF Value; x1, x2: Index );
  117. VAR temp: Value; h, i: Index;
  118. BEGIN
  119. Array1dBytes.RangeCheck2( x1, x2, 0, 0, LEN( s[0] ), LEN( s[0] ) );
  120. h := LEN( s );
  121. FOR i := 0 TO h - 1 DO temp := s[i, x1]; s[i, x1] := s[i, x2]; s[i, x2] := temp END
  122. END SwapCols;
  123. (** Monadic Operator - does not overwrite the argument *)
  124. OPERATOR "-"*( x: Array ): Array;
  125. VAR i, k, cols, rows: Index; minus: Array;
  126. BEGIN
  127. IF x # NIL THEN
  128. rows := LEN( x, 0 ); cols := LEN( x, 1 ); NEW( minus, rows, cols );
  129. FOR i := 0 TO rows - 1 DO
  130. FOR k := 0 TO cols - 1 DO minus[i, k] := -x[i, k] END
  131. END
  132. ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
  133. END;
  134. RETURN minus
  135. END "-";
  136. OPERATOR ":="*( VAR l: Array; r: Value );
  137. BEGIN
  138. IF l # NIL THEN Fill( r, l^, 0, 0, LEN( l[0] ), LEN( l ) ); ELSE DataErrors.Error( "The supplied instance of Array2dInt.Array was NIL." ) END
  139. END ":=";
  140. OPERATOR ":="*( VAR l: Array; VAR r: ARRAY OF ARRAY OF Value );
  141. VAR i, k, cols, rows: Index;
  142. BEGIN
  143. rows := LEN( r, 0 ); cols := LEN( r, 1 );
  144. IF l = NIL THEN NEW( l, rows, cols )
  145. ELSIF (LEN( l, 0 ) # rows) OR (LEN( l, 1 ) # cols) THEN NEW( l, rows, cols )
  146. ELSE (* matrix l is properly dimensioned *)
  147. END;
  148. FOR i := 0 TO rows - 1 DO
  149. FOR k := 0 TO cols - 1 DO l[i, k] := r[i, k] END
  150. END
  151. END ":=";
  152. (** Arithmetic. Operators do not overwrite the arguments. *)
  153. OPERATOR "+"*( l, r: Array ): Array;
  154. VAR i, k, cols, rows: Index; sum: Array;
  155. BEGIN
  156. IF (l # NIL ) & (r # NIL ) THEN
  157. IF (LEN( l, 0 ) = LEN( r, 0 )) & (LEN( l, 1 ) = LEN( r, 1 )) THEN
  158. rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( sum, rows, cols );
  159. FOR i := 0 TO rows - 1 DO
  160. FOR k := 0 TO cols - 1 DO sum[i, k] := l[i, k] + r[i, k] END
  161. END
  162. ELSE DataErrors.Error( "The sizes of the two supplied Array matrices were not equal." )
  163. END
  164. ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
  165. END;
  166. RETURN sum
  167. END "+";
  168. OPERATOR "-"*( l, r: Array ): Array;
  169. VAR i, k, cols, rows: Index; diff: Array;
  170. BEGIN
  171. IF (l # NIL ) & (r # NIL ) THEN
  172. IF (LEN( l, 0 ) = LEN( r, 0 )) & (LEN( l, 1 ) = LEN( r, 1 )) THEN
  173. rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( diff, rows, cols );
  174. FOR i := 0 TO rows - 1 DO
  175. FOR k := 0 TO cols - 1 DO diff[i, k] := l[i, k] - r[i, k] END
  176. END
  177. ELSE DataErrors.Error( "The sizes of the two supplied Array matrices were not equal." )
  178. END
  179. ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
  180. END;
  181. RETURN diff
  182. END "-";
  183. (** Array dot product *)
  184. OPERATOR "*"*( l, r: Array ): Array;
  185. (** Caution: Use brackets to ensure proper matrix multiplication when contracting three or more matrices,
  186. e.g., A*(B*C) is correct, whereas A*B*C is not. This is because matrix multiplician is from right to left;
  187. whereas, the Oberon programming languages multiplies from left to right. *)
  188. VAR i, j, k, cols, dummy, rows, sum: Index; dot: Array;
  189. BEGIN
  190. IF (l # NIL ) & (r # NIL ) THEN
  191. IF LEN( l, 1 ) = LEN( r, 0 ) THEN
  192. rows := LEN( l, 0 ); cols := LEN( r, 1 ); dummy := LEN( r, 0 ); NEW( dot, rows, cols );
  193. FOR i := 0 TO rows - 1 DO
  194. FOR j := 0 TO cols - 1 DO
  195. sum := 0;
  196. FOR k := 0 TO dummy - 1 DO sum := sum + l[i, k] * r[k, j] END;
  197. dot[i, j] := sum
  198. END
  199. END
  200. ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,1) # LEN(r,0)." )
  201. END
  202. ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
  203. END;
  204. RETURN dot
  205. END "*";
  206. (** Array-Vector contraction, returns x = A v or x[i] = A[i, k] v[k] *)
  207. OPERATOR "*"*( l: Array; r: ArrayXd.Array1 ): ArrayXd.Array1;
  208. VAR i, k, dummy, rows, sum: Index; dot: ArrayXd.Array1;
  209. BEGIN
  210. IF (l # NIL ) & (r # NIL ) THEN
  211. IF LEN( l, 1 ) = LEN( r ) THEN
  212. rows := LEN( l, 0 ); dummy := LEN( l, 1 ); NEW( dot, rows );
  213. FOR i := 0 TO rows - 1 DO
  214. sum := 0;
  215. FOR k := 0 TO dummy - 1 DO sum := sum + l[i, k] * r[k] END;
  216. dot[i] := sum
  217. END
  218. ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,1) # LEN(r)." )
  219. END
  220. ELSE DataErrors.Error( "Either the Array matrix or Vector vector supplied was NIL." )
  221. END;
  222. RETURN dot
  223. END "*";
  224. (** Vector-Array contraction, returns x = ATv = vTA or x[i] = A[k, i] v[k] = v[k] A[k, i] *)
  225. OPERATOR "*"*( l: ArrayXd.Array1; r: Array ): ArrayXd.Array1;
  226. VAR i, k, cols, dummy, sum: Index; dot: ArrayXd.Array1;
  227. BEGIN
  228. IF (l # NIL ) & (r # NIL ) THEN
  229. IF LEN( l ) = LEN( r, 0 ) THEN
  230. cols := LEN( r, 1 ); dummy := LEN( r, 0 ); NEW( dot, cols );
  231. FOR i := 0 TO cols - 1 DO
  232. sum := 0;
  233. FOR k := 0 TO dummy - 1 DO sum := sum + l[k] * r[k, i] END;
  234. dot[i] := sum
  235. END
  236. ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,0) # LEN(r)." )
  237. END
  238. ELSE DataErrors.Error( "Either the Vector vector or Array matrix supplied was NIL." )
  239. END;
  240. RETURN dot
  241. END "*";
  242. (** Scalar multiplication *)
  243. OPERATOR "*"*( l: Value; r: Array ): Array;
  244. VAR i, k, cols, rows: Index; prod: Array;
  245. BEGIN
  246. IF r # NIL THEN
  247. rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( prod, rows, cols );
  248. FOR i := 0 TO rows - 1 DO
  249. FOR k := 0 TO cols - 1 DO prod[i, k] := l * r[i, k] END
  250. END
  251. ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
  252. END;
  253. RETURN prod
  254. END "*";
  255. OPERATOR "*"*( l: Array; r: Value ): Array;
  256. VAR i, k, cols, rows: Index; prod: Array;
  257. BEGIN
  258. IF l # NIL THEN
  259. rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( prod, rows, cols );
  260. FOR i := 0 TO rows - 1 DO
  261. FOR k := 0 TO cols - 1 DO prod[i, k] := l[i, k] * r END
  262. END
  263. ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
  264. END;
  265. RETURN prod
  266. END "*";
  267. (** Scalar division *)
  268. OPERATOR "DIV"*( l: Array; r: Value ): Array;
  269. VAR i, k, cols, rows: Index; div: Array;
  270. BEGIN
  271. IF l # NIL THEN
  272. IF r # 0 THEN
  273. rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( div, rows, cols );
  274. FOR i := 0 TO rows - 1 DO
  275. FOR k := 0 TO cols - 1 DO div[i, k] := l[i, k] DIV r END
  276. END
  277. ELSE DataErrors.Error( "Division by zero." )
  278. END
  279. ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
  280. END;
  281. RETURN div
  282. END "DIV";
  283. OPERATOR "MOD"*( l: Array; r: Value ): Array;
  284. VAR i, k, cols, rows: Index; mod: Array;
  285. BEGIN
  286. IF l # NIL THEN
  287. IF r # 0 THEN
  288. rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( mod, rows, cols );
  289. FOR i := 0 TO rows - 1 DO
  290. FOR k := 0 TO cols - 1 DO mod[i, k] := l[i, k] MOD r END
  291. END
  292. ELSE DataErrors.Error( "Division by zero." )
  293. END
  294. ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
  295. END;
  296. RETURN mod
  297. END "MOD";
  298. END Array2dInt.