When I first started using FPC, I went through the manuals looking for useful features. I came across both open arrays and dynamic arrays, and thought that they might be valuable. But nowhere could I find any notation for the second, third ... dimension of the array. Without that, open and dynamic arrays were little more than curiosities, possibly useful for 1-dimensional array, but not beyond.
Now I see from your email that the notation for the second dimension of an array is Length(xarray[i]) where i is any valid index value (and hence can always be 0). By extension, the third dimension presumably would be Length(xarray[0,0]), and so forth.
Never, ever, would I have guessed that would work. It makes sense mathematically, but notationally I would have expected something like Length(xarray,2) for the second dimension. If I had thought of Length(xarray[0]), I would have deemed it so implausible that I never would have tried it.
But simply because this is feasible does not mean that one should use it. For one thing, I would like the compiler to generate warning messages if I try to add two matrices of incompatible sizes. I don't want to discover this hours into a computation. That type of checking is one of the main virtues of Pascal.
For another, it requires that I code a SetLength statement for every array. That means the array information becomes decentralized. I can't just read down the VAR section of my procedure and learn what I need about the variables, I must consult two sections.
Of course I wouldn't have to make every array open, but then I would have a mixture of two kinds of array declarations. This creates an extra maintenance task, making some arrays open, when needed, and restoring them to fixed size when they no longer need to be open. The problem could become fierce when the same declarations are shared by several different procedures. Which one should set the length? How can I be sure the length is set before I reach MyProc?
So, once again, I throw my support towards adding vector operations to the compiler.
Frank Rubin
In a message dated 8/6/2010 12:23:25 P.M. Eastern Daylight Time, harley@umich.edu writes: Dear Frank Rubin,
"Except that you have to code every single case separately, 2x6, 3x10, 4x4x4, etc. You need to write a separate routine for every shape of array you want to use."
Not so:
Use open arrays (always 0-based):
type Matrix = array of array of TRing;
Youu can write code, roughly:
operator * (const A, B: Matrix): Matrix;
var RowA, ColA, RowB, ColB, I, J, K: Integer; T: TRing;
begin RowA := Length(A); ... ColB := Length(B[0]); if ColA <> RowB then ... SetLength(Result, RowA); for J := 0 to RowA - 1 do SetLength(Result[J], ColB); for I := 0 to RowA - 1 do for K := 0 to ColB - 1 do begin T := Zero; // prefer just 0 for J := 0 to ColA - 1 do T := T + A[I, J]*B[J, K]; Result[I, K] := T; end; end;
once and for all, covering all sizes of matrices.
The problem I do not yet know how to solve: to do it for all TRing.
So I need a type TRing that can include any structure that has + and * operators, and a 0 element:
Integers, Floats, Rationals, Gaussian Integers, Polynomials with xxx coefficients,... any possible data type I can define with overloaded +, *, etc.
Note that 0 is a problem in itself -- one really needs to overload it too!
Frank Heckenbach's first reply to me may contain the answer. I haven't completely digested it yet.
Cheers,
Harley
Contestcen@aol.com wrote:
When I first started using FPC, [...]
Now I see from your email [...]
Never, ever, would I have guessed [...]
But simply because [...]
Sorry, but what does any of this have to do with GPC?
GPC supports schema types where all of this is straightforward, so the discussion of FPC's ways of doing things and whether or not they are intuitive really doesn't belong here.
For one thing, I would like the compiler to generate warning messages if I try to add two matrices of incompatible sizes.
If the sizes are not known at compile-time, of course, no compiler warning is possible.
If they are, then e.g. my suggested template solution does this in C++, so if we add equivalent support in GPC, this would do it.
So, once again, I throw my support towards adding vector operations to the compiler.
Once again, I'd stress one important principle:
Do not built things into the compiler (or ask for them) that can be done outside of it. Building in things is many times as much work. Maybe I haven't stressed this enough so far because it's so obvious to me, but not to those who haven't worked in the compiler.
In fact, I'm looking at features that will allow us to "build out" things that are now built into the compiler (e.g., strings, sets), of course, without sacrificing efficiency (e.g., using inlining). I think one of the strengths of C++ is that it has powerful and generic (but abstract) language features (e.g., templates) that allow many directly useful features (e.g., strings, I/O) to be written as regular C++ code. (For comparison, C tried so as well, but its built-in features were generic, but not very powerful, e.g. simple pointers for string handling, or varargs for text I/O, both dangerous features that contributed most to C's bad reputation. Pascal provided safe, but not generic features with its built-in string and I/O support.)
Compare my reply to Prof. Harley Flanders' long wishlist: http://www.gnu-pascal.de/crystal/gpc/en/mail14823.html Many of the wanted features can already now be written outside of the compiler. The rest can with a few general new compiler features, viz. templates, automatic con-/destructors, global inlining and function overloading.
What this means for this discussion is:
- When discussing wanted features, we should examine what can be implemented outside of the compiler, and which (preferably general) features really need to be added.
- For implementing the library code, who will do it? Since the excuse "the compiler is written in C" doesn't apply here, anyone interested in the features can start implementing them. (Some, as I said, even today with the existing GPC.) And if we agree that writing compilers is the "hard stuff", it follows that those who don't want to get involved with that might look here for opportunities to contribute.
Frank
Hi Frank (Rubin),
Sometimes life is simpler than appears at first glance :-)
I should have put in the stuff below in my previous message; I was thinking of triangular matrices, where you save memory by having the rows of different lengths.
But please tell me, have you _ever_ used 3-D arrays? 4-D arrays?
Harley
*From Delphi 2010 Help: * *SetLength*
For dynamic arrays, SetLength may take more than one-length parameter (up to the number of array dimensions). Each parameter specifies the number of elements along a particular dimension.
*Structured types/Data types*
Multidimensional Dynamic Arrays
To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example:
*type TMessageGrid = array of array of string; var Msgs: TMessageGrid;*
declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables:
*SetLength(Msgs,I,J);*
allocates an /I-by-J/ array, and Msgs[0,0] denotes an element of that array.
You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example:
var Ints: array of array of Integer; SetLength(Ints,10);
allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example:
SetLength(Ints[2], 5);
makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.
The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.
var A : array of array of string; I, J : Integer; begin SetLength(A, 10); for I := Low(A) to High(A) do begin SetLength(A[I], I); for J := Low(A[I]) to High(A[I]) do A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' '; end; end;
Contestcen@aol.com wrote:
When I first started using FPC, I went through the manuals looking for useful features. I came across both open arrays and dynamic arrays, and thought that they might be valuable. But nowhere could I find any notation for the second, third ... dimension of the array. Without that, open and dynamic arrays were little more than curiosities, possibly useful for 1-dimensional array, but not beyond.
Now I see from your email that the notation for the second dimension of an array is Length(xarray[i]) where i is any valid index value (and hence can always be 0). By extension, the third dimension presumably would be Length(xarray[0,0]), and so forth.
Never, ever, would I have guessed that would work. It makes sense mathematically, but notationally I would have expected something like Length(xarray,2) for the second dimension. If I had thought of Length(xarray[0]), I would have deemed it so implausible that I never would have tried it.
But simply because this is feasible does not mean that one should use it. For one thing, I would like the compiler to generate warning messages if I try to add two matrices of incompatible sizes. I don't want to discover this hours into a computation. That type of checking is one of the main virtues of Pascal.
For another, it requires that I code a SetLength statement for every array. That means the array information becomes decentralized. I can't just read down the VAR section of my procedure and learn what I need about the variables, I must consult two sections.
Of course I wouldn't have to make every array open, but then I would have a mixture of two kinds of array declarations. This creates an extra maintenance task, making some arrays open, when needed, and restoring them to fixed size when they no longer need to be open. The problem could become fierce when the same declarations are shared by several different procedures. Which one should set the length? How can I be sure the length is set before I reach MyProc?
So, once again, I throw my support towards adding vector operations to the compiler.
Frank Rubin
In a message dated 8/6/2010 12:23:25 P.M. Eastern Daylight Time, harley@umich.edu writes: Dear Frank Rubin,
"Except that you have to code every single case separately, 2x6, 3x10, 4x4x4, etc. You need to write a separate routine for every shape of array you want to use."
Not so:
Use open arrays (always 0-based):
type Matrix = array of array of TRing;
Youu can write code, roughly:
operator * (const A, B: Matrix): Matrix;
var RowA, ColA, RowB, ColB, I, J, K: Integer; T: TRing;
begin RowA := Length(A); ... ColB := Length(B[0]); if ColA <> RowB then ... SetLength(Result, RowA); for J := 0 to RowA - 1 do SetLength(Result[J], ColB); for I := 0 to RowA - 1 do for K := 0 to ColB - 1 do begin T := Zero; // prefer just 0 for J := 0 to ColA - 1 do T := T + A[I, J]*B[J, K]; Result[I, K] := T; end; end;
once and for all, covering all sizes of matrices.
The problem I do not yet know how to solve: to do it for all TRing.
So I need a type TRing that can include any structure that has + and * operators, and a 0 element:
Integers, Floats, Rationals, Gaussian Integers, Polynomials with xxx coefficients,... any possible data type I can define with overloaded +, *, etc.
Note that 0 is a problem in itself -- one really needs to overload it too!
Frank Heckenbach's first reply to me may contain the answer. I haven't completely digested it yet.
Cheers,
Harley
Prof. Harley Flanders wrote:
Sometimes life is simpler than appears at first glance :-)
I should have put in the stuff below in my previous message; I was thinking of triangular matrices, where you save memory by having the rows of different lengths.
It's probably more efficient to store it in a single array similar to the link below (quick Google search) than allocating each row individually.
http://www.itl.nist.gov/div897/sqg/dads/HTML/upperTriangularMatrix.html
But please tell me, have you _ever_ used 3-D arrays? 4-D arrays?
Yes. Yes.
Frank
Sure, you can store a triangular matrix in a single array. Now write a procedure for multiplying two of them.
Really simple and transparent, right (or wrong)?
HF
Frank Heckenbach wrote:
Prof. Harley Flanders wrote:
Sometimes life is simpler than appears at first glance :-)
I should have put in the stuff below in my previous message; I was thinking of triangular matrices, where you save memory by having the rows of different lengths.
It's probably more efficient to store it in a single array similar to the link below (quick Google search) than allocating each row individually.
http://www.itl.nist.gov/div897/sqg/dads/HTML/upperTriangularMatrix.html
But please tell me, have you _ever_ used 3-D arrays? 4-D arrays?
Yes. Yes.
Frank