Jump to content

Recommended Posts

  • Moderators

How to do matrix manipulation in sms.

 

A matrix is basically a multidimensional array and sms supports the 'array of array of ...' structure.

However I've never been able to get this to work for me satisfactorily.

 

Maybe I'm doing something wrong but as an example this code compiles and runs ok but the output doesn't make much sense to me

//  var myarray   : array of array of float;
//  var myarray1 : array of float := [1,2];       
//  var myarray2 : array of float := [3,4];       
//  Myarray.Add(myarray1,myarray2);                 
//  showmessage(floattostr(myarray[1,0]));          //1-1 = 4; 0-1 = 2; 0-0 = 1; 1-0 = 3
 
and the line myarray[0].add(myarray2) compiles but gives a runtime error on "Self.tryout[0].pusha(myarray2);"
 
So sidestepping the issue I looked for available libraries supporting matrix manipulation, the most likely candidates among others being Math.js and MathLib.js
 
Math.js has a typescript definition file available so potentially could be processed by Christian's ts2pas tool to produce a wrapper around this library.
However unfortunately this produces too many errors to be usable in this case. Possibly because the developer of the library and the author of the typescript file are different persons and there are some synchronisation issues ?
 
So as I only needed to do multiplication on 2D matrices, its sometimes easier to code the necessary functions in-project rather then importing another huge library 
 
The following code implements a 2DMatrix component based on a native js array with the matrix manipulation functions of multiply(DotX), Transpose and an isZero check
 


unit Unit2;
 
interface
 
uses 
  SmartCL.System, System.Types;
 
type
  TMatrix = class (TObject)
  public
    Constructor Create(dim1,dim2:integer); virtual;
    Procedure Insert(i,j:integer;content:variant);
    Function GetValue(i,j:integer): Variant;
    Function NrRows: Variant;
    Function NrColumns: Variant;
    Function Transpose(Matrixin:TMatrix): TMatrix;
    Function DotX(Matrix1,Matrix2:TMatrix): TMatrix;
    Function IsZero: Boolean;
    FHandle: THandle;
    Rows, Columns: Integer;
  end;
 
implementation
 
Constructor TMatrix.Create(dim1,dim2:integer);
begin
  inherited Create;
 
  asm
 
  function MyMatrix() {
    var iMax = dim1
    var jMax = dim2;
    var f = new Array();
 
    for (i=0;i<iMax;i++) {
      f[i]=new Array();
      for (j=0;j<jMax;j++) {
        f[i][j]=0;              //initialise with zero
      }
    }
    this.array = f;
  }
 
  MyMatrix.prototype.insert = function(dim1, dim2, data3) {
    this.array[dim1][dim2] = data3;
  };
 
  MyMatrix.prototype.getvalue = function(dim1, dim2) {
    return this.array[dim1][dim2];
  };
 
  @FHandle = new MyMatrix(dim1,dim2);
  @FHandle.Rows = dim1;
  @FHandle.Columns = dim2;
end;
 
end;
 
Procedure TMatrix.Insert(i,j:integer; content: Variant);
begin
  FHandle.insert(i,j,content);
end;
 
Function TMatrix.GetValue(i,j: integer) : Variant;
begin
  result := FHandle.getvalue(i,j);
end;
 
Function TMatrix.NrRows : Variant;
begin
  result := FHandle.Rows;
end;
 
Function TMatrix.NrColumns : Variant;
begin
  result := FHandle.Columns;
end;
 
Function TMatrix.Transpose(Matrixin:TMatrix) : TMatrix;
var
  MyTranspose : TMatrix;
begin
  MyTranspose := TMatrix.Create(Matrixin.NrColumns,Matrixin.NrRows);
  For var i := 0 to Matrixin.NrRows -1 do begin
    For var j := 0 to Matrixin.NrColumns -1 do begin
      MyTranspose.Insert(j,i,Matrixin.GetValue(i,j));
    end;
  end;
  result := MyTranspose;
end;
 
Function TMatrix.DotX(Matrix1,Matrix2:TMatrix) : TMatrix;
var
  MyDotX : TMatrix;
begin
  MyDotX := TMatrix.Create(Matrix1.NrRows,Matrix2.NrColumns);
  For var i := 0 to Matrix1.NrRows -1 do begin
    For var j := 0 to Matrix2.NrColumns -1 do begin
      var sum: float := 0;
      For var k := 0 to Matrix1.NrColumns -1 do begin
        sum := sum + Matrix1.GetValue(i,k) * Matrix2.GetValue(k,j);
        MyDotX.Insert(i,j,sum);
      end;
    end;
  end;
  result := MyDotX;
end;
 
Function TMatrix.IsZero: Boolean;
begin
  Result := true;
  For var i := 0 to NrRows -1 do begin
    For var j := 0 to NrColumns -1 do begin
      If GetValue(i,j) <> 0 then begin
        result := false;
      end;
    end;
  end;
end;
 
end.
 

 
and the calling code
 


unit Form1;
 
interface
 
uses 
  SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms, 
  SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, Unit2,
  SmartCL.Controls.Button;
 
