unit DefaultArray;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Basic2, StdCtrls, ExtCtrls, MtxVec, Math387, ComCtrls, TeEngine, Series,
  TeeProcs, Chart, Buttons;

type
  TDefArray = class(TBasicForm2)
    TrackBar1: TTrackBar;
    Label1: TLabel;
    Label2: TLabel;
    RadioGroup1: TRadioGroup;
    Button1: TBitBtn;
    Chart1: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TLineSeries;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure TrackBar1Change(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure RadioGroup1Click(Sender: TObject);
  private
    TestVec : TVec;
    TestMtx : TMtx;
    Len     : Integer;
    function CumulativeSum(A: TVec): TSample; overload;
    function CumulativeSum(A: TMtx): TSample; overload;
    function CumulativeSumFast(A: TVec): TSample;overload;
    function CumulativeSumFast(A: TMtx): TSample;overload;
    function CumulativeSumFast1(A: TMtx): TSample;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DefArray: TDefArray;

implementation

{$R *.DFM}

function TDefArray.CumulativeSum(A: TVec): TSample;
var i : Integer;
    t : TSample;
begin
     t := 0;
     for i := 0 to A.Length - 1 do
        t := t + A[i];
     Result := t;
end;

function TDefArray.CumulativeSumFast(A: TVec): TSample;
var i : Integer;
    t : TSample;
    a1 : PSArray;
begin
     t := 0;
     a1 := Pointer(A.Values);
     for i := 0 to A.Length - 1  do
        t := t + a1[i];
     Result := t;
end;

function TDefArray.CumulativeSum(A: TMtx): TSample;
var i,j : Integer;
    t   : TSample;
begin
     t := 0;
     for i := 0 to A.Rows - 1 do
        for j := 0 to A.Cols -4 do
        begin
           t := t + A[i,j];
           t := t + A[i,j+1];
           t := t + A[i,j+2];
           t := t + A[i,j+3];
        end;
     Result := t;
end;

function TDefArray.CumulativeSumFast1(A: TMtx): TSample;
var i,j : Integer;
    a1  : T2DSampleArray;
    t   : TSample;
begin
     a1 := Pointer(A.Values);
     t := 0;
     for i := 0 to A.Rows -1  do
        for j := 0 to A.Cols -4 do
        begin
             t := t + a1[i,j];
             t := t + a1[i,j+1];
             t := t + a1[i,j+2];
             t := t + a1[i,j+3];
        end;
     Result := t;
end;

function TDefArray.CumulativeSumFast(A: TMtx): TSample;
var i,j  : Integer;
    a1 : PSArray;
    t  : TSample;
    k  : Integer;
begin
     t := 0;
     a1 := Pointer(A.Values1D);
     k := A.Cols;
     for i := 0 to A.Rows-1 do
        for j := 0 to A.Cols -4 do
     begin
             t := t + a1[i*k+j];
             t := t + a1[i*k+j+1];
             t := t + a1[i*k+j+2];
             t := t + a1[i*k+j+3];
     end;
     Result := t;
end;


procedure TDefArray.FormCreate(Sender: TObject);
begin
  inherited;
  With RichEdit1 do
  begin
    Lines.Clear;
    Lines.Add('There are three different ways on how to'
                      + ' access the elements of an array. '
                      + ' (vector or matrix). All access methods '+
                      '  work on the same block of memory.');

    Lines.Add('');
    Lines.Add('(*) Default arrays give you clear syntax, '
                      + 'but are not as fast:');
    SelAttributes.Name := 'Courier New';
    Lines.Add('a[i,j] := 1; {where "a" is TMtx object}');
    Lines.Add('');
    Lines.Add('(*) Dynamic array pointer is a bit faster than '
            + ' default array.');
    SelAttributes.Name := 'Courier New';
    Lines.Add('a.Values[i,j] := 3.5; {where "a" is TMtx object}');
    Lines.Add('');
    Lines.Add('(*) One dimensional array (TMtx object only) allows '
            + 'you to work with the matrix as you would with one '
            + 'dimensional array:');
    SelAttributes.Name := 'Courier New';
    Lines.Add('a.Values1D[i*Cols+j]:= 2.3; {where "a" is TMtx object}');
  end;
  TestVec := TVec.Create;
  TestMtx := TMtx.Create;
  RadioGroup1Click(RadioGroup1);
  TrackBar1Change(TrackBar1);
  TButton(Self.Owner.FindComponent('btnHelp')).Enabled := false;
end;

procedure TDefArray.FormDestroy(Sender: TObject);
begin
  TestMtx.Destroy;
  TestVec.Destroy;
  inherited;
end;

procedure TDefArray.TrackBar1Change(Sender: TObject);
begin
  Len := TTrackBar(Sender).Position;
  Label1.Caption := IntToStr(Len);
end;

procedure TDefArray.Button1Click(Sender: TObject);
var i : Integer;
    j : Integer;
    MaxIter : Integer;
begin
  { setup TestVec }
  Series1.Clear;
  Series2.Clear;
  Series3.Clear;
  Screen.Cursor := crHourGlass;
  j := 1;
  if RadioGroup1.ItemIndex = 0 then { test vector }
  begin
       if Len < 500 then MaxIter := 2000
       else if Len < 2000 then MaxIter := 1000
       else if Len < 5000 then MaxIter := 500
       else MaxIter := 100;
        while j < Len do
        begin
             TestVec.Size(j);
             TimeCheck := GetTickCount;
             { default arrays }
             for i := 1 to MaxIter do CumulativeSum(TestVec);
             TimeElapsed := GetTickCount - TimeCheck;
             Series1.AddXY(j,TimeElapsed,'',clTeeColor);
             TimeCheck := GetTickCount;
             { TSampleArray }
             for i := 1 to MaxIter do CumulativeSumFast(TestVec);
             TimeElapsed := GetTickCount - TimeCheck;
             Series2.AddXY(j,TimeElapsed,'',clTeeColor);
             if j < 10 then j := j +2
             else if j < 500 then j := j + 50
             else if j < 1000 then j := j + 100
             else if j < 3000 then j := j + 250
             else j := j + 1000;
        end
  end
  else
  begin
       if Len < 30 then MaxIter := 500
       else if Len < 70 then MaxIter := 250
       else MaxIter := 50;
       while j < Len do
       begin
            TestMtx.Size(j,j);
            TimeCheck := GetTickCount;
            { default arrays }
            for i := 1 to MaxIter do CumulativeSum(TestMtx);
            TimeElapsed := GetTickCount - TimeCheck;
            Series1.AddXY(j,TimeElapsed,'',clTeeColor);
            { TSampleArray fast}
            TimeCheck := GetTickCount;
            for i := 1 to MaxIter do CumulativeSumFast1(TestMtx);
            TimeElapsed := GetTickCount - TimeCheck;
            Series2.AddXY(j,TimeElapsed,'',clTeeColor);
            { TSampleArray ultra fast}
            TimeCheck := GetTickCount;
            for i := 1 to MaxIter do CumulativeSumFast(TestMtx);
            TimeElapsed := GetTickCount - TimeCheck;
            Series3.AddXY(j,TimeElapsed,'',clTeeColor);
            if j < 10 then j := j +2
            else if j < 50 then j := j + 5
            else if j < 100 then j := j + 10
            else if j < 200 then j := j + 15
            else j := j + 20;
       end;
  end;
  Chart1.LeftAxis.Title.Caption := 'time [ms] ('+IntToStr(MaxIter)+' iterations)';
  Screen.Cursor := crDefault;
end;

procedure TDefArray.RadioGroup1Click(Sender: TObject);
begin
  Case TRadioGroup(Sender).ItemIndex of
  0  : begin
            Label2.Caption := 'Vector length';
            TrackBar1.Max := 10000;
            TrackBar1.Frequency := 500;
       end;
  1  : begin
            Label2.Caption := 'Sqared matrix rows';
            TrackBar1.Max := 300;
            TrackBar1.Frequency := 10;
            TrackBar1.Position := 150;
       end;
  end;
  Series3.Active := TRadiogroup(Sender).ItemIndex <> 0;
  TrackBar1Change(TrackBar1);
end;

initialization
   RegisterClass(TDefArray);

end.
