From: orpheus@reed.edu (P. Hawthorne)
Newsgroups: comp.lang.pascal
Subject: Re: Matrix routines in pascal
Date: 30 Jul 92 01:00:06 GMT
Article-I.D.: reed.1992Jul30.010006.19073
Distribution: usa
Organization: Reed College, Portland, OR


  eldred@rrunner.jpl.nasa.gov (Dan Eldred) writes:
: If you have a pascal compiler that allows conformant arrays, this is pretty
: easy--either do Fortran style calls in which the dimensions are passed as
: parameters, or pass a record structure which has the dimensions embedded.
: But I'm having trouble coming up with a satisfactory strategy for ANS
: pascal (i.e. Think Pascal 4.0 on the Mac). Suggestions?

  dmurdoch@QueensU.CA (Duncan Murdoch) writes:
: Think Pascal includes OOP extensions, doesn't it? If so, making a matrix
: object is probably the best way to go. That's how I handle matrices in
: Turbo Pascal. The big problem there is the 64K limit on size; that means I
: have to go through all sorts of gyrations to handle large matrices, since
: 90 by 90 is the biggest matrix of doubles that fits in 64K.

  Yeah, this sounds right to me, as far as it goes. Make a matrix class
that knows it's own dimensions. Give it methods for the desired matrix
operations. It's a textbook case for OOP. There are some other concerns...

  In Object Pascal, objects are relocatable memory blocks unless you get
around that requirement somehow. This can mean that they can relocate on
you at many points during code execution, which can really confuse the
things. So, in general, you would want to keep that object moved high in
the heap and locked down when it is in use. You can do that with the
HLock, HUnlock and MoveHHi traps.

  Another thing is that the 68000 series have a 16 bit address register
indirect addressing mode. This means it can only do array references the
easy way up to a limit of 32k. (Well, you could use negative array indexes
and get that other 32k, but that's somewhat beside the point.) So, if you
have a matrix which grows beyond 32K, you want to calculate the addresses
of each element on your own.

  All of that being said, here's some code for a simple matrix. It expects
the topmost leftmost corner to be at 1,1, but you can easily change that.
It also adjusts to handle elements of arbitrary size, which could be the
size of the extended format. If you're going to use a Mac, you might as
well benefit from the keen numeric environment it sports... :-)

 QMatrix = object(QContent)
   EntrySize: Longint;
   EntriesAcross: Longint;
   EntriesDown: Longint;
   Entries: EntryArray;

   function QMatrix.Construct: Boolean;
   override;

   procedure QMatrix.SetEntry (x, y: Longint; aPtr: univ Ptr);
   procedure QMatrix.GetEntry (x, y: Longint; aPtr: univ Ptr);
  end;

{Clean is essentially the same as Think Pascal's ORD4, but it also does
the equivalent of a call to StripAddress. There's not much reason to worry
about doing that unless you need to be 32 and 24 bit clean.}

function QMatrix.Construct: Boolean;
 begin
 Construct := false;
 Lock;
 if EntrySize = 0 then
  EntrySize := 4;
 if Grow(Clean(@Entries) - Clean(Handle(Self)^) + (EntriesAcross * EntriesDown
* EntrySize)) <> noErr then
  Exit(Construct);
 Construct := true;
 end;

procedure QMatrix.SetEntry (x, y: Longint; aPtr: univ Ptr);
 begin
 BlockMove(aPtr, Ptr(Clean(@Entries) + (x - 1 + (y - 1) * EntriesAcross) *
EntrySize), EntrySize);
 end;

procedure QMatrix.GetEntry (x, y: Longint; aPtr: univ Ptr);
 begin
 BlockMove(Ptr(Clean(@Entries) + (x - 1 + (y - 1) * EntriesAcross) *
EntrySize), aPtr, EntrySize);
 end;

{The Grow method is inherited. It adjusts the size of the handle that
contains the object, making it the intended size. Here's that:}

function Abstract.Grow (intended: Longint): OSErr;
 var
  state: SignedByte;
 begin
 state := HGetState(Handle(Self));
 HUnlock(Handle(Self));
 SetHandleSize(Handle(Self), intended);
 Grow := MemError;
 if state = -128 then
  MoveHHi(Handle(Self)); {Skanky little hack, but harmless}
 HSetState(Handle(Self), state);
 end;

  Theus (orpheus@reed.edu)