type
  TForm1 = class(TW3Form)
    procedure W3Button1Click(Sender: TObject);
  private
    {$I 'Form1:intf'}
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  public
    MyMatrix : TMatrix;
    MyMatrix2: TMatrix;
    MyMatrix3: TMatrix;
    MyMatrix4: TMatrix;
  end;
 
implementation
 
{ TForm1 }
 
procedure TForm1.W3Button1Click(Sender: TObject);
begin
  MyMatrix.Insert(0,0,0.9);
  MyMatrix.Insert(0,1,0.3);
  MyMatrix.Insert(0,2,0.4);
  MyMatrix.Insert(1,0,0.2);
  MyMatrix.Insert(1,1,0.8);
  MyMatrix.Insert(1,2,0.2);
  MyMatrix.Insert(2,0,0.1);
  MyMatrix.Insert(2,1,0.5);
  MyMatrix.Insert(2,2,0.6);
//
  MyMatrix2 := MyMatrix.Transpose(MyMatrix);
//
  MyMatrix3.Insert(0,0,0.9);
  MyMatrix3.Insert(1,0,0.1);
  MyMatrix3.Insert(2,0,0.8);
  MyMatrix4 := MyMatrix.DotX(MyMatrix, MyMatrix3);
 
  For var i := 0 to MyMatrix4.NrRows -1 do begin
    For var j := 0 to MyMatrix4.NrColumns -1 do begin
      ShowMessage(MyMatrix4.GetValue(i,j));
    end;
  end;
 
  If MyMatrix4.IsZero = true then showmessage('true') else showmessage('false');
end;
 
procedure TForm1.InitializeForm;
begin
  inherited;
  // this is a good place to initialize components
  MyMatrix := TMatrix.Create(3,3);
  MyMatrix3:= TMatrix.Create(3,1);
end;
 
procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
end;
 
procedure TForm1.Resize;
begin
  inherited;
end;
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.

 
.
 
 
 
 
 
 

 

 

Link to post
Share on other sites
  var myarray   : array of array of float;
  var myarray1 : array of float := [2, 3, 4, 5];
  var myarray2 : array of float := [4, 3, 3, 1];
  myarray.Add(myarray1, myarray2);

myarray = [[2,3,4,5],[4,3,3,1]]

 
// It does assume the two arrays are of equal length
  var sum := 0.0;
  for var i := 0 to myarray1.length - 1 do
  begin
    sum += myarray1[i] * myarray2[i];
  end;

  console.log(sum); // 2*4 + 3*3 + 4*3 + 5*1 = 34

using another approach

  var sumOfProds := 0.0;
  for var j := 0 to (myarray1.length - 1 AND myarray2.length - 1) do
  begin
    sumOfProds += myarray1[j] * myarray2[j];
  end;

  console.log(sumOfProds);  // 2*4 + 3*3 + 4*3 + 5*1 = 34

multiplying individual elements

var points : array of Float := [4, 400, 9, 81, 25, 100];
var roots := points.Map(Sqrt);
for var Index := Low(roots) to High(roots) do
  WriteLn(roots[Index]);  // 2 , 20, 3, 9, 5, 10

var multiply := points.Map(function(n: float):float
                begin
                  result := n * n;
                end);

for var Index := Low(multiply) to High(multiply) do
  WriteLn(multiply[Index]);  // 16, 160000, 81, 6561, 625, 10000

Let's suppose we want to multiply the following arrays:

 

A1 =  [[0,1,2],[1,2,3],[2,3,4]];

A2 =  [[10,20,30,40],[50,60,70,80],[11,22,33,44]];

var A1 : array of array of integer;
var A2 : array of array of integer;

A1 := new Integer[3, 3];
for var Index := 0 to 2 do begin
  for var j := 0 to 2 do
    A1[Index][j] := Index + j;
end;

(* A1 = [[0,1,2],[1,2,3],[2,3,4]] *)

A2 := new Integer[3, 3];
A2[0][0] := 10;
A2[0][1] := 20;
A2[0][2] := 30;
A2[0][3] := 40;

A2[1][0] := 50;
A2[1][1] := 60;
A2[1][2] := 70;
A2[1][3] := 80;

A2[2][0] := 11;
A2[2][1] := 22;
A2[2][2] := 33;
A2[2][3] := 44;

(* A2 = [[10,20,30,40],[50,60,70,80],[11,22,33,44]] *)


function multiplyMatrices(m1, m2: array of array of integer): variant;
begin
  var res := TVariant.CreateArray;
  for var i := 0 to m1.length - 1 do begin
    res[i] := TVariant.CreateArray;
    for var j := 0 to m2[0].length -1 do
    begin
    var sum := 0;
      for var k := 0 to m1[0].length - 1 do
      begin
        sum += m1[i][k] * m2[k][j];
      end;
        res[i][j] := sum;
    end;
  end;
  result := res;
end;

var res := multiplyMatrices(A1, A2);  
(*  res = [[72,104,136,168],[143,206,269,332],[214,308,402,496]]  *)

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...