LB Booster
Programming >> Language extensions >> Matrix multiplication (dot product)
http://lbb.conforums.com/index.cgi?board=extensions&action=display&num=1478868438

Matrix multiplication (dot product)
Post by Richard Russell on Nov 11th, 2016, 11:47am

Neither LB 4 nor LBB supports matrix multiplication (dot product) as a native operator, but BBC BASIC does so that makes it easy to incorporate it in an LBB program. This is exactly what I did as one of my speed-up modifications to Bluatigro's CG animation demo.

His original code used a multiply routine similar to this:

Code:
' matrix( c ) = matrix( a ) . matrix( b )
  for i = 0 to 3
    for j = 0 to 3
      c(i,j) = 0
      for k = 0 to 3
        c(i,j) = c(i,j) + a(i,k) * b(k,j)
      next k
    next j
  next i 

In my LBB version I used this as a (very) much faster replacement:

Code:
  !c() = a() . b() 

You might be surprised to discover how often matrix multiplication is useful. 3D manipulations (rotation, translation, scaling) as used by Bluatigro are probably some of the most common applications, but there are many others.

Richard.

Re: Matrix multiplication (dot product)
Post by CryptoMan on Nov 18th, 2016, 10:43pm

How about Inverse of a square matrıx?
Re: Matrix multiplication (dot product)
Post by Richard Russell on Nov 19th, 2016, 09:59am

on Nov 18th, 2016, 10:43pm, CryptoMan wrote:
How about Inverse of a square matrıx?

There's no built-in matrix inversion, but it's not that difficult to code in BASIC (the complexity depends on whether you need to choose the pivots carefully to maximize accuracy and avoid division-by-zero errors). Of course it won't be as fast as a native function would be.

I've got a matrix inversion routine in BBC BASIC but not in Liberty BASIC. Rather surprisingly, Rosetta Code doesn't seem to have a matrix inversion task either.

If I were to create a Programming Challenge to write a fast, accurate and stable matrix inversion in LB, do you think anybody other than me would submit an entry? wink

Richard.
Re: Matrix multiplication (dot product)
Post by CryptoMan on Nov 19th, 2016, 10:41pm

I would. In my past iife I used to work a lot on that. In those days memory was limited and we were spending more effort in storşng the matrices in smaller spacesdue to the nature of our matrices which were symetric around the diagonal. Today, there is obscene amount of memory is available.

Ofcourse, I know it can be done in Basic but wondering if there is a native version maybe even by accessing libraries on graphics processor cards which can do it lightning fast.

Probably, there are some 3rd party DLLs available for full set of matrix arithmetic. Just asked as a matter of curiosity if more native matrix functions
Available. I don't even remember the theory of Finite Elements now to make any use of it. Need to open the texr books and remember from 35 years ago.

I used to write it on TI59 and HP41CV programmable calculators and solving some of the problems in exams very quickly during the days when they did not expect such things from calculators and not forbidding them from exams. Later when IBM PC came in 1981 it was so simple and huge so we translated lots of code from IBM mainframe FORTRAN to BASIC, Pascal and C. So, it is always interesting for me to see what can be now done with all this additional power we have today. Some amazing things should be possible.



Re: Matrix multiplication (dot product)
Post by Richard Russell on Nov 20th, 2016, 11:48am

on Nov 19th, 2016, 10:41pm, CryptoMan wrote:
the nature of our matrices which were symetric around the diagonal.

