actually I do not see your approach to be "easy" at
all.
So please can you line out how the short sample I lined
out should look like ?
I'll give you the public interface to the entire library
instead.
With that you can allocate, initialise, introspect and
operate on arbitrarily sized matrices.
DEFINITION MODULE Matrix;
IMPORT Vector;
FROM Vector IMPORT VectorT;
TYPE Matrix; (* OPAQUE *)
TYPE MatrixT = Matrix; (* for unqualified use *)
(* allocator, passes back null matrix *)
PROCEDURE New ( VAR m : Matrix; rows, columns : CARDINAL
);
(* introspection *)
PROCEDURE rowCount ( m : Matrix ) : CARDINAL;
PROCEDURE columnCount ( m : Matrix ) : CARDINAL;
PROCEDURE isInvertible ( m : Matrix ) : BOOLEAN;
(* constructors *)
PROCEDURE NewWithRows ( VAR m : Matrix; rowValues : ARRAY
OF VectorT );
PROCEDURE NewWithColumns ( VAR m : Matrix; colValues :
ARRAY OF VectorT );
(* mutators *)
PROCEDURE StoreValue ( m : Matrix; row, col : CARDINAL;
value : REAL );
PROCEDURE StoreRow ( m : Matrix; rowIndex : CARDINAL;
rowValues : ARRAY OF VectorT );
PROCEDURE StoreColumn ( m : Matrix; colIndex :
CARDINAL; colValues : ARRAY OF VectorT );
(* accessors *)
PROCEDURE value ( m : Matrix; row, col : CARDINAL ) :
REAL;
PROCEDURE row ( m : Matrix; rowIndex : CARDINAL ) :
VectorT;
PROCEDURE column ( m : Matrix; colIndex : CARDINAL ) :
Vector T;
(* operations *)
PROCEDURE eq ( m1, m2 : Matrix ) : BOOLEAN;
PROCEDURE sum ( m1, m2 : Matrix ) : Matrix;
PROCEDURE diff ( m1, m2 : Matrix ) : Matrix;
PROCEDURE prod ( m1, m2 : Matrix ) : Matrix;
PROCEDURE scalarProd ( m : Matrix; scalar : REAL ) :
Matrix;
PROCEDURE vectorProd ( m : Matrix; vector : VectorT ) :
VectorT;
PROCEDURE inverse ( m : Matrix ) : Matrix;
PROCEDURE transpose ( m : Matrix ) : Matrix;
(* destructor, deallocates and passes back NIL *)
PROCEDURE Release ( VAR m : Matrix );
END Matrix.
The Vector type module follows the same pattern, so I
omitted it.
I believe you can do the implementation for this
yourself, so I omitted that, too.
Note that you can implement this in PIM and ISO without
the need for any additional features. However, since neither
PIM nor ISO provide any facility to declare a record field
of indeterminate size, you need to use an ADDRESS field and
then use address arithmetic to access the individual values.
TYPE Matrix = RECORD
rows, columns : CARDINAL;
capacity : LONGCARD;
data : ADDRESS
END; (* Matrix *)
Doing the address arithmetic will look very messy and
represents plenty of opportunity for error. In this way it
is even less safe than doing it in C. But it can be done and
the unholy mess is hidden in the implementation module. Once
you've got it working, you will only ever use the public
interface.
By contrast, with the facility of records with
indeterminate fields that I described does not rely on
address arithmetic, it allows the use of array subscripts to
address the values of the array field, clean and safe, as it
should be in Modula-2.
(* type declaration in implementation module *)
TYPE Matrix = POINTER TO RECORD
rows, columns : CARDINAL
+ data : ARRAY capacity OF REAL
END; (* Matrix *)
I hope this clarifies.
regards
benjamin