Author Topic: Matrix Multiply and Inverse  (Read 3651 times)

0 Members and 1 Guest are viewing this topic.

Charles Pegge

  • Guest
Matrix Multiply and Inverse
« on: June 08, 2011, 03:04:50 AM »
Generic code for multiplying / dividing square matrices. To divide you must first calculate the inverse matrix of the divisor then use it to multiply. The code given here can be configured for single or double precision.

This can be found in the examples/math folder

Multiplication:

Code: [Select]

  'Example of matrix layout mapped to an array of 4x4 cells
  '
  '  0 4 8 C
  '  1 5 9 D
  '  2 6 A E
  '  3 7 B F
  '

  '----------------------------------------
  sub MatrixMul(MatrixType *a,*b,*c, sys n)
  '========================================
  '
  '
  #if leftmatch matrixtype single
    % OneStep 4
    % ColStep 16
    % mtype single
  #endif
  '
  #if leftmatch matrixtype double
    % OneStep 8
    % ColStep 32
    % mtype double
  #endif

  sys pa=@a, pb=@b, pc=@c

  mov ecx,pa
  mov edx,pb
  mov eax,pc

  mov esi,n
  (
  call column : dec esi : jg repeat
  )
  exit sub

  column:
  '======

  mov edi,n
  (
  call cell : dec edi : jg repeat
  )
  add edx,ColStep
  sub ecx,ColStep
  ret

  cell: ' row A * column B
  '=======================

  'matrix data is stored ascending vertically then horizontally
  'thus rows are minor, columns are major
  '
  push  ecx
  push  edx
  push  eax
  mov   eax,4
  fldz
  (
  fld   mtype [ecx]
  fmul  mtype [edx]
  faddp st1
  add   ecx,ColStep 'next column of matrix A
  add   edx,OneStep 'next row of matrix B
  dec eax
  jnz repeat
  )
  pop eax
  fstp mtype [eax] 'assign to next row of matrix C
  '
  pop edx
  pop ecx
  add   eax,OneStep 'next cell in column of matrix C (columns then rows)
  add   ecx,OneStep 'next row of matrix A
  ret
  '
  end sub

       

  '-----------------------------------------------
  sub getrow4S(MatrixType* matrix, MarixType *row)
  '===============================================
  '
  indexbase 0
  row<=matrix[0],matrix[4],matrix[8],matrix[12]
  end sub



Inverse Matrix

(I 'borrowed' this algorithm from Dan Baron / thinBasic forum / PB examples)


Code: [Select]

  '----------------------------------
  sub MatrixInv(MatrixType *m, sys n)
  '==================================

  'Uses the Gauss-Jordan Method.
  'Inverts matrix, m[], "in-place".

  'limit to max 16x16 matrix

  sys        pivot,row,col,maxrow
  MatrixType test,colmax,divisor,factor,temp
  sys        rowswitch,switchcount
  sys        i,j
  sys        rs[128] 'for limit array n=64

  '
  'TO RESOLVE MATRIX INDEX
  '=======================
  '
  #indexbase 1
  #define mat(row,col) m[ (col-1)*n+row ]
  #define rowswitches(row,col) rs[ (col-1)*64+row ]
  #define first 1
  #define last  n
  '
  'TRAVERSE COLUMNS
  '================

  for pivot=first to last
  '
  '
  'GET THE MAXIMUM ELEMENT ON EACH PIVOT COL
  '=========================================
  '
  colmax=0
  maxrow=pivot
  '
  for row=pivot to last
    test=abs (mat(row,pivot))
    if test>colmax then
      colmax=test
      maxrow=row
    end if
  next

  if maxrow<>pivot then
    '
    '
    'SWAP ROWS TO GET THE MAX VALUE AT THE PIVOT
    '===========================================
    '
    for col=first to last
      temp=mat(pivot,col)
      mat(pivot,col)=mat(maxrow,col)
      mat(maxrow,col)=temp
    next
    '
    '
    'REMEMBER THE ROW SWAP
    '=====================
    '
    switchcount++
    rowswitches(switchcount,1)=pivot
    rowswitches(switchcount,2)=maxrow
  end if
  '
  '
  'DIVIDE THE PIVOT ROW BY THE PIVOT DIAGONAL
  '==========================================
  '
  'also setting the pivot diagonal to 1
  '
  divisor=mat(pivot,pivot)
  mat(pivot,pivot)=1
  '
  for col=first to last
    mat(pivot,col)=mat(pivot,col) / divisor
  next


  'APPLY PIVOT FACTORS TO ALL ELEMENTS (OTHER THAN PIVOT ROW)
  '==========================================================
  '
  'also setting each pivot row element to 0
  '
  for row=first to last
    if row<>pivot then
      factor=-mat(row,pivot)
      mat(row,pivot)=0
      for col=first to last
        mat(row,col)=mat(row,col)+mat(pivot,col) * factor
      next
    end if
  next

  next 'pivot


  '
  'SWAP COLUMN VALUES ACCORDING TO ORIGINAL ROW POSITIONS
  '======================================================
  '
  for rowswitch=switchcount to 1 step-1
    i=rowswitches(rowswitch,1)
    j=rowswitches(rowswitch,2)
    for row=first to last
      temp = mat(row,i)
      mat(row,i)=mat(row,j)
      mat(row,j)=temp
    next
  next
  '
  '
  end sub



Test

Code: [Select]

  'Example of Matrix layout in an array
  '
  '  0 4 8 C
  '  1 5 9 D
  '  2 6 A E
  '  3 7 B F
  '
  #define MatrixType double

  include "MatrixMul.inc"
  include "MatrixInv.inc"

  '-----------------------------------------------
  function showMat(MatrixType *r, sys n) as string
  '===============================================

  string tab.cr.pr
  tab=chr 9
  cr=chr(13) chr(10)
  pr="Matrix:" n "x" n cr
  sys i,j,m
  '
  'DISPLAY IN Y MINOR : X MAJOR ORDER (COLUMN MAJOR)
  '-------------------------------------------------
  '
  for i=1 to n
    m=0
    for j=1 to n
      pr+=str( r[m+i] ) tab
      m+=n
    next
    pr+=cr
  next
  return pr cr cr
  '
  end function




  MatrixType m[16],n[16],r[16]

  'set identity matrix values

  ' 1 0 0 0
  ' 0 1 0 0
  ' 0 0 1 0
  ' 0 0 0 1

  'reading vertically then left to right

  m<=1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1
  n<=1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1




  '=====
  'TESTS
  '=====
  '
  string cr=chr(13)+chr(10)
  string pr="MATRIX TESTS:" cr cr

  'scalar mul
  for i=1 to 16 : m[i]*=4 : next
  '
  m[4]=1
  n[4]=1

  MatrixMul m,n,r,4
  '
  pr+=showMat r,4
  MatrixInv   r,4
  pr+="Invert "+showMat r,4
  MatrixInv   r,4
  pr+="Invert again " ShowMat r,4

  print pr


Charles