Files
lazarus-ccr/applications/lazstats/source/forms/simulations/genrndvalsunit.pas

518 lines
13 KiB
ObjectPascal
Raw Normal View History

unit GenRndValsUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
ExtCtrls,
StdCtrls, Globals, MainUnit, DictionaryUnit;
type
TDistType = (dtUnknown, dtFlatInt, dtFlatReal, dtNormal, dtChiSq, dtF);
{ TGenRndValsFrm }
TGenRndValsFrm = class(TForm)
Bevel1: TBevel;
GroupBox1: TGroupBox;
NoCasesEdit: TEdit;
Label11: TLabel;
Panel1: TPanel;
rbFDistributionValues: TRadioButton;
rbChiSquaredValues: TRadioButton;
rbNormalZValues: TRadioButton;
rbFlatInteger: TRadioButton;
rbFlatFloatingPoint: TRadioButton;
ResetBtn: TButton;
ComputeBtn: TButton;
CloseBtn: TButton;
ChiDFEdit: TEdit;
FDF2Edit: TEdit;
FDF1Edit: TEdit;
FDF2Label: TLabel;
ChiSqDFLabel: TLabel;
FDF1Label: TLabel;
zSDEdit: TEdit;
zMeanEdit: TEdit;
HiRealEdit: TEdit;
AndRealLabel: TLabel;
MeanLabel: TLabel;
SDLabel: TLabel;
LowRealEdit: TEdit;
LowRealLabel: TLabel;
LowIntEdit: TEdit;
HiIntEdit: TEdit;
LowIntLabel: TLabel;
AndIntLabel: TLabel;
LabelEdit: TEdit;
Label1: TLabel;
RadioGroup1: TRadioGroup;
procedure ComputeBtnClick(Sender: TObject);
procedure FDF1EditKeyPress(Sender: TObject; var Key: char);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure LowIntEditKeyPress(Sender: TObject; var Key: char);
procedure LowRealEditKeyPress(Sender: TObject; var Key: char);
procedure NoCasesEditExit(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
procedure DistTypeChange(Sender: TObject);
procedure ResetBtnClick(Sender: TObject);
procedure zMeanEditKeyPress(Sender: TObject; var Key: char);
private
{ private declarations }
Ncases: integer;
DistType: TDistType;
function Validate(out AMsg: String; out AControl: TWinControl): boolean;
public
{ public declarations }
end;
var
GenRndValsFrm: TGenRndValsFrm;
implementation
uses
Math;
{ TGenRndValsFrm }
procedure TGenRndValsFrm.RadioGroup1Click(Sender: TObject);
begin
(*
if RadioGroup1.ItemIndex = 1 then
begin
if NoCases <= 0 then
begin
MessageDlg('There are currently no cases!', mtError, [mbOK], 0);
exit;
end
else
Ncases := NoCases
end else
NoCasesEdit.SetFocus;
*)
end;
procedure TGenRndValsFrm.LowIntEditKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then HiIntEdit.SetFocus;
end;
procedure TGenRndValsFrm.FDF1EditKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then FDF2Edit.SetFocus;
end;
procedure TGenRndValsFrm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
if DictionaryFrm = nil then
Application.CreateForm(TDictionaryFrm, DictionaryFrm);
end;
procedure TGenRndValsFrm.ComputeBtnClick(Sender: TObject);
var
i, j : integer;
col : integer;
RndNo : integer;
RealRnd : double;
Range : integer;
MinReal, MaxReal : double;
Mean, StdDev : double;
SumX1, SumX2 : double;
df1, df2 : integer;
C: TWinControl;
msg: String;
begin
if not Validate(msg, C) then begin
C.SetFocus;
MessageDlg(msg, mtError, [mbOK], 0);
exit;
end;
if (RadioGroup1.ItemIndex = 1) then
if NoCases < Ncases then
begin
OS3MainFrm.DataGrid.RowCount := NCases + 1;
OS3MainFrm.NoCasesEdit.Text := IntToStr(NCases);
NoCases := Ncases;
end;
if NoCases <= 0 then
begin
MessageDlg('There are currently no cases.', mtError, [mbOK], 0);
exit;
end;
DictionaryFrm.DictGrid.ColCount := 8;
if NoVariables <= 0 then // a new data file
begin
OS3MainFrm.DataGrid.ColCount := 2;
for i := 1 to Ncases do
OS3MainFrm.DataGrid.Cells[0,i] := Format('Case %d',[i]);
col := 1;
DictionaryFrm.DictGrid.RowCount := 1;
DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := LabelEdit.Text;
OS3MainFrm.DataGrid.Cells[col,0] := LabelEdit.Text;
end
else // existing data file
begin
col := NoVariables + 1;
DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := LabelEdit.Text;
OS3MainFrm.DataGrid.Cells[col,0] := LabelEdit.Text;
end;
Randomize;
case DistType of
dtFlatInt:
begin // range of integers
Range := StrToInt(HiIntEdit.Text) - StrToInt(LowIntEdit.Text);
for i := 1 to Ncases do
begin
RndNo := random(Range);
RndNo := RndNo + StrToInt(LowIntEdit.Text);
OS3MainFrm.DataGrid.Cells[col,i] := IntToStr(RndNo);
end;
end;
dtFlatReal:
begin // range of real random numbers
MinReal := StrToFloat(LowRealEdit.Text);
MaxReal := StrToFloat(HiRealEdit.Text);
Range := round(MaxReal - MinReal);
for i := 1 to Ncases do
begin
RealRnd := random;
RndNo := random(Range);
RealRnd := RndNo + RealRnd + MinReal;
OS3MainFrm.DataGrid.Cells[col,i] := format('%.3f',[RealRnd]);
end;
end;
dtNormal:
begin // normally distributed z score
Mean := StrToFloat(zMeanEdit.Text);
StdDev := StrToFloat(zSDEdit.Text);
for i := 1 to Ncases do
begin
RealRnd := RandG(Mean, StdDev);
OS3MainFrm.DataGrid.Cells[col,i] := format('%.3f',[RealRnd]);
end;
end;
dtChiSq:
begin // Chi square is a sum of df squared normally distributed z scores
df1 := StrToInt(ChiDFEdit.Text);
for i := 1 to Ncases do
begin
SumX1 := 0.0;
for j := 1 to df1 do
begin
RealRnd := RandG(0.0, 1.0);
SumX1 := SumX1 + sqr(RealRnd);
end;
OS3MainFrm.DataGrid.Cells[col,i] := format('%.3f', [SumX1]);
end;
end;
dtF:
begin // F ratio is a ratio of two independent chi-squares
df1 := StrToInt(FDF1Edit.Text);
df2 := StrToInt(FDF2Edit.Text);
for i := 1 to Ncases do
begin
SumX1 := 0.0;
SumX2 := 0.0;
for j := 1 to df1 do
begin
RealRnd := RandG(0.0, 1.0);
SumX1 := SumX1 + sqr(RealRnd);
end;
for j := 1 to df2 do
begin
RealRnd := RandG(0.0, 1.0);
SumX2 := SumX2 + sqr(RealRnd);
end;
RealRnd := SumX1 / SumX2;
OS3MainFrm.DataGrid.Cells[col,i] := format('%.3f',[RealRnd]);
end;
end;
end;
NoVariables := col;
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
OS3MainFrm.NoCasesEdit.Text := IntToStr(NoCases);
MessageDlg(Format('%d random cases added to grid.', [NCases]), mtInformation, [mbOK], 0);
end;
procedure TGenRndValsFrm.FormShow(Sender: TObject);
var
w: Integer;
begin
w := MaxValue([ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
ResetBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w;
CloseBtn.Constraints.MinWidth := w;
ResetBtnClick(self);
end;
procedure TGenRndValsFrm.LowRealEditKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then HiRealEdit.SetFocus;
end;
procedure TGenRndValsFrm.NoCasesEditExit(Sender: TObject);
begin
if RadioGroup1.ItemIndex = 1 then Ncases := StrToInt(NoCasesEdit.Text);
end;
procedure TGenRndValsFrm.DistTypeChange(Sender: TObject);
var
i: Integer;
selTag: Integer;
begin
if (Sender = nil) then
begin
DistType := dtUnknown;
selTag := -1;
end else
begin
DistType := TDistType((Sender as TRadioButton).Tag);
selTag := (Sender as TRadioButton).Tag;
end;
for i := 0 to GroupBox1.ControlCount-1 do
if not (GroupBox1.Controls[i] is TRadioButton) then
GroupBox1.Controls[i].Enabled := GroupBox1.Controls[i].Tag = selTag;
case DistType of
dtFlatInt:
LowIntEdit.SetFocus;
dtFlatReal:
LowRealEdit.SetFocus;
dtNormal:
zMeanEdit.SetFocus;
dtChiSq:
ChiDFEdit.SetFocus;
dtF:
FDF1Edit.SetFocus;
dtUnknown:
;
{
begin
MessageDlg('Please select a distribution type before pressing Compute.', mtError, [mbOK], 0);
exit;
end;
}
else
raise Exception.Create('Unsupported distribution type.');
end;
end;
procedure TGenRndValsFrm.ResetBtnClick(Sender: TObject);
begin
NoCasesEdit.Text := '';
RadioGroup1.ItemIndex := -1;
rbFlatInteger.Checked := false;
rbFlatFloatingPoint.Checked := false;
rbNormalZValues.Checked := false;
rbChiSquaredValues.Checked := false;
rbFDistributionValues.Checked := false;
LabelEdit.Text := '';
LowIntEdit.Text := '';
HiIntEdit.Text := '';
LowRealEdit.Text := '';
HiRealEdit.Text := '';
zMeanEdit.Text := '';
zSDEdit.Text := '';
ChiDFEdit.Text := '';
FDF1Edit.Text := '';
FDF2Edit.Text := '';
DistType := dtUnknown;
DistTypeChange(nil);
end;
procedure TGenRndValsFrm.zMeanEditKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then zSDEdit.SetFocus;
end;
function TGenRndvalsFrm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
var
x: Double;
n: Integer;
begin
Result := false;
if LabelEdit.Text = '' then
begin
AControl := LabelEdit;
AMsg := 'Enter a label for the variable.';
exit;
end;
if RadioGroup1.ItemIndex < 0 then
begin
AControl := RadioGroup1;
AMsg := 'Select an option for the number of values to generate.';
exit;
end;
if (RadioGroup1.ItemIndex = 1) then
begin
if (NoCasesEdit.Text = '') then
begin
AControl := NoCasesEdit;
AMsg := 'Number of cases not specified.';
exit;
end;
if not TryStrToInt(NoCasesEdit.Text, NCases) or (NCases <= 0) then
begin
AControl := NoCasesEdit;
AMsg := 'Valid positive number required.';
exit;
end;
end;
case DistType of
dtUnknown:
begin
AControl := GroupBox1;
AMsg := 'Select a distribution type.';
exit;
end;
dtFlatInt:
begin
if (LowIntEdit.Text = '') or (HiIntEdit.Text = '') then
begin
if LowIntEdit.Text = '' then
AControl := LowIntEdit
else
AControl := HiIntEdit;
AMsg := 'Value required.';
exit;
end;
if not TryStrToInt(LowIntEdit.Text, n) then
begin
AControl := LowIntEdit;
AMsg := 'Valid integer number required.';
exit;
end;
if not TryStrToInt(HiIntEdit.Text, n) then
begin
AControl := HiIntEdit;
AMsg := 'Valid integer number required.';
exit;
end;
end;
dtFlatReal:
begin
if (LowRealEdit.Text = '') or (HiRealEdit.Text = '') then
begin
if LowRealEdit.Text = '' then
AControl := LowRealEdit
else
AControl := HiRealEdit;
AMsg := 'Value required.';
exit;
end;
if not TryStrToFloat(LowRealEdit.Text, x) then
begin
AControl := LowRealEdit;
AMsg := 'Valid number required.';
exit;
end;
if not TryStrToFloat(HiRealEdit.Text, x) then
begin
AControl := HiRealEdit;
AMsg := 'Valid number required.';
exit;
end;
end;
dtNormal:
begin
if (zMeanEdit.Text = '') or (zSDEdit.Text = '') then
begin
if zMeanEdit.Text = '' then
AControl := zMeanEdit
else
AControl := zSDEdit;
AMsg := 'Value required.';
exit;
end;
if not TryStrToFloat(zMeanEdit.Text, x) then
begin
AControl := zMeanEdit;
AMsg := 'Valid number required.';
exit;
end;
if not TryStrToFloat(zSDEdit.Text, x) or (x <= 0) then
begin
AControl := zSDEdit;
AMsg := 'Valid positive number required.';
exit;
end;
end;
dtChiSq:
begin
if (ChiDFEdit.Text = '') then
begin
AControl := ChiDFEdit;
AMsg := 'Value required.';
exit;
end;
if not TryStrToInt(ChiDFEdit.Text, n) or (n <= 0)then
begin
AControl := ChiDFEdit;
AMsg := 'Valid positive number required.';
exit;
end;
end;
dtF:
begin
if (FDF1Edit.Text = '') or (FDF2Edit.Text = '') then
begin
if (FDF1Edit.Text = '') then
AControl := FDF1Edit
else
AControl := FDF2Edit;
AMsg := 'Value required.';
exit;
end;
if not TryStrToInt(FDF1Edit.Text, n) or (n <= 0)then
begin
AControl := FDF1Edit;
AMsg := 'Valid positive number required.';
exit;
end;
if not TryStrToInt(FDF2Edit.Text, n) or (n <= 0)then
begin
AControl := FDF2Edit;
AMsg := 'Valid positive number required.';
exit;
end;
end;
end;
Result := true;
end;
initialization
{$I genrndvalsunit.lrs}
end.