Mine usually are too, I suspect it follows when they are used for least-squares regression. Inverting such a symmetrical matrix is less demanding, I think, and that supports my feeling that there isn't a 'one size fits all' inversion routine. That may be one reason why inversion wasn't incorporated as a native operation in BBC BASIC 30 years ago (I was there at the time, but I don't think the BBC expressed a view either way).

Nevertheless embedded BBC BASIC code for array arithmetic can be very useful; one neat thing you can do is to normalise a vector to unit length in one fast operation:

Code:
    !array() /= MOD(array()) 

That can be valuable in some 3D graphics applications.

Quote:
I know it can be done in Basic but wondering if there is a native version maybe even by accessing libraries

In my experience matrix inversion hasn't been time-critical. Even in a real-time application like free-d2 (see the BBC BASIC Birthday page) it was acceptable to do the inversion in interpreted BASIC.

You may be interested in this example of using array arithmetic to fit a polynomial function to a large set of data points.

Richard.
Re: Matrix multiplication (dot product)
Post by Optimax on Nov 21st, 2016, 07:07am

A long time ago, I wrote an "inverse matrix" in Rapidq, that I later ported to LB. It uses the method of "minors" elaborated by Gauss and Jordan. There is an other method called "the simplex" that I never could find back.
Strangely there appears at the end a "-0.00" which is anyway equal to zero; could maybe come from rounding ?

Code:
'GAUSS-JORDAN MATRICE INVERSE
'=============================

'A original matrix, InvA inverse of A, B extended matrix, P = A * InvA

'let's have a square matrix A (3x3)         '2,        1,    -2
                                            '3         2      2
                                            '5         4      3

'--- creating the extended matrix B = A + unit matrix

DATA         2,     1,   -2,      1,     0,     0
DATA         3,     2,    2,      0,     1,     0
DATA         5,     4,    3,      0,     0,     1

n = 3

DIM A(n+1, n+1)
DIM B(n+1, n*2)

PRINT "EXTENDED MATRIX B :": PRINT
FOR i = 1 TO n
FOR j = 1 TO 2*n
    READ m
    B(i,j) = m
    PRINT "", B(i,j);    'and displaying it
NEXT j
    PRINT: PRINT
NEXT i
PRINT

'--- A is the left part of B, extraction

PRINT "ORIGINAL MATRIX A, extracted from B :"
PRINT
FOR i = 1 TO n
FOR j = 1 TO n
    A(i,j) = B(i,j)
    PRINT "", A(i,j);    'and displaying it
NEXT j
    PRINT: PRINT
NEXT i
PRINT

'--- calculation begins here 

'i = row index        'k = other row index (not-i)      'j = column index
'intermediary variables p, q, r to avoid divisions like A(i,j)/A(m,n) e.g., giving unpredictable results

FOR i = 1 TO n

'reducing each diagonal term B(i,i)  to 1 by dividing the hole row by B(i,i)
    p = B(i, i)
    FOR j = 1 TO 2*n
    q = B(i, j)
    B(i, j) = q / p
    NEXT j

'multiply row i by B(k,i)
'substract row i from row k

        FOR k = 1 TO n
        p = B(k, i)
        IF k <> i THEN
                  FOR j = 1 TO 2*n
                  q = B(k, j)
                   r = B(i, j)
                  B(k, j) = q - p * r
                  NEXT j
        END IF
    NEXT k

NEXT i

'--- end of calculation, let's see matrix B  now

PRINT "INTERMEDIAIRY MATRIX B :": PRINT
FOR i = 1 TO n
  FOR j= 1 TO 2*n
      m = B(i, j)
      PRINT "", USING("###.###", m);
  NEXT j
      PRINT: PRINT
NEXT i
PRINT

'---INVERSE of a, i.e. InvA, is the *right* part of B

PRINT "INVERSE of A (rounded) :": PRINT
DIM InvA(n+1,n+1)

FOR i = 1 TO n
FOR j = n+1 TO 2*n                            'copying the right part of B
          InvA(i, j-n) = B(i,j)
          m = InvA(i, j-n)
          PRINT "", USING("###.###", m);      'rounding
NEXT j
          PRINT: PRINT
NEXT i
PRINT

'--- Checking the result: A * InvA must guve P = the unit matrix

PRINT "CHECKING for InvA:  A * Inv must give the unit matrix P"
PRINT

DIM P(n+1, n+1)                  'empty

FOR i = 1 TO n                    'for each row i o f A and P
  FOR j = 1 TO n                  'for each horizontal term j of row i of P
    FOR k = 1 TO n                'for each vertical term k of column j of InvA
        x = A(k,i): y = InvA(j,k)
        P(i, j) = P(i, j) + x*y
     NEXT k
     m = P(i, j)
     PRINT "", USING("###.###", m);
  NEXT j
  PRINT: PRINT
NEXT i

END
 

Re: Matrix multiplication (dot product)
Post by Richard Russell on Nov 21st, 2016, 09:43am

on Nov 21st, 2016, 07:07am, Optimax wrote:
A long time ago, I wrote an "inverse matrix" in Rapidq, that I later ported to LB. It uses the method of "minors" elaborated by Gauss and Jordan.

The problem with that method is that there's no 'pivot selection': you simply work down the diagonal from top-left to bottom-right. This can result in inaccuracy, or worse, if you are unlucky with your input matrix.

That can easily be demonstrated by changing your test matrix so that the top-left element is 0 rather than 2:

Code:
DATA         0,     1,   -2,      1,     0,     0
DATA         3,     2,    2,      0,     1,     0
DATA         5,     4,    3,      0,     0,     1 

Now when I run your program it reports a Division by zero error! It's not that the matrix is non-invertable, in fact the inverse matrix is this:

Code:
      -0.4         1      -0.4
       0.2        -2       1.2
       0.4         1      -0.6 

The BBC BASIC code I referred to does attempt to be more 'intelligent' in its pivot selection, and it is successful in this case, but I make no claims for it in other respects.

Quote:
Strangely there appears at the end a "-0.00"

I don't see that here, but it's a perfectly reasonable thing to output (representing a negative number which is zero when rounded to two decimal places)

Richard.
Re: Matrix multiplication (dot product)
Post by Optimax on Nov 25th, 2016, 12:30pm

You are right.
Thanks for advice.
I should have a look at that pivot thing.