123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- (* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
- (* Version 1, Update 2 *)
- MODULE Array2dInt; (**AUTHOR "adf, fof"; PURPOSE "Basic operations on type ARRAY OF ARRAY OF Int **)
- IMPORT SYSTEM, Array1dBytes, NbrInt, NbrRe, ArrayXd := ArrayXdInt, Array1d := Array1dInt, DataErrors;
- TYPE
- Value* = ArrayXd.Value; RealValue* = NbrRe.Real;
- Array* = POINTER TO ARRAY OF ARRAY OF Value;
- Index* = NbrInt.Integer;
- PROCEDURE Copy*( VAR src: ARRAY OF ARRAY OF Value; VAR dest: ARRAY OF ARRAY OF Value; srcx, srcy, destx, desty, w, h: Index );
- (** ccordinates: A[y,x] *)
- VAR y: Index;
- BEGIN
- Array1dBytes.RangeCheck2( srcx, srcy, w, h, LEN( src[0] ), LEN( src ) );
- Array1dBytes.RangeCheck2( destx, desty, w, h, LEN( dest[0] ), LEN( dest ) );
- IF (ADDRESSOF( src[0] ) = ADDRESSOF( dest[0] )) (* same array *) & (srcy < desty) THEN (*reverse copy order *)
- y := h - 1;
- WHILE (y >= 0) DO Array1d.Copy( src[srcy + y], dest[desty + y], srcx, destx, w ); DEC( y ) END;
- ELSE
- y := 0;
- WHILE (y < h) DO Array1d.Copy( src[srcy + y], dest[desty + y], srcx, destx, w ); INC( y ); END;
- END;
- END Copy;
- PROCEDURE Fill*( val: Value; VAR res: ARRAY OF ARRAY OF Value; x, y, w, h: Index );
- VAR i: Index;
- BEGIN
- Array1dBytes.RangeCheck2( x, y, w, h, LEN( res[0] ), LEN( res ) );
- i := 0;
- WHILE (i < h) DO Array1d.Fill( val, res[i + y], x, w ); INC( i ); END;
- END Fill;
- PROCEDURE MinMax*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index; VAR min, max: Value;
- VAR minx, miny, maxx, maxy: Index );
- VAR cmin, cmax: Value; cminpos, cmaxpos, i: Index;
- BEGIN
- Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
- min := s[y, x]; max := s[y, x]; minx := x; miny := y; maxx := x; maxy := y;
- FOR i := y TO y + h - 1 DO
- Array1d.MinMax( s[i], x, w, cmin, cmax, cminpos, cmaxpos );
- IF cmin < min THEN min := cmin; minx := cminpos; miny := i; END;
- IF cmax > max THEN max := cmax; maxx := cmaxpos; maxy := i; END
- END
- END MinMax;
- PROCEDURE kSmallest*( k: Index; VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index ): Value;
- (** does not modify S*)
- VAR values: ArrayXd.Array1; i: Index;
- BEGIN
- Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
- NEW( values, w * h );
- FOR i := y TO y + h - 1 DO Array1d.Copy( s[i], values^, x, i * w, w ); END;
- RETURN Array1d.kSmallestModify( k, values^, w * h )
- END kSmallest;
- PROCEDURE Median*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index ): Value;
- BEGIN
- RETURN kSmallest( w * h DIV 2, s, x, y, w, h )
- END Median;
- PROCEDURE MeanSsq*( VAR s: ARRAY OF ARRAY OF Value; x, y, w, h: Index; VAR mean, ssq: RealValue );
- (* mean and ssq distance of mean by provisional means algorithm *)
- VAR d: RealValue; val: Value; i, j: Index;
- BEGIN
- Array1dBytes.RangeCheck2( x, y, w, h, LEN( s[0] ), LEN( s ) );
- mean := 0; ssq := 0;
- FOR i := 0 TO h - 1 DO
- FOR j := 0 TO w - 1 DO
- val := s[i + y, j + x]; d := val - mean; mean := mean + d / ((i * w + j) + 1); ssq := ssq + d * (val - mean);
- END
- END;
- END MeanSsq;
- PROCEDURE CopyRow*( y: Index; VAR s: ARRAY OF ARRAY OF Value; VAR res: ARRAY OF Value; srcoffset, destoffset, len: Index );
- BEGIN
- (* range check Array1d *)
- Array1d.Copy( s[y], res, srcoffset, destoffset, len );
- END CopyRow;
- PROCEDURE CopyCol*( x: Index; VAR s: ARRAY OF ARRAY OF Value; VAR res: ARRAY OF Value; srcoffset, destoffset, len: Index );
- BEGIN
- Array1dBytes.RangeCheck2( x, srcoffset, 1, len, LEN( s[0] ), LEN( s ) ); Array1dBytes.RangeCheck( destoffset, len, LEN( res ) );
- INC( len, srcoffset );
- WHILE (srcoffset < len) DO res[destoffset] := s[srcoffset, x]; INC( srcoffset ); INC( destoffset ); END;
- END CopyCol;
- PROCEDURE CopyToRow*( VAR s: ARRAY OF Value; y: Index; VAR res: ARRAY OF ARRAY OF Value;
- srcoffset, destoffset, len: Index );
- BEGIN
- (* asserts in Array1d *)
- Array1d.Copy( s, res[y], srcoffset, destoffset, len );
- END CopyToRow;
- PROCEDURE CopyToCol*( VAR s: ARRAY OF Value; x: Index; VAR res: ARRAY OF ARRAY OF Value; srcoffset, destoffset, len: Index );
- BEGIN
- Array1dBytes.RangeCheck2( x, destoffset, 1, len, LEN( res[0] ), LEN( res ) ); Array1dBytes.RangeCheck( srcoffset, len, LEN( s ) );
- INC( len, srcoffset );
- WHILE (srcoffset < len) DO res[destoffset, x] := s[srcoffset]; INC( srcoffset ); INC( destoffset ); END;
- END CopyToCol;
- PROCEDURE Row*( y: Index; VAR s: ARRAY OF ARRAY OF Value ): ArrayXd.Array1;
- VAR res: ArrayXd.Array1; len: Index;
- BEGIN
- len := LEN( s[0] ); NEW( res, len ); CopyRow( y, s, res^, 0, 0, len ); RETURN res;
- END Row;
- PROCEDURE Col*( x: Index; VAR s: ARRAY OF ARRAY OF Value ): ArrayXd.Array1;
- VAR res: ArrayXd.Array1; len: Index;
- BEGIN
- len := LEN( s ); NEW( res, len ); CopyCol( x, s, res^, 0, 0, len ); RETURN res;
- END Col;
- PROCEDURE Transposed*( VAR s: ARRAY OF ARRAY OF Value ): Array;
- VAR res: Array; x, y, w, h: Index;
- BEGIN
- h := LEN( s ); w := LEN( s[0] ); NEW( res, w, h );
- FOR y := 0 TO h - 1 DO
- FOR x := 0 TO w - 1 DO res[x, y] := s[y, x]; END;
- END;
- RETURN res;
- END Transposed;
- PROCEDURE SwapRows*( VAR s: ARRAY OF ARRAY OF Value; y1, y2: Index );
- VAR temp: Value; w, i: Index;
- BEGIN
- Array1dBytes.RangeCheck2( y1, y2, 0, 0, LEN( s ), LEN( s ) );
- w := LEN( s[0] );
- FOR i := 0 TO w - 1 DO temp := s[y1, i]; s[y1, i] := s[y2, i]; s[y2, i] := temp END
- END SwapRows;
- PROCEDURE SwapCols*( VAR s: ARRAY OF ARRAY OF Value; x1, x2: Index );
- VAR temp: Value; h, i: Index;
- BEGIN
- Array1dBytes.RangeCheck2( x1, x2, 0, 0, LEN( s[0] ), LEN( s[0] ) );
- h := LEN( s );
- FOR i := 0 TO h - 1 DO temp := s[i, x1]; s[i, x1] := s[i, x2]; s[i, x2] := temp END
- END SwapCols;
- (** Monadic Operator - does not overwrite the argument *)
- OPERATOR "-"*( x: Array ): Array;
- VAR i, k, cols, rows: Index; minus: Array;
- BEGIN
- IF x # NIL THEN
- rows := LEN( x, 0 ); cols := LEN( x, 1 ); NEW( minus, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO minus[i, k] := -x[i, k] END
- END
- ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
- END;
- RETURN minus
- END "-";
- OPERATOR ":="*( VAR l: Array; r: Value );
- BEGIN
- 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
- END ":=";
- OPERATOR ":="*( VAR l: Array; VAR r: ARRAY OF ARRAY OF Value );
- VAR i, k, cols, rows: Index;
- BEGIN
- rows := LEN( r, 0 ); cols := LEN( r, 1 );
- IF l = NIL THEN NEW( l, rows, cols )
- ELSIF (LEN( l, 0 ) # rows) OR (LEN( l, 1 ) # cols) THEN NEW( l, rows, cols )
- ELSE (* matrix l is properly dimensioned *)
- END;
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO l[i, k] := r[i, k] END
- END
- END ":=";
- (** Arithmetic. Operators do not overwrite the arguments. *)
- OPERATOR "+"*( l, r: Array ): Array;
- VAR i, k, cols, rows: Index; sum: Array;
- BEGIN
- IF (l # NIL ) & (r # NIL ) THEN
- IF (LEN( l, 0 ) = LEN( r, 0 )) & (LEN( l, 1 ) = LEN( r, 1 )) THEN
- rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( sum, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO sum[i, k] := l[i, k] + r[i, k] END
- END
- ELSE DataErrors.Error( "The sizes of the two supplied Array matrices were not equal." )
- END
- ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
- END;
- RETURN sum
- END "+";
- OPERATOR "-"*( l, r: Array ): Array;
- VAR i, k, cols, rows: Index; diff: Array;
- BEGIN
- IF (l # NIL ) & (r # NIL ) THEN
- IF (LEN( l, 0 ) = LEN( r, 0 )) & (LEN( l, 1 ) = LEN( r, 1 )) THEN
- rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( diff, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO diff[i, k] := l[i, k] - r[i, k] END
- END
- ELSE DataErrors.Error( "The sizes of the two supplied Array matrices were not equal." )
- END
- ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
- END;
- RETURN diff
- END "-";
- (** Array dot product *)
- OPERATOR "*"*( l, r: Array ): Array;
- (** Caution: Use brackets to ensure proper matrix multiplication when contracting three or more matrices,
- e.g., A*(B*C) is correct, whereas A*B*C is not. This is because matrix multiplician is from right to left;
- whereas, the Oberon programming languages multiplies from left to right. *)
- VAR i, j, k, cols, dummy, rows, sum: Index; dot: Array;
- BEGIN
- IF (l # NIL ) & (r # NIL ) THEN
- IF LEN( l, 1 ) = LEN( r, 0 ) THEN
- rows := LEN( l, 0 ); cols := LEN( r, 1 ); dummy := LEN( r, 0 ); NEW( dot, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR j := 0 TO cols - 1 DO
- sum := 0;
- FOR k := 0 TO dummy - 1 DO sum := sum + l[i, k] * r[k, j] END;
- dot[i, j] := sum
- END
- END
- ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,1) # LEN(r,0)." )
- END
- ELSE DataErrors.Error( "One or both of the two supplied Array matrices was NIL." )
- END;
- RETURN dot
- END "*";
- (** Array-Vector contraction, returns x = A v or x[i] = A[i, k] v[k] *)
- OPERATOR "*"*( l: Array; r: ArrayXd.Array1 ): ArrayXd.Array1;
- VAR i, k, dummy, rows, sum: Index; dot: ArrayXd.Array1;
- BEGIN
- IF (l # NIL ) & (r # NIL ) THEN
- IF LEN( l, 1 ) = LEN( r ) THEN
- rows := LEN( l, 0 ); dummy := LEN( l, 1 ); NEW( dot, rows );
- FOR i := 0 TO rows - 1 DO
- sum := 0;
- FOR k := 0 TO dummy - 1 DO sum := sum + l[i, k] * r[k] END;
- dot[i] := sum
- END
- ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,1) # LEN(r)." )
- END
- ELSE DataErrors.Error( "Either the Array matrix or Vector vector supplied was NIL." )
- END;
- RETURN dot
- END "*";
- (** Vector-Array contraction, returns x = ATv = vTA or x[i] = A[k, i] v[k] = v[k] A[k, i] *)
- OPERATOR "*"*( l: ArrayXd.Array1; r: Array ): ArrayXd.Array1;
- VAR i, k, cols, dummy, sum: Index; dot: ArrayXd.Array1;
- BEGIN
- IF (l # NIL ) & (r # NIL ) THEN
- IF LEN( l ) = LEN( r, 0 ) THEN
- cols := LEN( r, 1 ); dummy := LEN( r, 0 ); NEW( dot, cols );
- FOR i := 0 TO cols - 1 DO
- sum := 0;
- FOR k := 0 TO dummy - 1 DO sum := sum + l[k] * r[k, i] END;
- dot[i] := sum
- END
- ELSE DataErrors.Error( "The sizes were incompatible, i.e., LEN(l,0) # LEN(r)." )
- END
- ELSE DataErrors.Error( "Either the Vector vector or Array matrix supplied was NIL." )
- END;
- RETURN dot
- END "*";
- (** Scalar multiplication *)
- OPERATOR "*"*( l: Value; r: Array ): Array;
- VAR i, k, cols, rows: Index; prod: Array;
- BEGIN
- IF r # NIL THEN
- rows := LEN( r, 0 ); cols := LEN( r, 1 ); NEW( prod, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO prod[i, k] := l * r[i, k] END
- END
- ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
- END;
- RETURN prod
- END "*";
- OPERATOR "*"*( l: Array; r: Value ): Array;
- VAR i, k, cols, rows: Index; prod: Array;
- BEGIN
- IF l # NIL THEN
- rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( prod, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO prod[i, k] := l[i, k] * r END
- END
- ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
- END;
- RETURN prod
- END "*";
- (** Scalar division *)
- OPERATOR "DIV"*( l: Array; r: Value ): Array;
- VAR i, k, cols, rows: Index; div: Array;
- BEGIN
- IF l # NIL THEN
- IF r # 0 THEN
- rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( div, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO div[i, k] := l[i, k] DIV r END
- END
- ELSE DataErrors.Error( "Division by zero." )
- END
- ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
- END;
- RETURN div
- END "DIV";
- OPERATOR "MOD"*( l: Array; r: Value ): Array;
- VAR i, k, cols, rows: Index; mod: Array;
- BEGIN
- IF l # NIL THEN
- IF r # 0 THEN
- rows := LEN( l, 0 ); cols := LEN( l, 1 ); NEW( mod, rows, cols );
- FOR i := 0 TO rows - 1 DO
- FOR k := 0 TO cols - 1 DO mod[i, k] := l[i, k] MOD r END
- END
- ELSE DataErrors.Error( "Division by zero." )
- END
- ELSE DataErrors.Error( "The supplied Array matrix was NIL." )
- END;
- RETURN mod
- END "MOD";
- END Array2dInt.
|