From 44a49b43bd9fa68b0cd1bebd9d6d01e99298dc7e Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Fri, 10 Apr 2020 18:10:15 +0000 Subject: [PATCH] LazStats: Refactor DescrimUnit. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7368 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../lazstats/docs/HelpNDoc/LazStats.hnd | Bin 5795840 -> 5869568 bytes .../analysis/multivariate/discrimunit.lfm | 58 +- .../analysis/multivariate/discrimunit.pas | 573 +++++++++--------- .../lazstats/source/units/matrixlib.pas | 28 +- 4 files changed, 339 insertions(+), 320 deletions(-) diff --git a/applications/lazstats/docs/HelpNDoc/LazStats.hnd b/applications/lazstats/docs/HelpNDoc/LazStats.hnd index c03e78b536fc8e8439a8d2b0c32cf535b0560a30..0baf4995fdd06a6954971802bbee697f67aa1492 100644 GIT binary patch delta 46979 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ຠ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

7khU4!P?;Jz6N7e9udR>9l||; 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 diff --git a/applications/lazstats/source/forms/analysis/multivariate/discrimunit.lfm b/applications/lazstats/source/forms/analysis/multivariate/discrimunit.lfm index 28b6d68f8..722f7cfa6 100644 --- a/applications/lazstats/source/forms/analysis/multivariate/discrimunit.lfm +++ b/applications/lazstats/source/forms/analysis/multivariate/discrimunit.lfm @@ -13,77 +13,59 @@ object DiscrimFrm: TDiscrimFrm Position = poMainFormCenter LCLVersion = '2.1.0.0' object ResetBtn: TButton - AnchorSideRight.Control = CancelBtn + AnchorSideRight.Control = ComputeBtn AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 304 + Left = 396 Height = 25 Top = 424 Width = 54 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'Reset' OnClick = ResetBtnClick TabOrder = 2 end - object CancelBtn: TButton - AnchorSideRight.Control = ComputeBtn - AnchorSideBottom.Control = Owner - AnchorSideBottom.Side = asrBottom - Left = 370 - Height = 25 - Top = 424 - Width = 62 - Anchors = [akRight, akBottom] - AutoSize = True - BorderSpacing.Left = 12 - BorderSpacing.Top = 8 - BorderSpacing.Right = 12 - BorderSpacing.Bottom = 8 - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 3 - end object ComputeBtn: TButton - AnchorSideRight.Control = ReturnBtn + AnchorSideRight.Control = CloseBtn AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 444 + Left = 458 Height = 25 Top = 424 Width = 76 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 Caption = 'Compute' OnClick = ComputeBtnClick - TabOrder = 4 + TabOrder = 3 end - object ReturnBtn: TButton + object CloseBtn: TButton AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 532 + Left = 542 Height = 25 Top = 424 - Width = 61 + Width = 55 Anchors = [akRight, akBottom] AutoSize = True - BorderSpacing.Left = 12 + BorderSpacing.Left = 8 BorderSpacing.Top = 8 - BorderSpacing.Right = 12 + BorderSpacing.Right = 8 BorderSpacing.Bottom = 8 - Caption = 'Return' - ModalResult = 1 - TabOrder = 5 + Caption = 'Close' + ModalResult = 11 + TabOrder = 4 end object Panel1: TPanel AnchorSideLeft.Control = Owner @@ -152,6 +134,7 @@ object DiscrimFrm: TDiscrimFrm BorderSpacing.Right = 8 ItemHeight = 0 MultiSelect = True + OnSelectionChange = PredListSelectionChange TabOrder = 0 end object DepIn: TBitBtn @@ -362,6 +345,7 @@ object DiscrimFrm: TDiscrimFrm Top = 17 Width = 176 Anchors = [akTop, akLeft, akRight] + ReadOnly = True TabOrder = 3 Text = 'GroupVar' end @@ -380,6 +364,8 @@ object DiscrimFrm: TDiscrimFrm Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 8 ItemHeight = 0 + MultiSelect = True + OnSelectionChange = PredListSelectionChange TabOrder = 6 end end @@ -387,7 +373,7 @@ object DiscrimFrm: TDiscrimFrm AnchorSideLeft.Control = Owner AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = ReturnBtn + AnchorSideBottom.Control = CloseBtn Left = 0 Height = 8 Top = 408 diff --git a/applications/lazstats/source/forms/analysis/multivariate/discrimunit.pas b/applications/lazstats/source/forms/analysis/multivariate/discrimunit.pas index ac0d8a7ac..78264e6b9 100644 --- a/applications/lazstats/source/forms/analysis/multivariate/discrimunit.pas +++ b/applications/lazstats/source/forms/analysis/multivariate/discrimunit.pas @@ -1,3 +1,5 @@ +// Sample file for testing: manodiscrim.laz + unit DiscrimUnit; {$mode objfpc}{$H+} @@ -19,9 +21,8 @@ type Panel1: TPanel; Panel2: TPanel; ResetBtn: TButton; - CancelBtn: TButton; ComputeBtn: TButton; - ReturnBtn: TButton; + CloseBtn: TButton; DescChk: TCheckBox; PCovChk: TCheckBox; CentroidsChk: TCheckBox; @@ -53,6 +54,7 @@ type procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure PredInClick(Sender: TObject); + procedure PredListSelectionChange(Sender: TObject; User: boolean); procedure PredOutClick(Sender: TObject); procedure ResetBtnClick(Sender: TObject); private @@ -78,7 +80,8 @@ type GrpVar : integer; NoGrps : integer; NoInGrp : IntDyneVec; - VarLabels : StrDyneVec); + VarLabels : StrDyneVec; + AReport: TStrings); procedure ClassIt(Sender: TObject; PooledW : DblDyneMat; ColNoSelected : IntDyneVec; @@ -91,7 +94,9 @@ type NoSelected : integer; NoCases : integer; RawCmat : DblDyneMat; - Constants : DblDyneVec); + Constants : DblDyneVec; + AReport: TStrings); + procedure UpdateBtnStates; public { public declarations } end; @@ -102,28 +107,26 @@ var implementation uses - Math; + Math, Utils; { TDiscrimFrm } procedure TDiscrimFrm.ResetBtnClick(Sender: TObject); -VAR i : integer; +var + i: integer; begin - VarList.Clear; - PredList.Clear; - PredOut.Enabled := false; - PredIn.Enabled := true; - DepOut.Enabled := false; - DepIn.Enabled := true; - GroupVar.Text := ''; - DescChk.Checked := false; - CorrsChk.Checked := false; - InvChk.Checked := false; - PlotChk.Checked := false; - ClassChk.Checked := false; - AnovaChk.Checked := false; - for i := 1 to NoVariables do - VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); + VarList.Clear; + PredList.Clear; + GroupVar.Text := ''; + DescChk.Checked := false; + CorrsChk.Checked := false; + InvChk.Checked := false; + PlotChk.Checked := false; + ClassChk.Checked := false; + AnovaChk.Checked := false; + for i := 1 to NoVariables do + VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); + UpdateBtnStates; end; procedure TDiscrimFrm.FormActivate(Sender: TObject); @@ -133,11 +136,10 @@ begin if FAutoSized then exit; - w := MaxValue([ResetBtn.Width, CancelBtn.Width, ComputeBtn.Width, ReturnBtn.Width]); + w := MaxValue([ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]); ResetBtn.Constraints.MinWidth := w; - CancelBtn.Constraints.MinWidth := w; ComputeBtn.Constraints.MinWidth := w; - ReturnBtn.Constraints.MinWidth := w; + CloseBtn.Constraints.MinWidth := w; Panel1.Constraints.MinWidth := OptionsGroup.Width * 2 + DepIn.Width; Constraints.MinWidth := Width; Constraints.MinHeight := Height; @@ -148,8 +150,6 @@ end; procedure TDiscrimFrm.FormCreate(Sender: TObject); begin Assert(OS3MainFrm <> nil); - if OutputFrm = nil then - Application.CreateForm(TOutputFrm, OutputFrm); if GraphFrm = nil then Application.CreateForm(TGraphFrm, GraphFrm); if DictionaryFrm = nil then @@ -161,43 +161,49 @@ begin ResetBtnClick(self); end; -procedure TDiscrimFrm.DepInClick(Sender: TObject); -VAR index : integer; -begin - index := VarList.ItemIndex; - GroupVar.Text := VarList.Items.Strings[index]; - VarList.Items.Delete(index); - DepOut.Enabled := true; - DepIn.Enabled := false; -end; - procedure TDiscrimFrm.ComputeBtnClick(Sender: TObject); var - i, j, k, grp, grpvalue, matrow, matcol, noroots, dfchi, n2, k2 : integer; - NoSelected : integer; - outline, GroupLabel, ColHead : string; - Title : string; - GrpVar, NoGrps, nowithin, TotalCases, value, grpno : integer; - ColNoSelected : IntDyneVec; - CaseNo, NoInGrp : IntDyneVec; - VarLabels, ColLabels, GrpNos : StrDyneVec; - X, Y, GroupSS, ErrorSS, GroupMS, ErrorMS, TotalSS, num, s, v2, den : double; - Lambda, ChiSquare, Pillia, TotChi, p, Rc, chi, chiprob, m, L2, F, Fprob : double; - DFGroup, DFError, DFTotal, Fratio, prob, minroot, trace, pcnttrace : double; - probchi : double; - WithinMat, WithinInv, WinvB, v, PooledW, TotalMat, BetweenMat : DblDyneMat; - EigenVectors, EigenTrans, TempMat, Theta, DiagMat, CoefMat : DblDyneMat; - RawCMat, GrpMeans, GrpSDevs, Centroids, Structure : DblDyneMat; - Constants, ScoreVar, Roots, Pcnts, TotalMeans, TotalVariances : DblDyneVec; - TotalStdDevs, WithinMeans, WithinVariances, WithinStdDevs, w : DblDyneVec; - errorcode : boolean = false; + i, j, k, grp, grpvalue, matrow, matcol, noroots, dfchi, n2, k2 : integer; + NoSelected : integer; + outline, GroupLabel, ColHead : string; + Title : string; + GrpVar, NoGrps, nowithin, TotalCases, value, grpno : integer; + ColNoSelected : IntDyneVec; + CaseNo, NoInGrp : IntDyneVec; + VarLabels, ColLabels, GrpNos : StrDyneVec; + X, Y, GroupSS, ErrorSS, GroupMS, ErrorMS, TotalSS, num, s, v2, den : double; + Lambda, ChiSquare, Pillia, TotChi, p, Rc, chi, chiprob, m, L2, F, Fprob : double; + DFGroup, DFError, DFTotal, Fratio, prob, minroot, trace, pcnttrace : double; + probchi : double; + WithinMat, WithinInv, WinvB, v, PooledW, TotalMat, BetweenMat : DblDyneMat; + EigenVectors, EigenTrans, TempMat, Theta, DiagMat, CoefMat : DblDyneMat; + RawCMat, GrpMeans, GrpSDevs, Centroids, Structure : DblDyneMat; + Constants, ScoreVar, Roots, Pcnts, TotalMeans, TotalVariances : DblDyneVec; + TotalStdDevs, WithinMeans, WithinVariances, WithinStdDevs, w : DblDyneVec; + errorcode : boolean = false; + lReport: TStrings; begin - TotalCases := 0; - OutputFrm.RichEdit.Clear(); - OutputFrm.RichEdit.Lines.Add('MULTIVARIATE ANOVA / DISCRIMINANT FUNCTION'); - OutputFrm.RichEdit.Lines.Add('Reference: Multiple Regression in Behavioral Research'); - OutputFrm.RichEdit.Lines.Add('Elazar J. Pedhazur, 1997, Chapters 20-21'); - OutputFrm.RichEdit.Lines.Add('Harcourt Brace College Publishers'); + if GroupVar.Text = '' then + begin + MessageDlg('Group variable not selected.', mtError, [mbOK], 0); + exit; + end; + if PredList.Items.Count = 0 then + begin + MessageDlg('No Predictor variable(s) selected.', mtError, [mbOK], 0); + exit; + end; + + TotalCases := 0; + + lReport := TStringList.Create; + try + lReport.Add('MULTIVARIATE ANOVA / DISCRIMINANT FUNCTION'); + lReport.Add('Reference: Multiple Regression in Behavioral Research'); + lReport.Add('Elazar J. Pedhazur, 1997, Chapters 20-21'); + lReport.Add('Harcourt Brace College Publishers'); + lReport.Add(''); + NoSelected := PredList.Items.Count + 1; SetLength(ColNoSelected,NoVariables); SetLength(VarLabels,NoVariables); @@ -298,11 +304,8 @@ begin end; end; - OutputFrm.RichEdit.Lines.Add(''); - outline := format('Total Cases := %d, Number of Groups := %d', - [NoCases, NoGrps]); - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.RichEdit.Lines.Add(''); + lReport.Add('Total Cases: %d, Number of Groups: %d', [NoCases, NoGrps]); + lReport.Add(''); //Read the data for each group, accumulating cross-products and sums for grp := 1 to NoGrps do @@ -341,12 +344,12 @@ begin end; // next case // Does user want cross-products matrices ? - if (CrossChk.Checked = true) then + if CrossChk.Checked then begin // print within matrix - ColHead := format('Group %d, N = %d',[grp,nowithin]); + ColHead := Format('Group %d, N = %d', [grp, nowithin]); Title := 'SUM OF CROSS-PRODUCTS for ' + ColHead; - MAT_PRINT(WithinMat,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,nowithin); + MatPrint(WithinMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, nowithin, lReport); end; // Convert to deviation cross-products and pool @@ -354,20 +357,19 @@ begin begin for k := 1 to NoSelected - 1 do begin - WithinMat[j-1,k-1] := WithinMat[j-1,k-1] - - (WithinMeans[j-1] * WithinMeans[k-1] / nowithin); + WithinMat[j-1,k-1] := WithinMat[j-1,k-1] - (WithinMeans[j-1] * WithinMeans[k-1] / nowithin); PooledW[j-1,k-1] := PooledW[j-1,k-1] + WithinMat[j-1,k-1]; end; end; // Does user want deviation cross-products? - if (DevCPChk.Checked = true) then + if DevCPChk.Checked then begin // print within matrix - ColHead := format('Group %d, N := %d',[grpvalue,nowithin]); + ColHead := Format('Group %d, N = %d', [grpvalue, nowithin]); Title := 'WITHIN GROUP SUM OF DEVIATION CROSS-PRODUCTS ' + ColHead; - MAT_PRINT(WithinMat,NoSelected-1,NoSelected-1,Title,VarLabels, - VarLabels,nowithin); + MatPrint(WithinMat, NoSelected-1, NoSelected-1, Title, VarLabels, + VarLabels, nowithin, lReport); end; // Compute descriptives from sums and sums of squares @@ -384,17 +386,20 @@ begin if DescChk.Checked then begin // print mean, variance and std. dev.s for variables - outline := format('MEANS FOR GROUP %d, N := %d',[grp,nowithin]); - DynVectorPrint(WithinMeans,NoSelected-1,outline,VarLabels,nowithin); - outline := format('VARIANCES FOR GROUP %d',[grp]); - DynVectorPrint(WithinVariances,NoSelected-1,outline,VarLabels,nowithin); + outline := Format('MEANS FOR GROUP %d, N: %d', [grp, nowithin]); + DynVectorPrint(WithinMeans, NoSelected-1, outline, VarLabels, nowithin, lReport); + + outline := format('VARIANCES FOR GROUP %d', [grp]); + DynVectorPrint(WithinVariances, NoSelected-1, outline, VarLabels, nowithin, lReport); + outline := format('STANDARD DEVIATIONS FOR GROUP %d',[grp]); - DynVectorPrint(WithinStdDevs,NoSelected-1,outline,VarLabels,nowithin); + DynVectorPrint(WithinStdDevs, NoSelected-1, outline, VarLabels, nowithin, lReport); end; - if (DescChk.Checked) or (DevCPChk.Checked) or (CrossChk.Checked) then + + if DescChk.Checked or DevCPChk.Checked or CrossChk.Checked then begin - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Now initialize for the next group and save descriptives @@ -414,9 +419,9 @@ begin begin // print Total cross-products matrix Title := 'TOTAL SUM OF CROSS-PRODUCTS'; - MAT_PRINT(TotalMat,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(TotalMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; //Obtain Total deviation cross-products @@ -430,10 +435,11 @@ begin begin // print total deviation cross-products matrix Title := 'TOTAL SUM OF DEVIATION CROSS-PRODUCTS'; - MAT_PRINT(TotalMat,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(TotalMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; + for j := 1 to NoSelected - 1 do begin TotalVariances[j-1] := TotalVariances[j-1] - @@ -448,28 +454,29 @@ begin begin // print mean, variance and std. dev.s for variables Title := 'MEANS'; - DynVectorPrint(TotalMeans,NoSelected-1,Title,VarLabels,TotalCases); + DynVectorPrint(TotalMeans, NoSelected-1, Title, VarLabels, TotalCases, lReport); + Title := 'VARIANCES'; - DynVectorPrint(TotalVariances,NoSelected-1,Title,VarLabels,TotalCases); + DynVectorPrint(TotalVariances, NoSelected-1, Title, VarLabels, TotalCases, lReport); + Title := 'STANDARD DEVIATIONS'; - DynVectorPrint(TotalStdDevs,NoSelected-1,Title,VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + DynVectorPrint(TotalStdDevs, NoSelected-1, Title, VarLabels, TotalCases, lReport); + + lReport.Add(DIVIDER); + lReport.Add(''); end; // Obtain between groups deviation cross-products matrix - MATSUB(BetweenMat,TotalMat,PooledW,NoSelected-1,NoSelected-1, - NoSelected-1,NoSelected-1,errorcode); + MatSub(BetweenMat, TotalMat, PooledW, NoSelected-1, NoSelected-1, NoSelected-1, NoSelected-1, errorcode); // Does user want deviation cross-products? if DevCPChk.Checked then begin // print between groups deviation cross-products matrix Title := 'BETWEEN GROUPS SUM OF DEV. CPs'; - MAT_PRINT(BetweenMat,NoSelected-1,NoSelected-1,Title,VarLabels, - VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(BetweenMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Do univariate ANOVA's for each variable @@ -477,10 +484,10 @@ begin begin for j := 1 to NoSelected - 1 do begin - outline := format('UNIVARIATE ANOVA FOR VARIABLE %s', - [VarLabels[j-1]]); - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.RichEdit.Lines.Add('SOURCE DF SS MS F PROB > F'); + lReport.Add('UNIVARIATE ANOVA FOR VARIABLE %s', [VarLabels[j-1]]); + lReport.Add(''); + lReport.Add('SOURCE DF SS MS F PROB > F'); + lReport.Add('---------- ---- ---------- ---------- ---------- ----------'); GroupSS := BetweenMat[j-1,j-1]; ErrorSS := PooledW[j-1,j-1]; TotalSS := TotalMat[j-1,j-1]; @@ -491,18 +498,13 @@ begin ErrorMS := ErrorSS / DFError; Fratio := GroupMS / ErrorMS; prob := probf(Fratio,DFGroup,DFError); - outline := format('BETWEEN %3.0f%10.3f%10.3f%10.3f%10.3f', - [DFGroup,GroupSS,GroupMS,Fratio,prob]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := format('ERROR %3.0f%10.3f%10.3f', - [DFError,ErrorSS,ErrorMS]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := format('TOTAL %3.0f%10.3f',[DFTotal,TotalSS]); - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.RichEdit.Lines.Add(''); + lReport.Add('BETWEEN %4.0f %10.3f %10.3f %10.3f %10.3f', [DFGroup,GroupSS,GroupMS,Fratio,prob]); + lReport.Add('ERROR %4.0f %10.3f %10.3f', [DFError,ErrorSS,ErrorMS]); + lReport.Add('TOTAL %4.0f %10.3f',[DFTotal,TotalSS]); + lReport.Add(''); end; - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Get roots of the product of the within group inverse times between @@ -516,9 +518,9 @@ begin if InvChk.Checked then begin Title := 'Inv. of Pooled Within Dev. CPs Matrix'; - MAT_PRINT(WithinInv,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(WithinInv, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Get roots of the W inverse times Betweeen matrices @@ -529,15 +531,12 @@ begin trace := 0.0; pcnttrace := 0.0; nonsymroots(WinvB,NoSelected-1,noroots,minroot,EigenVectors,Roots,Pcnts,trace,pcnttrace); - outline := format('Number of roots extracted := %d',[noroots]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := format('Percent of trace extracted := %10.4f',[pcnttrace]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := 'Roots of the W inverse time B Matrix'; - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.RichEdit.Lines.Add(''); - outline := 'No. Root Proportion Canonical R Chi-Squared D.F. Prob.'; - OutputFrm.RichEdit.Lines.Add(outline); + lReport.Add('Number of roots extracted: %d', [noroots]); + lReport.Add('Percent of trace extracted: %10.4f',[pcnttrace]); + lReport.Add('Roots of the W inverse time B Matrix'); + lReport.Add(''); + lReport.Add('No. Root Proportion Canonical R Chi-Squared D.F. Prob.'); + lReport.Add('--- ---------- ---------- ------------ ------------ ---- -------'); Lambda := 1.0; ChiSquare := 0.0; Pillia := 0.0; @@ -555,22 +554,21 @@ begin dfchi := (NoSelected - i) * (NoGrps - i ); chi := TotChi * (TotalCases - 1.0 - 0.5 * (NoSelected + NoGrps)); chiprob := 1.0 - chisquaredprob(chi,dfchi); - outline := format('%2d %10.4f %6.4f %6.4f %10.4f %3d %6.3f', - [i,Roots[i-1],p,Rc,chi,dfchi,chiprob]); - OutputFrm.RichEdit.Lines.Add(outline); + lReport.Add('%3d %10.4f %10.4f %12.4f %12.4f %4d %6.3f', [i, Roots[i-1], p, Rc, chi, dfchi, chiprob]); TotChi := TotChi - ln(1.0 + Roots[i-1]); end; ChiSquare := ChiSquare * ((TotalCases - 1) - (0.5 * (NoSelected - 1 + NoGrps))); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + lReport.Add(''); + lReport.Add(DIVIDER); + lReport.Add(''); for i := 1 to noroots do ColLabels[i-1] := IntToStr(i); if EigensChk.Checked then begin Title := 'Eigenvectors of the W inverse x B Matrix'; - MAT_PRINT(EigenVectors,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(EigenVectors, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Now get covariance matrices for the total and within @@ -586,27 +584,27 @@ begin if PCovChk.Checked then begin Title := 'Pooled Within-Groups Covariance Matrix'; - MAT_PRINT(PooledW,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); + MatPrint(PooledW, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); Title := 'Total Covariance Matrix'; - MAT_PRINT(TotalMat,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(TotalMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; //Get the pooled within groups variance-covariance of disc. scores matrix v'C v - MATTRN(EigenTrans,EigenVectors, NoSelected-1,noroots); // v' - MATAxB(TempMat,EigenTrans,PooledW,noroots,NoSelected-1,NoSelected-1, - NoSelected-1,errorcode);//v'C - MATAxB(Theta,TempMat,EigenVectors,noroots,NoSelected-1,NoSelected-1, - noroots, errorcode); //v'C v + MatTrn(EigenTrans, EigenVectors, NoSelected-1, noroots); // v' + MatAxB(TempMat, EigenTrans, PooledW, noroots, NoSelected-1, NoSelected-1, NoSelected-1,errorcode);//v'C + MatAxB(Theta, TempMat, EigenVectors, noroots, NoSelected-1, NoSelected-1, noroots, errorcode); //v'C v //Create a diagonal matrix with square roots of the diagonal of the Within for i := 1 to NoSelected - 1 do begin for j := 1 to NoSelected - 1 do begin - if (i <> j) then DiagMat[i-1,j-1] := 0.0 - else DiagMat[i-1,j-1] := sqrt(PooledW[i-1,j-1]); + if (i <> j) then + DiagMat[i-1,j-1] := 0.0 + else + DiagMat[i-1,j-1] := sqrt(PooledW[i-1,j-1]); end; end; @@ -636,37 +634,35 @@ begin // Plot discriminant scores? if PlotChk.Checked then - begin - PlotPts(self,RawCMat,Constants,ColNoSelected,NoSelected, - noroots,NoCases,GrpVar,NoGrps,NoInGrp); - end; + PlotPts(self,RawCMat,Constants,ColNoSelected,NoSelected, noroots,NoCases,GrpVar,NoGrps,NoInGrp); // print discrim functions - Title := 'Raw Function Coeff.s from Pooled Cov.'; - MAT_PRINT(RawCMat,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); - Title := 'Raw Discriminant Function Constants'; - DynVectorPrint(Constants,noroots,Title,ColLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + Title := 'Raw Function Coeff.s from Pooled Cov.'; + MatPrint(RawCMat, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); + Title := 'Raw Discriminant Function Constants'; + DynVectorPrint(Constants, noroots, Title, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); //Does user want to classify cases using canonical functions? if ClassChk.Checked then begin Classify(self,PooledW, GrpMeans, ColNoSelected, NoSelected-1, NoCases, - GrpVar, NoGrps, NoInGrp, VarLabels); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear; + GrpVar, NoGrps, NoInGrp, VarLabels, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); + ClassIt(self,PooledW,ColNoSelected,GrpMeans,Roots,noroots, GrpVar, - NoGrps,NoInGrp,NoSelected-1,NoCases,RawCMat,Constants); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear; + NoGrps,NoInGrp,NoSelected-1,NoCases,RawCMat,Constants, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // print standardized discrim function coefficients Title := 'Standardized Coeff. from Pooled Cov.'; - MAT_PRINT(CoefMat,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(CoefMat, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); // Calculate centroids for k := 1 to NoGrps do @@ -674,9 +670,7 @@ begin for i := 1 to noroots do begin for j := 1 to NoSelected - 1 do - begin Centroids[k-1,i-1] := Centroids[k-1,i-1] + (RawCMat[j-1,i-1] * GrpMeans[k-1,j-1]); - end; Centroids[k-1,i-1] := Centroids[k-1,i-1] + Constants[i-1]; end; end; @@ -684,54 +678,51 @@ begin if CentroidsChk.Checked then begin Title := 'Centroids'; - MAT_PRINT(Centroids,NoGrps,noroots,Title,GrpNos,ColLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(Centroids, NoGrps, noroots, Title, GrpNos, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Get variance-covariance matrix of functions (theta) - MATTRN(EigenTrans,EigenVectors,NoSelected-1,noroots); - MATAxB(TempMat,EigenTrans,TotalMat,noroots,NoSelected-1,NoSelected-1, - NoSelected-1,errorcode); - MATAxB(Theta,TempMat,EigenVectors,noroots,NoSelected-1,NoSelected-1, - noroots,errorcode); + MatTrn(EigenTrans, EigenVectors, NoSelected-1, noroots); + MatAxB(TempMat, EigenTrans, TotalMat, noroots, NoSelected-1, NoSelected-1, + NoSelected-1, errorcode); + MatAxB(Theta, TempMat, EigenVectors, noroots, NoSelected-1, NoSelected-1, + noroots, errorcode); // Create a diagonal matrix with square roots of the Total covariance diagonal for i := 1 to NoSelected - 1 do - begin for j := 1 to NoSelected - 1 do - begin - if (i <> j) then DiagMat[i-1,j-1] := 0.0 - else DiagMat[i-1,j-1] := sqrt(TotalMat[i-1,j-1]); - end; - end; + if (i <> j) then + DiagMat[i-1,j-1] := 0.0 + else + DiagMat[i-1,j-1] := sqrt(TotalMat[i-1,j-1]); // Get recipricol of standard deviations of each function - for i := 1 to noroots do ScoreVar[i-1] := 1.0 / sqrt(Theta[i-1,i-1]); + for i := 1 to noroots do + ScoreVar[i-1] := 1.0 / sqrt(Theta[i-1,i-1]); // Divide coefficients by score standard deviations for i := 1 to NoSelected - 1 do - begin for j := 1 to noroots do begin RawCMat[i-1,j-1] := EigenVectors[i-1,j-1] * ScoreVar[j-1]; CoefMat[i-1,j-1] := RawCMat[i-1,j-1] * sqrt(TotalMat[i-1,i-1]); end; - end; // print functions obtained from total matrix Title := 'Raw Coefficients from Total Cov.'; - MAT_PRINT(RawCMat,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); + MatPrint(RawCMat, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); Title := 'Raw Discriminant Function Constants'; - DynVectorPrint(Constants,noroots,Title,ColLabels,TotalCases); -// OutputFrm.ShowModal; -// OutputFrm.RichEdit.Clear(); + DynVectorPrint(Constants, noroots, Title, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); // print std. disc coefficients from total matrix Title := 'Standardized Coeff.s from Total Cov.'; - MAT_PRINT(CoefMat,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + MatPrint(CoefMat, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); // Get correlations from Total covariance matrix for i := 1 to NoSelected - 1 do @@ -742,15 +733,15 @@ begin if CorrsChk.Checked then begin Title := 'Total Correlation Matrix'; - MAT_PRINT(TempMat,NoSelected-1,NoSelected-1,Title,VarLabels,VarLabels,TotalCases); -// OutputFrm.ShowModal; -// OutputFrm.RichEdit.Clear(); + MatPrint(TempMat, NoSelected-1, NoSelected-1, Title, VarLabels, VarLabels, TotalCases, lReport); + lReport.Add(DIVIDER); + lReport.Add(''); end; // Obtain structure coefficients - MATAxB(Structure,TempMat,CoefMat,NoSelected-1,NoSelected-1,NoSelected-1,noroots,errorcode); + MatAxB(Structure, TempMat, CoefMat, NoSelected-1, NoSelected-1, NoSelected-1, noroots, errorcode); Title := 'Corr.s Between Variables and Functions'; - MAT_PRINT(Structure,NoSelected-1,noroots,Title,VarLabels,ColLabels,TotalCases); + MatPrint(Structure, NoSelected-1, noroots, Title, VarLabels, ColLabels, TotalCases, lReport); //Compute and print overall statistics for equal group centroids n2 := (NoSelected-1) * (NoSelected-1); @@ -763,22 +754,28 @@ begin L2 := Power(Lambda,1.0 / s); F := ((1.0 - L2)/ L2) * (den / num); Fprob := probf(F,num,den); - outline := format('Wilk''s Lambda = %10.4f.',[Lambda]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := format('F = %10.4f with D.F. %5.0f and %5.0f . Prob > F = %6.4f', - [F,num,den,Fprob]); - OutputFrm.RichEdit.Lines.Add(outline); + lReport.Add('Wilk''s Lambda: %10.4f', [Lambda]); + lReport.Add('F: %10.4f', [F]); + lReport.Add(' with D.F. %10.0f and %.0f', [num, den]); + lReport.Add(' prob > F: %10.4f', [Fprob]); + lReport.Add(''); + dfchi := (NoSelected - 1) * noroots; probchi := 1.0 - chisquaredprob(ChiSquare,dfchi); - outline := format('Bartlett Chi-Squared = %10.4f with %d D.F. and prob. = %6.4f', - [ChiSquare,dfchi,probchi]); - OutputFrm.RichEdit.Lines.Add(outline); - outline := format('Pillai Trace = %10.4f',[Pillia]); - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.ShowModal; - OutputFrm.RichEdit.Clear(); + lReport.Add('Bartlett Chi-Squared: %10.4f', [ChiSquare]); + lReport.Add(' with D.F. %10d', [dfchi]); + lReport.Add(' and prob. %10.4f', [probchi]); + lReport.Add(''); - // Clean up heap + lReport.Add('Pillai Trace %10.4f', [Pillia]); + lReport.Add(''); + + lReport.Add(DIVIDER); + lReport.Add(''); + + DisplayReport(lReport); + finally + lReport.Free; ColNoSelected := nil; NoInGrp := nil; GrpNos := nil; @@ -814,46 +811,74 @@ begin CaseNo := nil; ColLabels := nil; VarLabels := nil; + end; end; +procedure TDiscrimFrm.DepInClick(Sender: TObject); +var + index: Integer; +begin + index := VarList.ItemIndex; + if (index > -1) and (GroupVar.Text = '') then + begin + GroupVar.Text := VarList.Items[index]; + VarList.Items.Delete(index); + end; + UpdateBtnStates; +end; + + procedure TDiscrimFrm.DepOutClick(Sender: TObject); begin - VarList.Items.Add(GroupVar.Text); - GroupVar.Text := ''; - DepOut.Enabled := false; - DepIn.Enabled := true; + if GroupVar.Text <> '' then + begin + VarList.Items.Add(GroupVar.Text); + GroupVar.Text := ''; + end; + UpdateBtnStates; end; procedure TDiscrimFrm.PredInClick(Sender: TObject); -VAR i, index : integer; +var + i: integer; begin - index := VarList.Items.Count; - i := 0; - while i < index do - begin - if (VarList.Selected[i]) then - begin - PredList.Items.Add(VarList.Items.Strings[i]); - VarList.Items.Delete(i); - index := index - 1; - i := 0; - end - else i := i + 1; - end; - PredOut.Enabled := true; + i := 0; + while i < VarList.Items.Count do + begin + if VarList.Selected[i] then + begin + PredList.Items.Add(VarList.Items[i]); + VarList.Items.Delete(i); + i := 0; + end + else + i := i + 1; + end; + UpdateBtnStates; +end; + +procedure TDiscrimFrm.PredListSelectionChange(Sender: TObject; User: boolean); +begin + UpdateBtnStates; end; procedure TDiscrimFrm.PredOutClick(Sender: TObject); -VAR index : integer; +var + i: integer; begin - index := PredList.ItemIndex; - if index < 0 then - begin - PredOut.Enabled := false; - exit; - end; - VarList.Items.Add(PredList.Items.Strings[index]); - PredList.Items.Delete(index); + i := 0; + while i < PredList.Items.Count do + begin + if PredList.Selected[i] then + begin + VarList.Items.Add(PredList.Items[i]); + PredList.Items.Delete(i); + i := 0; + end + else + i := i + 1; + end; + UpdateBtnStates; end; procedure TDiscrimFrm.PlotPts(Sender: TObject; RawCMat: DblDyneMat; @@ -941,7 +966,7 @@ begin GraphFrm.AutoScaled := true; GraphFrm.PtLabels := true; GraphFrm.GraphType := 7; // 2d points - GraphFrm.BackColor := clYellow; + GraphFrm.BackColor := clCream; GraphFrm.ShowBackWall := true; GraphFrm.ShowModal; end; // next i @@ -956,16 +981,14 @@ end; procedure TDiscrimFrm.Classify(Sender: TObject; PooledW: DblDyneMat; GrpMeans: DblDyneMat; ColNoSelected: IntDyneVec; NoSelected: integer; NoCases: integer; GrpVar: integer; NoGrps: integer; NoInGrp: IntDyneVec; - VarLabels: StrDyneVec); + VarLabels: StrDyneVec; AReport: TStrings); var i, j, k, grp : integer; outline : string; Constant, T : DblDyneVec; S : double; Coeff, WithinInv : DblDyneMat; - begin -// SetLength(NoInGrp,NoGrps); SetLength(T,NoSelected); SetLength(Coeff,NoGrps,NoSelected); SetLength(WithinInv,NoSelected,NoSelected); @@ -978,7 +1001,7 @@ begin SVDinverse(WithinInv,NoSelected); // Get Fisher Discrim Functions and probabilities - OutputFrm.RichEdit.Lines.Add('Fisher Discriminant Functions'); + AReport.Add('FISHER DISCRIMINANT FUNCTIONS'); for grp := 0 to NoGrps-1 do begin Constant[grp] := 0.0; @@ -994,15 +1017,12 @@ begin T[j] := T[j] + WithinInv[j,k] * GrpMeans[grp,k]; end; for j := 0 to NoSelected-1 do Coeff[grp,j] := T[j]; - outline := format('Group %3d Constant := %6.3f',[grp+1,Constant[grp]]); - OutputFrm.RichEdit.Lines.Add(outline); - OutputFrm.RichEdit.Lines.Add('Variable Coefficient'); + AReport.Add('Group %d Constant: %6.3f', [grp+1, Constant[grp]]); + AReport.Add('Variable Coefficient'); + AReport.Add('-------- -----------'); for i := 0 to NoSelected-1 do - begin - outline := format(' %3d %6.3f',[i+1,T[i]]); - OutputFrm.RichEdit.Lines.Add(outline); - end; - OutputFrm.RichEdit.Lines.Add(''); + AReport.Add('%8d %11.3f', [i+1, T[i]]); + AReport.Add(''); end; // next group // clean up the heap @@ -1010,14 +1030,13 @@ begin WithinInv := nil; Coeff := nil; T := nil; -// NoInGrp := nil; end; procedure TDiscrimFrm.ClassIt(Sender: TObject; PooledW: DblDyneMat; ColNoSelected: IntDyneVec; GrpMeans: DblDyneMat; Roots: DblDyneVec; noroots: integer; GrpVar : integer; NoGrps: integer; NoInGrp: IntDyneVec; NoSelected: integer; NoCases: integer; RawCmat: DblDyneMat; - Constants: DblDyneVec); + Constants: DblDyneVec; AReport: TStrings); var i, j, k, grp, j1, InGrp, Largest, SecdLarge, oldcolcnt, linecount : integer; numberstr, prompt, outline, cellname : string; @@ -1077,20 +1096,19 @@ begin for i := 1 to noroots do Determinant := Determinant * Roots[i-1]; linecount := 0; + // Print Heading - OutputFrm.RichEdit.Clear; - OutputFrm.RichEdit.Lines.Add(''); - outline := 'CLASSIFICATION OF CASES'; - OutputFrm.RichEdit.Lines.Add(outline); - outline := 'SUBJECT ACTUAL HIGH PROBABILITY SEC.D HIGH DISCRIM'; - OutputFrm.RichEdit.Lines.Add(outline); - outline := 'ID NO. GROUP IN GROUP P(G/D) GROUP P(G/D) SCORE'; - OutputFrm.RichEdit.Lines.Add(outline); + AReport.Add('CLASSIFICATION OF CASES'); + AReport.Add(''); + AReport.Add('SUBJECT ACTUAL HIGH PROBABILITY SEC.D HIGH DISCRIM'); + AReport.Add('ID NO. GROUP IN GROUP P(G/D) GROUP P(G/D) SCORE'); + AReport.Add('------- ------ ---- ------------ ----- ------ -------'); linecount := linecount + 4; //Get selected priors // Default priors are equal proportions - for j := 1 to NoGrps do Apriori[j-1] := 1.0 / NoGrps; + for j := 1 to NoGrps do + Apriori[j-1] := 1.0 / NoGrps; if ClassSizeGroup.ItemIndex = 1 then begin // Get apriori probabilities @@ -1111,12 +1129,14 @@ begin // Calculate group probabilities for each case for i := 1 to NoCases do begin + { if (linecount >= 59) then begin OutputFrm.ShowModal; OutputFrm.RichEdit.Clear; linecount := 0; end; + } if (not GoodRecord(i,NoSelected,ColNoSelected))then continue; InGrp := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[GrpVar,i]))); InGrp := NoGrps - (MaxGrp - InGrp); @@ -1156,7 +1176,7 @@ begin begin for j := 1 to noroots do begin - numberstr := format('%8.3f',[Discrim[j-1]]); + numberstr := Format('%8.3f', [Discrim[j-1]]); OS3MainFrm.DataGrid.Cells[oldcolcnt+j,i] := numberstr; end; end; @@ -1186,16 +1206,13 @@ begin end; // Print results for this case i - outline := format('%3d %3d %3d %6.4f %3d %6.4f %7.4f', - [i,InGrp,Largest,LargestProb,SecdLarge,SecdProb, - Discrim[0]]); - OutputFrm.RichEdit.Lines.Add(outline); + AReport.Add('%7d %6d %4d %12.4f %5d %6.4f %7.4f', [ + i,InGrp,Largest,LargestProb,SecdLarge,SecdProb, Discrim[0] + ]); linecount := linecount + 1; for j := 2 to noroots do begin - outline := format(' %7.4f', - [Discrim[j-1]]); - OutputFrm.RichEdit.Lines.Add(outline); + AReport.Add(' %7.4f', [Discrim[j-1]]); linecount := linecount + 1; end; Table[InGrp-1,Largest-1] := Table[InGrp-1,Largest-1] + 1; @@ -1212,9 +1229,11 @@ begin if (linecount > 0) then begin - OutputFrm.ShowModal(); - OutputFrm.RichEdit.Clear; + AReport.Add(''); + AReport.Add(DIVIDER); + AReport.Add(''); end; + // Print table of classifications for i := 1 to NoGrps + 1 do begin @@ -1224,7 +1243,8 @@ begin RowLabels[NoGrps] := 'TOTAL'; ColLabels[NoGrps] := 'TOTAL'; IntArrayPrint(Table, NoGrps+1,NoGrps+1, 'PREDICTED GROUP', - RowLabels, ColLabels, 'CLASSIFICATION TABLE'); + RowLabels, ColLabels, 'CLASSIFICATION TABLE', + AReport); // Clean up the heap WithinInv := nil; @@ -1240,6 +1260,17 @@ begin Table := nil; end; +procedure TDiscrimFrm.UpdateBtnStates; +var + varSelected: Boolean; +begin + varSelected := AnySelected(VarList); + DepIn.Enabled := varSelected and (GroupVar.Text = ''); + PredIn.Enabled := varSelected; + Depout.Enabled := (GroupVar.Text <> ''); + PredOut.Enabled := AnySelected(PredList); +end; + initialization {$I discrimunit.lrs} diff --git a/applications/lazstats/source/units/matrixlib.pas b/applications/lazstats/source/units/matrixlib.pas index 7745960f0..4c4f0617d 100644 --- a/applications/lazstats/source/units/matrixlib.pas +++ b/applications/lazstats/source/units/matrixlib.pas @@ -141,8 +141,8 @@ procedure MReg2(NCases : integer; PrintInv : boolean; AReport: TStrings); -procedure MATSUB(VAR a, b, c : DblDyneMat; - brows, bcols, crows, ccols : integer; VAR errorcode : boolean); +procedure MatSub(const a, b, c: DblDyneMat; + brows, bcols, crows, ccols: integer; out errorcode: boolean); procedure IntArrayPrint(mat : IntDyneMat; rows, cols : integer; @@ -1494,19 +1494,21 @@ begin end; //--------------------------------------------------------------------------- -procedure MATSUB(VAR a, b, c : DblDyneMat; - brows, bcols, crows, ccols : integer; VAR errorcode : boolean); +procedure MatSub(const a, b, c: DblDyneMat; + brows, bcols, crows, ccols: integer; out errorcode: boolean); // Subtracts matrix c from b and returns the results in matrix a -var i, j : integer; +var + i, j: integer; begin - errorcode := FALSE; - if ((brows <> crows) or (bcols <> ccols)) then errorcode := TRUE - else - begin - for i := 0 to brows-1 do - for j := 0 to bcols-1 do - a[i,j] := b[i,j] - c[i,j]; - end; + errorcode := false; + if (brows <> crows) or (bcols <> ccols) then + errorcode := true + else + begin + for i := 0 to brows-1 do + for j := 0 to bcols-1 do + a[i,j] := b[i,j] - c[i,j]; + end; end; { of matsub } //---------------------------------------------------------------------------