|
From: | Michael Riedl |
Subject: | Re: Dynamic mutidimensional arrays |
Date: | Wed, 5 Apr 2023 09:40:28 +0200 |
User-agent: | Mozilla/5.0 (X11; Linux i686; rv:102.0) Gecko/20100101 Thunderbird/102.9.0 |
Hallo Andreas,
thanks for the feedback, parts of my answer below in your text.
I am fully aware about (most of) the current features of the language (at least I hope so :-)
For me there is a inconsistency in the ISO approach of
mutidimensional array ...
- you can use 1-dimensional open array parameters and you can allocate the space for them in the calling program or procedure
- we have multiply dimensional open array parameters for
procedures
- but we can only use fixed sized multiple-dimensional arrays to hand over
- even in case of 1-dimensional arrays we cannot use "HIGH" to
check if the dimension of the actual parameter handed over is
sufficient (at least if I do not want to make everything based on
records having a data field and a size field.
Below a short sample (which, for the reasons give about, is
sub-optimal).
With "my" approach one could hand over proper "high" parameters to the procedure called for 1 or multi-dimensional fields - something offering the possibility to procedure code better able to catch failures ...
It might have a reason why Niklaus Wirth introduced that in
Oberon and other languages also went that way ...
Gruß / Regads
Michael
MODULE DynArray1D;
FROM Storage IMPORT ALLOCATE,DEALLOCATE;
IMPORT STextIO;
IMPORT SWholeIO;
(* Here I assume that INTEGER and SYSTEM.ADDRESS have the same
size, *)
(* but this is not essential for this
sample *)
CONST MaxV = MAX(INTEGER) DIV SIZE(REAL);
TYPE PVECTOR = POINTER TO ARRAY [0..MaxV-1] OF REAL;
PROCEDURE AddVector( N : CARDINAL;
VAR A : ARRAY OF REAL; (* in *)
VAR B : ARRAY OF REAL; (* in *)
VAR C : ARRAY OF REAL); (* out *)
(* add vector A abd B and return the result in vector
C *)
VAR i : CARDINAL;
BEGIN
IF (HIGH(C) < N-1) THEN
(* Some error handling code ... *)
(* but : actually HIGH(C) will be MaxV-1 and NOT N *)
STextIO.WriteLn;
STextIO.WriteString(" HIGH(C) = ");
SWholeIO.WriteCard(HIGH(C),1);
STextIO.WriteLn;
STextIO.WriteString(" N = ");
SWholeIO.WriteCard(N,1);
STextIO.WriteLn;
STextIO.WriteString(" Error *** HIGH(C) < N-1
(AddVector) ***");
STextIO.WriteLn;
HALT;
END;
FOR i:=0 TO N-1 DO C[i]:= A[i] + B[i]; END;
END AddVector;
VAR A,B,C : PVECTOR;
N,i : CARDINAL;
BEGIN
N := 7; (* suppose N is read in from some source ... *)
ALLOCATE(A,N*SIZE(REAL));
ALLOCATE(B,N*SIZE(REAL));
ALLOCATE(C,N*SIZE(REAL));
FOR i:=0 TO N-1 DO (* some code to initialize A,B ... *)
A^[i] := VAL(REAL,i);
B^[i] := VAL(REAL,2*i);
END;
AddVector(N,A^,B^,C^);
(* Some code to output the result C ... *)
DEALLOCATE(A,N*SIZE(REAL));
DEALLOCATE(B,N*SIZE(REAL));
DEALLOCATE(C,N*SIZE(REAL));
END DynArray1D.
Dear Michael,
Whatever the availability of some of the features are that you envisage to need, it struck me that your sample code seems to suffer from the fact that you squeeze everything into the same program module, while the services you seem to look for typically should go into a library module.
By this approach you seem to fully miss out on one of the fundamental features of M2. Notably data abstraction by using e.g. an opaque type exported from a library module. It seems to me before calling for language extensions it would be advisable to first try to fully exploit the features the language already offers. Perhaps I am wrong with this impression, I just wanted to share it with you as it may possibly help.[MRi: The sample code is only menat to show how my proposual may work. The libraries and programms I have in mind all have several thouthands lines o code and are spread about dozends of modules - shurely nothing to line out the basics]
Now of course, as Benjamin rightly pointed out, one disadvantage of PIM M2 is that you need "procedures like WriteThis, WriteThat, WriteYetAnotherThat.” for the functionality of Write, which is also true of course for any functionality such as matrix algebra.
Yet, I would argue that even classical M2 offers quite attractive solutions. Perhaps not what you would be happy with, but I’d say at least usable. Look e.g. for our modules LgMatrices, LgMatCalc, or LgMatInv from our SciLib (home page, quick reference) all from RAMSES.
[MRi If you want to have a look on the libraries I actually have in mind see on my (outdated) repository at https://opensourceprojects.eu/p/modula2 (I need to find a new place to publish the actual versions). ]
Andreas
ETH ZurichProf. em. Dr. Andreas FischlinIPCC Vice-Chair WGIISystems Ecology - Institute of Biogeochemistry and Pollutant DynamicsCHN E 24Universitaetstrasse 168092 ZurichSWITZERLAND
+41 44 633-6090 phone+41 44 633-1136 fax+41 79 595-4050 mobile
Make it as simple as possible, but distrust it!________________________________________________________________________
On Tue, 28.03.23, at 00:22, Michael Riedl <udo-michael.riedl@t-online.de> wrote:
Gaius, all,
I have a questions / suggest about a possible extension of GM2.
Would it be possible to have dynamic multidimensional arrays implemented ?
We have multidimensional open array as procedure parameter, but if we come to the main module we already need to know the (maximal) dimension of e.g. a matrix - that does not make a lot of sense in my view. Especially if you have more complex programs where you do not know upfront the dimensions of the problem you would like to handle.
A small sample code illustrating the approach below - the code should work with AWD Modula, XDS M2 and the P1 compiler - it's the way Oberon addresses the issue (without the "DISPOSE").
Thanks for some feedback
Michael
----------------------------------------------------------------------
MODULE DynArray;
TYPE tVECTOR = ARRAY OF REAL; (* 1-dim open array *)
tMATRIX = ARRAY OF tVECTOR; (* 2-dim open array *)
tPtrVECTOR = POINTER TO tVECTOR; (* pointer to open 1-dim array *)
tPtrMATRIX = POINTER TO tMATRIX; (* pointer to open 2-dim array *)
PROCEDURE MultMatVek( M,N : CARDINAL;
VAR A : ARRAY OF ARRAY OF REAL; (* in *)
VAR B : ARRAY OF REAL; (* in *)
VAR C : ARRAY OF REAL); (* out *)
(* multiply matrix A[M,N] times vector B[N], result is vector C[M] *)
VAR i,j : CARDINAL;
s : REAL;
BEGIN
FOR i:=0 TO M-1 DO
s := 0.0;
FOR j:=0 TO N-1 DO s:=s + A[i,j]*B[j]; END;
C[i] := s;
END; (* FOR i *)
END MultMatVek;
VAR A : tPtrMATRIX;
B,C : tPtrVECTOR;
M,N,i,j : CARDINAL;
BEGIN
M := 4;
N := 3; (* suppose M and N are read in from some (external) source ... *)
NEW(A,M,N);
NEW(B,N);
NEW(C,M);
FOR i:=0 TO M-1 DO (* some code to initialize A,B ... *)
FOR j:=0 TO N-1 DO A^[i,j] := VAL(REAL,i+j); END;
END;
FOR i:=0 TO N-1 DO B^[i] := VAL(REAL,i); END;
MultMatVek(M,N,A^,B^,C^);
(* Some code to output the result C ... *)
DISPOSE(A);
DISPOSE(B);
DISPOSE(C);
END DynArray.
[Prev in Thread] | Current Thread | [Next in Thread] |