//----------------------------------------------------------------------------//
// module FMain.cpp //
// //
// Main form of the GUI for the PNC cluster/learning algorithm //
// //
// copyright (c) 2003 by Lars Haendel //
// home: www.newty.de //
// //
// This program is free software and can be used under the terms of the //
// GNU licence. See header file for further information and disclaimer. //
// //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------------------
// Notes:
// The output variable may be changed, but the columns in the data object are not exchanged until the user hits the
// buttons 'Edit Types'/'Edit Sets'/'Tune' and the function DoIt() or DoItExt() is called.
//----------------------------------------------------------------------------------------------------------------------
// Naming convention:
//
// Enable show and hide or enable and disable controls
// Ev evaluate functions: set controls depending on some settings/parameters which (may) have changed
// Set set functions: set control's values depending on some initilization or default values
// Act actualize displayed values
//----------------------------------------------------------------------------------------------------------------------
// Most important objects:
// Name Type Description
// ---------------------------------------------------
// data_L TData* learn data file
// data_T TData* test data file
// model TCluster* learned model
// tuneResults TTune* tune results
//
// prj TProjectG project
// learnPara TParameter parameters displayed below on tab sheet 'Learn'; will be used to learn
// stdPara TParameter default parameters
//
// loss TLossFunction* loss function results (temporary)
// pnc TPnc* used to learn model (temporary)
//----------------------------------------------------------------------------------------------------------------------
// help contexts
// 1-4 tab sheets
// 5 load learn data
// 6 variable types dialog
// 7 general setting parameter tuning
// 8 defining parameter sets
// 9 select an optimal paramter set
// 10 parameters
// 11 model characteristics
// 12 using the model
// 13 options
// 14 toolbar
// 20 start tuning
// 21 start learning
//----------------------------------------------------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "FMain.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
//----------------------------------------------------------------------------------------------------------------------
#include <stdio> // due to: sprintf()
#include <dir> // getcwd
#include <filectrl.hpp> // MinimizeName()
#include <htmlhelp> // HTML help
#include "ThrLoadData.h" // ThrLoadData (thread object)
#include "ThrUseModel.h" // ThrUseModel (thread object)
#include "ThrLearnModel.h" // ThrLearnModel (thread object)
#include "ThrTune.h" // ThrTune (thread object)
#include "FAbout.h" // about dialog
#include "FOptions.h" // project options dialog
#include "FGuiOptions.h" // program/gui options dialog
#include "FVarTypes.h" // variable type selection dialog
#include "FEditSets.h" // tune tasks dialog
#include "FOpenProject.h" // LoadProject
#include "fileutil.h" // FlagToString() etc.
//----------------------------------------------------------------------------------------------------------------------
#define PRGNAME "PNC2 Rule Induction System" // program's name and version
#define VERSION "v1.0b"
#define PROJECT_EXTENSION "bap" // extension for project files
#define SIM_FILE_EXTENSION "sim" // extension of simulation output files
#define TUNE_FILE_EXT "opt" // extension for tune results file
#define HELP_FILE "Pnc2Gui.chm" // help file GUI
#define MIN_LEARN_DATA_TUPLES 10 // min. # learn data tuples
//----------------------------------------------------------------------------------------------------------------------
// globals
bool f_DisableWarnings; // flag: disable warning message boxes
bool f_DisableQuestions; // flag: assume YES on silly questions
//----------------------------------------------------------------------------------------------------------------------
// message texts
static const char* szBusyCloseQuery = "I'm busy. Do you want to exit anyway ??";
static const char* szUnsaveExitQuery = "Project not saved! Do you want to exit anyway ??";
static const char* szUnsaveNewQuery = "Project not saved! Do you want to continue ??";
static const char* szLearnDataLoaded = "This will delete the current model and project. Do you want to continue ??";
static const char* szTestDataLoaded = "Test data file already loaded. Do you want to load another file ??";
static const char* szModelLoaded = "This will delete the current model and project. Do you want to continue ??";
static const char* szModuleIsEmpty = "Model is empty! Reduce value of 'Min. rule mass' on tab sheet 'Use Model'.";
//----------------------------------------------------------------------------------------------------------------------
// write defaults to registry; used on first startup of the program and to change default settings in options dialog
// note: existing key are not overwriten if f_Overwrite is set to false
void WriteDefaultsToRegistry(TRegistry* registry, const bool& f_Overwrite=false)
{
registry->RootKey = HKEY_CURRENT_USER; // set root key
registry->OpenKey(SZ_REGISTRY_KEY, true); // open key creating it if it does not
// exist
// project settings
if(!registry->ValueExists(SZ_N_G_MAX) || f_Overwrite) // N_G_Max
registry->WriteInteger(SZ_N_G_MAX, DEF_N_G_MAX);
if(!registry->ValueExists(SZ_N_BINS) || f_Overwrite) // N_Bins
registry->WriteInteger(SZ_N_BINS, DEF_N_BINS);
if(!registry->ValueExists(SZ_OVERLAP_FAC) || f_Overwrite) // overlap factor
registry->WriteFloat(SZ_OVERLAP_FAC, DEF_OVERLAP_FAC);
if(!registry->ValueExists(SZ_EQUAL_WIDTH_BINNING) || f_Overwrite) // flag equal width binning
registry->WriteBool(SZ_EQUAL_WIDTH_BINNING, DEF_EQUAL_WIDTH_BINNING);
if(!registry->ValueExists(SZ_NORMALIZE_BY_RANGE) || f_Overwrite) // flag normalize by range
registry->WriteBool(SZ_NORMALIZE_BY_RANGE, DEF_NORMALIZE_BY_RANGE);
// program/gui settings
if(!registry->ValueExists(SZ_COM_CHAR) || f_Overwrite) // comment character
registry->WriteString(SZ_COM_CHAR, DEF_COM_CHAR);
if(!registry->ValueExists(SZ_DISABLE_WARNINGS) || f_Overwrite) // flag diable warning messages
registry->WriteBool(SZ_DISABLE_WARNINGS, DEF_DISABLE_WARNINGS);
if(!registry->ValueExists(SZ_DISABLE_QUESTIONS) || f_Overwrite) // flag assume YES on silly questions
registry->WriteBool(SZ_DISABLE_QUESTIONS, DEF_DISABLE_QUESTIONS);
registry->CloseKey(); // close registry key
}
TFMain *FMain;
//----------------------------------------------------------------------------------------------------------------------
// constructor
__fastcall TFMain::TFMain(TComponent* Owner) : TForm(Owner)
{
// a) compose complete program name
sprintf(cmplPrgName, "%s %s", PRGNAME, VERSION);
// b) remember executable's directory
char szTmp[256];
getcwd(szTmp, 256); // read
szExeDir = szTmp; // copy to AnsiString
if(!szExeDir.IsPathDelimiter(szExeDir.Length())) // ensure backslash - now program can run from disk root directory
szExeDir += '\\';
// c) initialize pointer
data_L = data_T = NULL;
model = NULL;
tuneResults = NULL;
pnc = NULL;
loss = NULL;
// d) reset flags
f_Loading = f_Testing = f_Tuning = f_Learning = false;
// e) create and initialize program's registry key if they don't exist already
registry = new TRegistry;
WriteDefaultsToRegistry(registry);
// f) read program/gui settings from registry - note: project settings are read in actionList 'EmptyProject'
registry->OpenKey(SZ_REGISTRY_KEY, true); // open key creating it if it does not exist
f_DisableWarnings = registry->ReadBool(SZ_DISABLE_WARNINGS); // read flag
f_DisableQuestions = registry->ReadBool(SZ_DISABLE_QUESTIONS); // read flag
ComChar = registry->ReadString(SZ_COM_CHAR)[1]; // read comment char
registry->CloseKey(); // close key
// initialize HTML help and full help file name
HtmlHelp(0, 0, HH_INITIALIZE, reinterpret_cast <DWORD> (&HtmlHelpCookie));
szHtmlHelpFile = szExeDir + HELP_FILE;
}
//----------------------------------------------------------------------------------------------------------------------
// destructor
__fastcall TFMain::~TFMain()
{
// release learn and test data
if(data_L)
data_L->Release();
if(data_T)
data_T->Release();
delete model;
delete tuneResults;
// note: should not be necessary since objects always get deleted in On...Finished()
delete loss;
delete pnc;
delete registry;
// un-initialize HTML help
HtmlHelp(0, 0, HH_UNINITIALIZE, reinterpret_cast <DWORD> (HtmlHelpCookie));
}
//----------------------------------------------------------------------------------------------------------------------
// initialize controls
void __fastcall TFMain::FormShow(TObject *Sender)
{
// a) initialize everthing for an empty project
ActionList(EmptyProject);
// b) initialize control texts and constraints
TbDataSplitting->Max = MAX_SPLIT; // data splitting slider bar
// note: minimum is calculated based upon # learn data tuples
// c) listview on tab sheet 'Tuning Results'
LvTuneResults->Columns->Clear(); // clear all columns
LvTuneResults->Columns->Add()->Caption = "Id"; // set column header names
LvTuneResults->Columns->Add()->Caption = "Intervals";
LvTuneResults->Columns->Add()->Caption = "Anti COD";
LvTuneResults->Columns->Add()->Caption = "Eta";
LvTuneResults->Columns->Add()->Caption = "Min. rule mass";
if(prj.Regression())
LvTuneResults->Columns->Add()->Caption = "Sigma";
else
LvTuneResults->Columns->Add()->Caption = "Kernel width";
LvTuneResults->Columns->Add()->Caption = "Weights";
LvTuneResults->Columns->Add()->Caption = "Prune";
LvTuneResults->Columns->Add()->Caption = "Euclidean";
LvTuneResults->Columns->Add()->Caption = "Rules";
LvTuneResults->Columns->Add()->Caption = "Rules (reduced)";
LvTuneResults->Columns->Add()->Caption = "Variables";
LvTuneResults->Columns->Add()->Caption = "Hitrate";
LvTuneResults->Columns->Add()->Caption = "Error";
// set column width and enable auto sizing
int w = LvTuneResults->Width/LvTuneResults->Columns->Count; // width of each column
for(int i=0;i<LvTuneResults->Columns->Count;i++)
{
LvTuneResults->Columns->Items[i]->AutoSize = true;
LvTuneResults->Columns->Items[i]->Width = w;
}
}
//----------------------------------------------------------------------------------------------------------------------
// handle otherwise unhandled exceptions
void __fastcall TFMain::ApplicationEventsException(TObject*, Exception* E)
{
// exceptions of type U: Intendend to be shown to the user
if(IsTypeUExcpetion())
Application->MessageBox(GetLastExcpetionU().GetErrorText(), "Error", MB_OK | MB_ICONERROR);
else
// exception of type A and B: Only intended for algorithm development
if(IsTypeABExcpetion())
Application->MessageBox(GetLastExcpetionAB().GetErrorText(), MSG_IPI, MB_OK | MB_ICONERROR);
else
if(E->Message.IsEmpty())
Application->MessageBox("C++ Exception ;-)", "Error", MB_OK | MB_ICONERROR); // unknown exception
else
Application->MessageBox(E->Message.c_str(), "Error", MB_OK | MB_ICONERROR); // display message
}
//----------------------------------------------------------------------------------------------------------------------
// open help: close all previous windows, get actual help context Id and show help. Called by the reponse handler to
// key F1 and help menu/toolbar items
void TFMain::OpenHelp()
{
// close all help windows
HtmlHelp(0, 0, HH_CLOSE_ALL, 0);
// get help topic Id
int ContextId = 0;
if(Screen->ActiveForm!=FMain) // use help topic Id from active form if child window ...
ContextId = Screen->ActiveForm->HelpContext; // ... is displayed modally
else
if(ActiveControl) // else: try to initialize from active main form control
ContextId = ActiveControl->HelpContext;
// open the help file in its default window type using the default opening page
HtmlHelp(NULL, szHtmlHelpFile.c_str(), HH_DISPLAY_TOPIC, 0);
// show context sensitive help topic
HtmlHelp(NULL, szHtmlHelpFile.c_str(), HH_HELP_CONTEXT, ContextId);
}
//----------------------------------------------------------------------------------------------------------------------
// open help in response to button 'F1'
// note: this function may be called while a child window is displayed modally
void __fastcall TFMain::ApplicationEventsShortCut(TWMKey &Msg, bool &Handled)
{
if(Msg.CharCode==VK_F1) // if 'F1' was hit
{
OpenHelp(); // open help file
Handled = true; // ... and eat the event :-)
}
else
Handled = false;
}
//----------------------------------------------------------------------------------------------------------------------
// open program help file in response to menu entry 'Help|Pnc Gui Help'
void __fastcall TFMain::MnHelpGuiClick(TObject *Sender){ OpenHelp(); }
//----------------------------------------------------------------------------------------------------------------------
// show about dialog
void __fastcall TFMain::AboutClick(TObject*)
{
TFAbout* about = new TFAbout(this, cmplPrgName, szExeDir); // create dialog note: dialog deletes itself when closed
about->ShowModal(); // show dialog (modal)
}
//----------------------------------------------------------------------------------------------------------------------
// show project options dialog
void __fastcall TFMain::MnProjectOptionsClick(TObject *Sender)
{
FOptions->SetProject(&prj); // pass project to dialog
FOptions->ShowModal(); // show modal
if(FOptions->SomethingChanged()) // unset saved flag if somth. has changed
SetSavedFlag(false);
}
//----------------------------------------------------------------------------------------------------------------------
// show program/gui options dialog
void __fastcall TFMain::MnGuiOptionsClick(TObject *Sender)
{
FGuiOptions->ShowModal();
}
//----------------------------------------------------------------------------------------------------------------------
// menu item 'File|New' clicked: Clear everything. Warn user if an unsaved project exists.
void __fastcall TFMain::MnNewClick(TObject *Sender)
{
// if unsaved model or tune results exist
if(!f_Saved && (model || tuneResults) && !f_DisableWarnings)
if(Application->MessageBox(szUnsaveNewQuery, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
return;
// else: clear all
ActionList(EmptyProject);
}
//----------------------------------------------------------------------------------------------------------------------
// Menu item 'File|Load Project' clicked: Load project
void __fastcall TFMain::MnOpenProjectClick(TObject *Sender)
{
// a) if unsaved model or tune results exist
if(!f_Saved && (data_L || model || tuneResults) && !f_DisableWarnings)
if(Application->MessageBox(szUnsaveNewQuery, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
return;
ActionList(EmptyProject); // clear all
// b) ask user for filename
OpenDialog->Title = "Open project ...";
OpenDialog->Options << ofFileMustExist << ofPathMustExist;
OpenDialog->DefaultExt = PROJECT_EXTENSION;
OpenDialog->Filter = AnsiString("project file (*.") + AnsiString(PROJECT_EXTENSION) + AnsiString(")|*.") +
AnsiString(PROJECT_EXTENSION);
OpenDialog->FileName = szProjectFile;
if(!OpenDialog->Execute())
return; // return if closed with 'Cancel' button
szProjectFile = OpenDialog->FileName; // store project filename
// c) open/load project file
ifstream file(szProjectFile.c_str()); // open file
try
{
prj.Load(file, /*dir*/ ExtractFileDir(szProjectFile).c_str()); // load project
if(prj.Model())
szModelFile = ChangeFileExt(szProjectFile, AnsiString(".") + TPnc::Extension());
if(prj.TuningResults())
szTuningFile = ChangeFileExt(szProjectFile, AnsiString(".") + TUNE_FILE_EXT);
int line=0; // dummy, not used
f_LearnParaInitialized = learnPara.Load(file, line);
}
catch(TExceptionU excp) // exception handling
{
ActionList(EmptyProject); // in case of an error ... note: if an error occured all 3 objects point to NULL
// display error message ...
Application->MessageBox(excp.GetErrorText(), "Error loading project file", MB_OK | MB_ICONERROR);
return;
}
file.close(); // close file
// d) load model, tune results and data
FOpenProject->Associate(&prj, szModelFile.c_str(), szTuningFile.c_str());
FOpenProject->ShowModal();
FOpenProject->WriteBack(model, data_L, data_T, tuneResults); // write back loaded objects
// e) initialize GUI according to loaded objects (model, tune results, learn and test data)
// e1) learn data
if(data_L)
{
stdPara.SetStandardValues(data_L); // initialize standard parameters
if(f_LearnParaInitialized)
SetParameters(learnPara); // if there are some: set parameters from project file
ActionList(ProjectToGUI); // write project settings to GUI
Caption = AnsiString(cmplPrgName) + " " + szProjectFile; // display project filename in window caption
// e2) test data
if(data_T)
{
prj.SetData2(data_T); // set data filename in project
f_IsWithOutput = FOpenProject->IsWithOutput();
}
// e3) model
if(model)
ActionList(ModelLoaded);
// e4) tune results
if(tuneResults)
ActionList(TuneResultsLoaded);
SetSavedFlag(true); // just opened ;-)
}
else
ActionList(EmptyProject); // in case of an error ... note: if an error occured all 4 objects point to NULL
}
//----------------------------------------------------------------------------------------------------------------------
// save project, ask user for filename before if necessary
void __fastcall TFMain::MnSaveProjectClick(TObject*)
{
if(szProjectFile.IsEmpty())
MnSaveProjectAsClick(this);
else
SaveProject(szProjectFile);
}
//----------------------------------------------------------------------------------------------------------------------
// ask user for filename to save project
void __fastcall TFMain::MnSaveProjectAsClick(TObject*)
{
// ask user for filename
SaveDialog->Title = "Save project as ...";
SaveDialog->Options << ofPathMustExist << ofOverwritePrompt << ofNoReadOnlyReturn;
SaveDialog->Filter = AnsiString("project file (*.") + AnsiString(PROJECT_EXTENSION) + AnsiString(")|*.")
+ AnsiString(PROJECT_EXTENSION);
SaveDialog->DefaultExt = PROJECT_EXTENSION; // set default extension
SaveDialog->FileName = szProjectFile;
if(!SaveDialog->Execute())
return; // return if closed with 'Cancel' button
SaveProject(SaveDialog->FileName); // save
}
//----------------------------------------------------------------------------------------------------------------------
// save project, model and tune results (if existing) to file
void TFMain::SaveProject(AnsiString szFileName)
{
// a) store filename and set simulation output file note: done here to allow a relative path
szProjectFile = szFileName;
prj.SetSimulationOutputFileName(ExtractRelativePath(ExtractFilePath(szProjectFile), szSimOutputFile).c_str());
// b) save model if it exists
if(model)
{
// compose model filename taking project filename exchanging its extension
szModelFile = ChangeFileExt(szProjectFile, AnsiString(".") + TPnc::Extension());
// error if the two files are the same, i.e. the user has specified the model extension as project extension
if(szModelFile == szProjectFile)
{
char szText[256];
sprintf(szText, "Do NOT use the extension '%s' for project files! Please retry!", TPnc::Extension());
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
// try to open and save
ofstream file(szModelFile.c_str(), ios::out); // open
if(!file) // check for errors
{
char szText[256]; // compose error text
sprintf(szText, "Unable to open file '%s'!", szModelFile.c_str());
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
model->Save(file); // save model data
prj.Model() = true; // set model flag note: model cannot be empty, thus there is no check
}
// c) save tune results if they exist
if(tuneResults)
{
// compose result filename
szTuningFile = ChangeFileExt(szProjectFile, AnsiString(".") + TUNE_FILE_EXT);
// error if the two files are the same, i.e. the user has specified the tune file extension as project extension
if(szTuningFile == szProjectFile)
{
char szText[256];
sprintf(szText, "Do NOT use the extension '%s' for project files! Please retry!", TUNE_FILE_EXT);
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
// try to open and save
ofstream file(szTuningFile.c_str(), ios::out); // open
if(!file) // check for errors
{
char szText[256]; // compose error text
sprintf(szText, "Unable to open file '%s'!", szTuningFile.c_str());
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
tuneResults->Save(file); // save tune results
prj.TuningResults() = true; // set flag in project, that indicates that a tune results file exists
}
// d) save project: try to open file, check and save
ofstream file(szProjectFile.c_str(), ios::out); // open
if(!file) // check
{
char szText[256]; // compose error text
sprintf(szText, "Unable to open file '%s'!", szProjectFile.c_str());
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
prj.Save(file); // save project
if(f_LearnParaInitialized) // and parameters from group box 'Parameters' in tab sheet "Learn'
{
file << endl << endl; // line feeds
learnPara.Save(file); // parameters
}
// e) misc.
SetSavedFlag(true); // set flag: everything is saved now
ActModelStatus(); // display model filename
ActTuningResultsStatus(); // display tune results filename
Caption = AnsiString(cmplPrgName) + " " + szProjectFile; // diaplay project filename in window caption
}
//----------------------------------------------------------------------------------------------------------------------
// Menu 'File|Load Model' clicked: Load model from file
void __fastcall TFMain::MnLoadModelClick(TObject *Sender)
{
// ToDo: check parameter Prune against f_HasPruningInfo and f_HasOriginalCuboids
// a) if data or model is already loaded/learned
if((data_L || model))
{
if(!f_DisableWarnings) // ask user if he wants to continue as project/model will be lost
if(Application->MessageBox(szModelLoaded, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
return; // abort
ActionList(EmptyProject); // else: clear all
}
// b) set dialog caption/options and execute it
OpenDialog->Title = "Import model file ...";
OpenDialog->Options << ofFileMustExist << ofPathMustExist;
OpenDialog->Options >> ofOldStyleDialog;
OpenDialog->DefaultExt = TPnc::Extension();
OpenDialog->Filter = "PNC model files (*." + AnsiString(TPnc::Extension()) + ")|*." + AnsiString(TPnc::Extension());
OpenDialog->FileName = szModelFile;
if(!OpenDialog->Execute())
return; // return if closed with 'Cancel' button
// c) create parameter and model objects and load selected file
ifstream file(OpenDialog->FileName.c_str()); // open file
IfTrueThrowTypeU(!file, "Unable to open model file!"); // and check success
szModelFile = OpenDialog->FileName; // and additionally store in GUI variable
model = new TCluster(); // instantiate model
try
{
int line = 1;
model->Load(file, line); // load model (cuboids)
}
catch(TExceptionU excp) // exception handling
{
Application->MessageBox(excp.GetErrorText(), "Error", MB_OK | MB_ICONERROR); // display error message ...
ActionList(DeleteModel);
}
file.close(); // close file
// d) if parameters and model are loaded correctly -> ... show them
if(model)
ActionList(ModelLoaded);
}
//----------------------------------------------------------------------------------------------------------------------
// Menu item 'File|Export Model' clicked:
void __fastcall TFMain::MnSaveModelClick(TObject *Sender)
{
// a) ask user for filename
SaveDialog->Title = "Export model file ...";
SaveDialog->Options << ofPathMustExist << ofOverwritePrompt << ofNoReadOnlyReturn;
SaveDialog->Filter = AnsiString("project file (*.") + AnsiString(TPnc::Extension()) + AnsiString(")|*.")
+ AnsiString(TPnc::Extension());
SaveDialog->DefaultExt = TPnc::Extension(); // set default extension
if(!szModelFile.IsEmpty()) // inititalize from model filename if string is not empty
SaveDialog->FileName = szModelFile;
else
if(!szProjectFile.IsEmpty()) // else: initalize from project filename if it's not empty
SaveDialog->FileName = ChangeFileExt(szProjectFile, AnsiString(".") + TPnc::Extension());
else
SaveDialog->FileName = ""; // else: clear filename
if(!SaveDialog->Execute())
return; // return if closed with 'Cancel' button
szModelFile = SaveDialog->FileName; // store filename
// b) export model
ofstream file(szModelFile.c_str(), ios::out); // open
if(!file) // check for errors
{
char szText[256]; // compose error text
sprintf(szText, "Unable to open file '%s'!", szModelFile.c_str());
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
return;
}
UpdatePara(); // initialize (learn and) test parameters
model->Save(file, /*compact saving*/true, /*alternate parameters*/¶); // save model data
if(model->nCuboidsRed()==0 && !f_DisableWarnings) // display warning if module is empty
Application->MessageBox(szModuleIsEmpty, "Warning", MB_OK | MB_ICONWARNING);
ActModelStatus(); // display model filename
}
//----------------------------------------------------------------------------------------------------------------------
// Menu item 'File|Exit' clicked: Ask user if the program is busy and terminate
void __fastcall TFMain::MnExitClick(TObject*)
{
bool f_CanClose = true;
FormCloseQuery(this, f_CanClose);
if(f_CanClose)
Application->Terminate();
}
//----------------------------------------------------------------------------------------------------------------------
// Gets called if application wants to terminate: Ask the user if program is busy
void __fastcall TFMain::FormCloseQuery(TObject*, bool &CanClose)
{
CanClose=true;
// ask user if he really wants to exit if program is busy ...
if((f_Loading || f_Testing || f_Tuning || f_Learning) && !f_DisableWarnings)
{
if(Application->MessageBox(szBusyCloseQuery, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
CanClose=false;
}
else
// ... or if unsaved model or tune results exist
if((!f_Saved && (model || tuneResults)) && !f_DisableWarnings)
if(Application->MessageBox(szUnsaveExitQuery, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
CanClose=false;
}
//----------------------------------------------------------------------------------------------------------------------
// Gets called if user tries to change the tab sheet: Check if selected tab sheet is allowed to be displayed
void __fastcall TFMain::PageControlChanging(TObject *Sender, bool &AllowChange)
{
// disallow without user notice if program is busy
AllowChange = true;
if(f_Loading || f_Testing || f_Tuning || f_Learning)
AllowChange = false;
}
//----------------------------------------------------------------------------------------------------------------------
// enable/disable menu and toolbar entries
void TFMain::EnableMenus(const bool& f_Enable)
{
// menu 'File'
MnNew ->Enabled = f_Enable;
MnOpenProject ->Enabled = f_Enable;
MnLoadModel ->Enabled = f_Enable;
MnSaveProject ->Enabled = !f_Saved && f_Enable && data_L; // enable only if learn data is present and project unsaved
MnSaveProjectAs->Enabled = f_Enable && data_L; // enable only if learn data is present
MnSaveModel ->Enabled = f_Enable && model; // enable only if model is present
TbNew ->Enabled = f_Enable;
TbOpenProject ->Enabled = f_Enable;
TbLoadModel ->Enabled = f_Enable;
TbSaveProject ->Enabled = !f_Saved && f_Enable && data_L; // enable only if learn data is present and project unsaved
TbSaveModel ->Enabled = f_Enable && model; // enable only if model is present
// menu 'Options'
MnOptions->Enabled = f_Enable;
}
//----------------------------------------------------------------------------------------------------------------------
// commands for some common actions
// - ClearResults: clear displayed results and hide pie chart
// - ProjectToGUI: write project settings to GUI
// - EmptyProject: reset project and GUI
// - ClearTestData: delete test data
// - LearnDataLoaded: learn data loaded, enable controls
// - ModelLoaded: 'show' and initialize (prepare) model
// - TuneResultsLoaded transfer loaded tune results to list view on tab sheet 'Tuning Results'
// - DeleteModel delete model
void TFMain::ActionList(const TActionList& action)
{
switch(action)
{
//----------------------------------------------------------------------------------------------------------------
// clear displayed loss results and hide pie chart
case ClearResults :
MceChart->Visible = false; // hide pie chart
LaOverallLoss1->Caption = "??"; // clear displayed results
LaInsideLoss1 ->Caption = "??";
LaOutsideLoss1->Caption = "??";
LaOverallLoss2->Caption = "??";
LaInsideLoss2 ->Caption = "??";
LaOutsideLoss2->Caption = "??";
LaInsideRatio ->Caption = "??";
LaTestCuboids->Caption = "??";
LaInsideRatio->Caption = "??";
break;
//----------------------------------------------------------------------------------------------------------------
// write project settings to GUI
case ProjectToGUI :
// group box 'Parameter tuning'
EMaxSize ->Text = AnsiString(prj.GetMaxSize()) + " %"; // maximum model size
EMinCmpr ->Text = AnsiString(prj.GetMinCompression()) + " %"; // minimum compression rate
CbSkipTuning->Checked = !prj.DoTuning(); //
CbRandomize ->Checked = prj.Randomize(); // flags
CbSkipping->Checked = prj.Skipping();
EnableLearnDataCtrls(data_L); // enable/disable controls
ActLearnDataStatus(data_L); // display filename or hint how to load
MnSaveProject ->Enabled = (data_L!=NULL); // enable/disable menu entry and tool bar button 'Save Project'
MnSaveProjectAs->Enabled = (data_L!=NULL);
TbSaveProject ->Enabled = (data_L!=NULL);
// note: changing of radio buttons generates an 'OnClick' events and the corresponding event handler may try
// to write updated settings to the project object which would raise an exception because no data is
// associated. Thus do not proceed!
if(!data_L)
break;
// group box 'Learn Data'
EOutCol->Text = prj.GetOutCol()+1; // output column
EvOutputType(); // classification flag
// initialize group box 'Tune parameters'
ERepetition ->Text = prj.Get_N_R_Tune(); // # repetitions/cross-validations
if(prj.GetTuneType()==Rep) // tune type
RbRepetition->Checked = true;
else
if(prj.GetTuneType()==Cv)
RbCrossValidation->Checked = true;
else
RbLoocv->Checked = true;
EvTuneType(); // show or hide controls according
SetNParameterSets(); // display # parameter sets defined for tuning
// tab sheet 'Use Model'
CbWritePredictions->Checked = prj.WritePredictions();
CbModify1->Checked = prj.Modify1();
CbModify2->Checked = prj.Modify2();
szSimOutputFile = prj.GetSimulationOutputFileName(); // initialize simulation output filename from project
break;
//----------------------------------------------------------------------------------------------------------------
// clear all and restore the state as it was when started note: calls action lists DeleteModel,
// DeleteTuningResults and ProjectToGUI
case EmptyProject :
PageControl->ActivePage = TsBasic; // change to tab sheet 'Basic'
ActiveControl = BtLearnData; // set focus note: important to prevent errors
f_LearnParaInitialized = false;
szSimOutputFile = szProjectFile = ""; // clear filenames
szModelFile = szTuningFile = "";
Caption = AnsiString(cmplPrgName); // 'remove' project filename from main window caption
if(data_L) data_L->Release(); // release learn and test data
data_L = NULL;
prj.Reset(); // reset project ...
// ... and initialize N_G_Max, N_Bins, overlap factor flag from registry
registry->OpenKey(SZ_REGISTRY_KEY, true); // open key creating it if it does not exist
prj.Set_N_G_Max (registry->ReadInteger(SZ_N_G_MAX)); // read N_G_Max
prj.Set_N_Bins (registry->ReadInteger(SZ_N_BINS)); // read N_Bins
prj.SetOverlapFac(registry->ReadFloat(SZ_OVERLAP_FAC)); // read overlap factor
prj.NormalizeByRange() = registry->ReadBool(SZ_NORMALIZE_BY_RANGE); // read normalize by range flag
prj.EqualWidthBinning()= registry->ReadBool(SZ_EQUAL_WIDTH_BINNING); // read equal width binning flag
registry->CloseKey(); // close key
ActionList(DeleteModel); // hide tab sheets and release model
delete pnc; // note: obsolete, should not be necessary
pnc = NULL;
ActionList(DeleteTuningResults); // hide tab sheet and delete tune results
SetSavedFlag(false);
// tab sheet 'Basics'
LaLearnDataStatus->Caption = "";
// group box 'Parameters'
EIntervals ->Text = ""; // 'clear' parameters
EWmin ->Text = "";
EEta ->Text = "";
ECardinality->Text = "";
ESpecial ->Text = "";
ESigma ->Text = "";
// note: do not(!) reset the check boxes as this would cause an OnClick event
// which would write through to the project. Either i or the developper of
// TCheckbox is an idiot :-|
// tab sheet 'Use Model'
CbWritePredictions->Checked = DEF_WRITE_PREDICTIONS;
LaTestTime->Caption = ""; // clear "elapsed time" string
ActionList(ClearTestData);
CbModify1->Checked = false; // uncheck modify check boxes
CbModify2->Checked = false;
// actualize GUI
ActionList(ProjectToGUI);
break;
//----------------------------------------------------------------------------------------------------------------
// clear test data note: calls ClearResults at the end
case ClearTestData :
if(data_T)
data_T->Release(); // release test data
data_T = NULL;
prj.ClearData2(); // clear test data association in project
EnableTestDataCtrls(false); // disable/hide controls
ActTestDataStatus(); // and actualize displayed status
// group box 'Simulation'
ActTestStatus();
LaTestStatus->Caption = "No results";
LaTestTime ->Caption = "0m00s";
// clear loss results
ActionList(ClearResults);;
break;
//----------------------------------------------------------------------------------------------------------------
// learn data has been loaded, enable controls
case LearnDataLoaded :
prj.Initialize(data_L); // initialize project using learn data
ActionList(ProjectToGUI);
ActiveControl = EOutCol; // set focus to output column control
// hints
LaOutCol->Hint= "Which column of the data file contains the output values?\nEnter a value between 1 and "
+ AnsiString(data_L->nVar()) + ".";
EOutCol->Hint = LaOutCol->Hint;
// min. slider data splitting
TbDataSplitting->Min = max((int) ceil(500/data_L->nTup()), MIN_SPLIT); // ensure at least 5 learn data tuples
break;
//----------------------------------------------------------------------------------------------------------------
// model has been loaded
case ModelLoaded :
model->Prepare(); // set cardinality
ActModelParameters(); // initialize displayed parameters and values
ActModelStatus(); // display model filename
para = *(model->GetParameters()); // initialize from model parameters
LaModelTime->Caption = "NA"; // clear time
PageControl->ActivePage = TsModel; // ... change to tab sheet 'Model'
MnSaveModel->Enabled = true; // enable menu entry 'Export Model' and toolbar button
TbSaveModel->Enabled = true; //
break;
//----------------------------------------------------------------------------------------------------------------
// transfer loaded tuning results to list view on tab sheet 'Tuning Results'
case TuneResultsLoaded :
AddTuningResults(); // add tune results to list view
TsTuneResults->TabVisible = true; // show tab sheet 'Tune Results'
LaSelectText->Visible = true; // show hint text how to select parameter set
LaTuneTime->Caption = "NA"; // clear time
ActTuningResultsStatus(); // display file name
break;
//----------------------------------------------------------------------------------------------------------------
// delete model
case DeleteModel :
delete model; // delete model
model = NULL;
szModelFile = "";
GbModel->Visible = false; // hide group box 'Model' in tab sheet 'Model'
MnSaveModel->Enabled = false; // disable 'Export Model' menu and toolbar button
TbSaveModel->Enabled = false;
TsModel->TabVisible = false; // hide tab sheets 'Model' and 'Use Model'
TsUseModel->TabVisible = false;
CbModify1->Checked = false; // uncheck checkboxes on tab sheet 'Use Model' to re-initialize them later
CbModify2->Checked = false; // if a new model is learned
break;
//----------------------------------------------------------------------------------------------------------------
// delete tune results
case DeleteTuningResults :
TsTuneResults->TabVisible = false; // hide tab sheet 'Tune Results'
LvTuneResults->Items->Clear(); // delete all results in list view
LaSelectText->Visible = false; // hide hint
BtSelect->Enabled = false; // disable button 'Select'
delete tuneResults; // delete
tuneResults = NULL;
break;
//----------------------------------------------------------------------------------------------------------------
// delete tune tasks
case DeleteTuningTasks :
prj.DeleteAllTasks(); // tune tasks
BtTune->Enabled = false; // disable button
SetNParameterSets(); // display # parameter sets
break;
}
}
//-----------------------------------------------------------------------------------------------
//
// Tab Sheet 'Basic'
//
//----------------------------------------------------------------------------------------------------------------------
//
void __fastcall TFMain::TsBasicShow(TObject *Sender)
{
SetTsLearnFocus(); // set focus to appropriate control
}
//----------------------------------------------------------------------------------------------------------------------
// set focus to appropriate control
void TFMain::SetTsLearnFocus()
{
if(!data_L)
ActiveControl = BtLearnData;
else
if(CbSkipTuning->Checked)
ActiveControl = BtLearn; // focus button 'Learn'
else
if(prj.nParaSets()>0) // if parameter sets are defined ...
ActiveControl = BtTune; // ... focus button 'Tune'
else
ActiveControl = BtEditSets; // ... else focus button 'Edit Sets'
}
//----------------------------------------------------------------------------------------------------------------------
// write through output column and set data and project in TVarTypes object
void TFMain::DoIt()
{
prj.WriteThroughOutCol(f_IsWithOutput);
FVarTypes->Associate(data_L, &prj, this);
FEditSets->Associate(data_L, &prj, &stdPara);
}
//----------------------------------------------------------------------------------------------------------------------
//
void SetLabelFontStyleAndColor(TLabel* label, const bool& f_Bold, const TColor& color)
{
TFontStyles style = label->Font->Style; // get control's font style
if(f_Bold)
style << fsBold; // set bold style
else
style >> fsBold; // unset bold style
label->Font->Color = color; // and set it to red
label->Font->Style = style; // set style
}
//----------------------------------------------------------------------------------------------------------------------
// call DoIt() and calculate feature weights and initialize standard parameter object
// ToDo: find a better solution! Maybe use a thread to calculate feature weights
void TFMain::DoItExt()
{
DoIt(); // write through output column
// set label text and bold style and color to red
SetLabelFontStyleAndColor(LaLearnDataStatus, true, clRed);
LaLearnDataStatus->Caption = "Calculating feature weigths";
LaLearnDataStatus->Repaint();
EnableMenus(false); // disable menu entries
ToolBar->Repaint();
// calculate feature weights and update standard parameters if weights have been (re-)calculated
if(data_L->CalculateWeights(prj.Get_N_Bins(), !prj.Regression(), prj.EqualWidthBinning()))
stdPara.SetStandardValues(data_L);
// unset label bold style and set color back to black
SetLabelFontStyleAndColor(LaLearnDataStatus, false, clBlack);
ActLearnDataStatus();
EnableMenus(true); // enable menu entries again
}
//----------------------------------------------------------------------------------------------------------------------
// Called while learn data is loaded: Actualize progress bar and status text
void __fastcall TFMain::OnLoadLearnDataTimer(TObject*)
{
LaLearnDataStatus->Caption = AnsiString(data_L->StatusText());
PbLearnData->Position = data_L->LoadDataProgress();
}
//----------------------------------------------------------------------------------------------------------------------
// hide and show, enable and disable controls in tab sheet 'Basic'
void TFMain::EnableLearnDataCtrls(const bool& f_Enable)
{
// a) group box 'Learn Data'
LaOutCol ->Visible = f_Enable;
EOutCol ->Visible = f_Enable;
BtOutColUp ->Visible = f_Enable;
BtOutColDown ->Visible = f_Enable;
BtEditTypes ->Visible = f_Enable;
CbClassification->Visible = f_Enable;
BtLearnDataPause->Visible = !f_Enable; // 'Pause' button
BtLearnDataAbort->Visible = !f_Enable; // 'Abort' button
// b) group box 'Tune parameters'
CbSkipTuning->Enabled = f_Enable; // check box 'Skip tuning'
// c) enable/disable controls in other group boxes
// note: only one of them, depending on the 'Skip tuning' check box, can be enabled
EnableTuneCtrls(!CbSkipTuning->Checked && f_Enable); // group box 'Tune parameters'
EnableParameterCtrls(CbSkipTuning->Checked && f_Enable); // group box 'Parameters'
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status on tab sheet 'Use Model' note: useful for display of filenames with MinimizeName()
void __fastcall TFMain::TsBasicResize(TObject *Sender)
{
// call to update displayed filename (because maybe it has been or now has to be minimized)
ActLearnDataStatus(true);
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status labels at the top of tab sheet 'Basic': display filename of loaded data or hint how to load data
void TFMain::ActLearnDataStatus(const bool& f_ActFilename)
{
// display learn data filename (normal) or hint (bold) how to load it
if(data_L)
{
LaLearnFileHeader->Caption = "File";
// set filename note: file name was set after it was specified in OnLoad...
if(f_ActFilename)
LaLearnFile->Caption=MinimizeName(data_L->LoadFileName(), LaLearnFile->Canvas, LaLearnFile->Width);
LaLearnDataStatusHeader->Visible = true;
LaLearnDataStatus ->Visible = true;
if(!f_Loading)
{
// display # variables and tuples
char text[256];
sprintf(text, "%d variables and %d tuples", data_L->nVar(), data_L->nTup());
LaLearnDataStatus->Caption = text;
}
// note: "Loading" is displayed via OnTimer event handler
}
else
{
LaLearnFileHeader->Caption = "Hit button to load learn data file!";
LaLearnFile ->Caption = "";
LaLearnDataStatusHeader->Visible = false;
LaLearnDataStatus ->Visible = false;
}
}
//----------------------------------------------------------------------------------------------------------------------
// enable/disable controls in group box 'Tune parameters'
void TFMain::EnableTuneCtrls(const bool& f_Enable)
{
RbRepetition ->Enabled = f_Enable;
RbCrossValidation->Enabled = f_Enable;
RbLoocv ->Enabled = f_Enable;
LaRepetition ->Enabled = f_Enable;
LaSplitting ->Enabled = f_Enable;
LaRuns ->Visible = f_Enable;
TbDataSplitting ->Enabled = f_Enable;
CbRandomize ->Enabled = f_Enable;
CbSkipping ->Enabled = f_Enable;
ERepetition ->Enabled = f_Enable;
BtRepetitionUp ->Enabled = f_Enable;
BtRepetitionDown ->Enabled = f_Enable;
LaMaxSize ->Enabled = f_Enable && CbSkipping->Checked; // do not enable if skipping is unchecked
LaMinCmpr ->Enabled = f_Enable && CbSkipping->Checked;
EMaxSize ->Enabled = f_Enable && CbSkipping->Checked;
EMinCmpr ->Enabled = f_Enable && CbSkipping->Checked;
BtMaxSizeUp ->Enabled = f_Enable && CbSkipping->Checked;
BtMaxSizeDown ->Enabled = f_Enable && CbSkipping->Checked;
BtMinCmprUp ->Enabled = f_Enable && CbSkipping->Checked;
BtMinCmprDown ->Enabled = f_Enable && CbSkipping->Checked;
BtEditSets ->Enabled = f_Enable;
// enable button 'Tune' only if parameter sets are defined
BtTune->Enabled = (prj.nParaSets()>0 && f_Enable);
}
//----------------------------------------------------------------------------------------------------------------------
// enable/disable controls in group box 'Parameters'
void TFMain::EnableParameterCtrls(const bool& f_Enable)
{
// a) classification or regression parameters
// disallow enabling of parameter 'Intervals' if classification check box is set
if(!CbClassification->Checked || !f_Enable)
{
LaIntervals ->Enabled = f_Enable;
EIntervals ->Enabled = f_Enable;
LaSigma ->Enabled = f_Enable;
ESigma ->Enabled = f_Enable;
}
// disallow enabling of 'classification only' parameters (W_Kernel ...) if it's not a classification task
if(CbClassification->Checked || !f_Enable)
{
LaSpecial ->Enabled = f_Enable;
ESpecial ->Enabled = f_Enable;
}
// b) other parameters
GbParameters ->Enabled = f_Enable;
LaWmin ->Enabled = f_Enable;
LaEta ->Enabled = f_Enable;
LaCardinality->Enabled = f_Enable;
CbWeights ->Enabled = f_Enable;
CbPrune ->Enabled = f_Enable;
CbEuclidean ->Enabled = f_Enable;
EWmin ->Enabled = f_Enable;
EEta ->Enabled = f_Enable;
ECardinality ->Enabled = f_Enable;
// c) misc.
CbPruneAnyWay->Enabled = !CbPrune->Checked && f_Enable; // enable check box 'Prune anyway' if prune
// is unchecked
CbKillCuboids->Enabled = f_Enable; // check box 'Kill small cuboids'
BtDefault ->Enabled = f_Enable; // button 'Defaults'
BtLearn ->Enabled = f_Enable; // button 'Learn'
}
//----------------------------------------------------------------------------------------------------------------------
// change output column
void TFMain::ChangeOutCol(int outcol)
{
if(!data_L) // return if learn data is not loaded note: may happen if 'File|New' is hit when focus is on EOutCol
return;
// a) check contraints and return if outcol has not changed
if(outcol<0) outcol = 0; // minimum
if(outcol>=data_L->nVar()) outcol = data_L->nVar()-1; // maximum
if(prj.GetOutCol()==outcol) // return if output column has not changed
{
EOutCol->Text = prj.GetOutCol()+1; // re-write/correct text
return;
}
SetSavedFlag(false);
// b) ask user if something (defined tasks for tuning, tune results or learned model) gets lost if
// requested change is done
// if classification is enabled: does this need to be changed to regression as new output column is continous ?
bool f_Change = (!prj.Regression() && !prj.CouldBeClassification(outcol));
// ask
if((prj.nParaSets()>0 && f_Change) || tuneResults || model)
{
ActiveControl = EOutCol; // give focus back
EOutCol->SelectAll(); // and select/highlight text
char szText[STS];
if(f_Change)
strcpy(szText, "You'll loose all parameters sets, tune results and learned model!\nDo you\
really want to change the output column ??");
else
strcpy(szText, "You'll loose the tune results and learned model!\nDo you\
really want to change the output column ??");
if(Application->MessageBox(szText, "Question", MB_YESNO | MB_ICONQUESTION)== ID_NO)
{
EOutCol->Text = prj.GetOutCol()+1; // write back actual value to edit field
return; // return if user selects 'No'
}
} // else continue, i.e. make change
// c) delete model, tune tasks and results
ActionList(DeleteModel); // model
ActionList(DeleteTuningResults); // tune results
if(f_Change) // if changed from classification to regression by force
ActionList(DeleteTuningTasks);
// d) now change the output column
prj.SetOutCol(outcol); // set new output column
EOutCol->Text = prj.GetOutCol()+1; // re-write/correct text
if(!f_Change)
if(!prj.Regression())
prj.CorrectTasksIntervals();
// e) update GUI
EvOutputType(); // display parameters and classification check box
}
//----------------------------------------------------------------------------------------------------------------------
// function gets called from class TVarTypes: Tuning results or learned model would be lost if (input) variable
// types are changed. Thus ask user before.
bool TFMain::AllowChangeOfInputType()
{
// a) ask user if tune results or model are present
if(tuneResults || model)
if(Application->MessageBox("You'll loose all tuning results and the learned model!\nDo you really want to\
change the variable type ??", "Question", MB_YESNO | MB_ICONQUESTION)== ID_NO)
return false; // disallow change if user selects 'No'
// else
// b) delete model and tune results
ActionList(DeleteModel); // model
ActionList(DeleteTuningResults); // tune results
SetSavedFlag(false);
return true; // allow change
}
//----------------------------------------------------------------------------------------------------------------------
// adjust displayed parameters and classification check box depending on regression flag (TProjectG::f_Regression)
void TFMain::EvOutputType()
{
// a) set and enable classification check box if output is/could be symbolic, else unset and disable it
CbClassification->Checked = !prj.Regression(); // set/unset and ...
CbClassification->Enabled = prj.CouldBeClassification(prj.GetOutCol()); // ... enable/disable check box
// b) group box 'Parameters'
// enable/disable parameter 'Intervals', 'Kernel Width', 'min. Kernel Width' and 'Sigma'
if(!prj.Regression()) // classifciation problem
{
LaIntervals->Enabled = false; // disable parameter 'Intervals'
EIntervals ->Enabled = false;
LaSigma ->Enabled = false; // disable parameter 'Sigma'
ESigma ->Enabled = false;
LaSpecial ->Enabled = GbParameters->Enabled; // enable parameter 'Kernel Width'
ESpecial ->Enabled = GbParameters->Enabled;
// enforce # classes to be display for parameter 'Intervals' if parameter values are displayed at all
if(f_LearnParaInitialized)
EIntervals->Text = ValueToText1(prj.nClasses());
}
else // regression problem
{
LaIntervals->Enabled = GbParameters->Enabled; // parameter 'Intervals': set to the same state as
EIntervals ->Enabled = GbParameters->Enabled; // the group box itself
LaSigma ->Enabled = GbParameters->Enabled; // parameter 'Sigma': do.
ESigma ->Enabled = GbParameters->Enabled;
LaSpecial ->Enabled = false; // disbale parameter 'Kernel Width'
ESpecial ->Enabled = false;
// set value for parameter 'Intervals' if parameter values are displayed at all
if(f_LearnParaInitialized)
EIntervals->Text = ValueToText1(learnPara.N_Int);
}
}
//----------------------------------------------------------------------------------------------------------------------
// evaluate selected tune type: set tune type in TProjectG evaluating tune type radio group and
// show or hide controls for # repetitions/cross-validations and data splitting
void TFMain::EvTuneType()
{
// a) evaluate tune type radio group and set type in project
if(RbCrossValidation->Checked)
{
prj.SetTuneType(Cv); // set to cross-validation
prj.Set_N_R_Tune(DEF_N_R_TUNE); // set new default value
}
else
if(RbRepetition->Checked)
{
prj.SetTuneType(Rep); // set to repetition
prj.Def_N_R_Tune(); // set new default value
}
else
prj.SetTuneType(Loocv); // set to loocv
// b) show and hide controls
ERepetition ->Visible=!RbLoocv->Checked;
LaRepetition ->Visible=!RbLoocv->Checked;
BtRepetitionUp ->Visible=!RbLoocv->Checked;
BtRepetitionDown->Visible=!RbLoocv->Checked;
LaSplitting ->Visible=!RbLoocv->Checked && RbRepetition->Checked;
TbDataSplitting ->Visible=!RbLoocv->Checked && RbRepetition->Checked;
CbRandomize ->Visible=!RbLoocv->Checked; // hide as irrelevant for LOOCV
//c) set # repetitions/cross-validations text
ERepetition->Text = AnsiString(prj.Get_N_R_Tune());
// d) set data splitting
char szText[256];
sprintf(szText, "Data Splitting %d\%", TbDataSplitting->Position);
LaSplitting->Caption = szText;
TbDataSplitting->Position = prj.GetDataSplitting();
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// display actual number of tune parameter sets or a hint how to define some
void TFMain::SetNParameterSets()
{
if(prj.nParaSets()>0)
LaRuns->Caption = "You've defined " + AnsiString(prj.nParaSets()) + " parameter set(s).";
else
LaRuns->Caption = "Hit 'Edit Tasks' to define parameter sets!";
}
//----------------------------------------------------------------------------------------------------------------------
// initialize parameters in group box 'Parameters' in tab sheet 'Basic' with given values
void TFMain::SetParameters(const TParaSet& para)
{
f_LearnParaInitialized = true; // set flag
// a) copy from standard parameter object
learnPara = para;
// b) set texts in parameter edit fields
if(!CbClassification->Checked) // parameter 'Intervals'
EIntervals->Text = ValueToText1(learnPara.N_Int); // regression: # output intervals
else
EIntervals->Text = ValueToText1(prj.nClasses()); // classifciation: # classes
EWmin ->Text = ValueToText1(learnPara.w_COD, 0, PREC_PARA); // w_COD
EEta ->Text = ValueToText1(learnPara.Eta); // eta
ECardinality ->Text = ValueToText1(learnPara.p_min); // min. cuboid mass
ESigma ->Text = ValueToText1(learnPara.Sigma, 0, PREC_PARA); // sigma
ESpecial ->Text = ValueToText1(learnPara.W_Kernel); // special (kernel width)
// c) set check box states of boolean parameters
CbWeights ->Checked = learnPara.Weights; // use weights
CbPrune ->Checked = learnPara.Prune; // prune cuboids
CbEuclidean->Checked = (learnPara.Metric==2); // euclidean distance
// d)
CbPruneAnyWay->Checked = prj.PruneAnyway();
CbKillCuboids->Checked = prj.KillCuboids();
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Load' on tab sheet 'Basic' clicked: Open file open dialog and load selected test
// data file
void __fastcall TFMain::BtLearnDataClick(TObject *Sender)
{
// a) if learn data is already loaded (or model imported)
if(data_L || model)
{
if(!f_DisableWarnings) // ask user if he wants to load another file
if(Application->MessageBox(szLearnDataLoaded, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
return;
ActionList(EmptyProject);
}
// b) set dialog caption/options and execute it
OpenDialog->Title = "Open learn data file ...";
OpenDialog->Options << ofFileMustExist << ofPathMustExist;
OpenDialog->DefaultExt = "dat";
OpenDialog->Filter = "ASCII data files (*.dat)|*.dat|Any file (*.*)|*.*";
OpenDialog->FileName = "";
if(!OpenDialog->Execute())
return; // return if closed with 'Cancel' button
// display filename
LaLearnFile->Caption = MinimizeName(OpenDialog->FileName, LaLearnFile->Canvas, LaLearnFile->Width);
// c) set flags and load selected data file in additional thread showing actual progress
f_Loading = true;
f_Stop = false;
data_L = new TData(); // new data object
// new thread object, note: deletes itself
LoadDataThread = new ThrLoadData(false, data_L, OpenDialog->FileName.c_str(), &CallLoadLearnDataFinish, &f_Stop);
// enable/show and disable/hide controls
PbLearnData ->Position= 0; // reset progress bar
PbLearnData ->Visible = true; // show progress bar
BtLearnData ->Enabled = false; // disable 'Load Data'
BtLearnDataPause->Enabled = true; // enable 'Pause'
BtLearnDataAbort->Enabled = true; // enable 'Abort'
LoadDataTimer->OnTimer = &OnLoadLearnDataTimer; // set OnTimer function
LoadDataTimer ->Enabled = true; // start progress indication timer
ActiveControl = BtLearnDataPause;
EnableMenus(false); // disbale menu entries
ActLearnDataStatus(false); // ... but do not(!) actualize filename because maybe it is not
// initialized in TData object yet
}
//----------------------------------------------------------------------------------------------------------------------
// Called after learn data has been loaded: Enable learn data and other controls
// callback wrapper function
void CallLoadLearnDataFinish(const bool& f_Error){
FMain->OnLoadLearnDataFinish(f_Error);}
void TFMain::OnLoadLearnDataFinish(const bool& _f_Error)
{
bool f_Error = _f_Error; // copy
// a) enable/disable controls
f_Loading = false; // reset flag
LoadDataTimer ->Enabled = false; // disable progress indication timer
BtLearnDataPause->Enabled = false; // disable 'Pause' button
BtLearnDataAbort->Enabled = false; // disable 'Abort' button
BtLearnData ->Enabled = true; // enable 'Load' button
PbLearnData ->Visible = false; // hide progress bar
EnableMenus(true); // enable menu entries
// b) check min. # learn data tuples
if(data_L->nTup()<MIN_LEARN_DATA_TUPLES)
{
char szText[256];
sprintf(szText, "Minimum number of learn data tuples is %d! File loading aborted!", MIN_LEARN_DATA_TUPLES);
Application->MessageBox(szText, "Error", MB_OK | MB_ICONERROR);
f_Error=true;
}
// c) if an error occured while loading -> delete data object and return (action list 'EmptyProject')
if(f_Error)
{
ActionList(EmptyProject);
ActiveControl = BtLearnData;
}
else
ActionList(LearnDataLoaded);
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Pause' on tab sheet 'Learn' clicked: Pause loading of learn data file
void __fastcall TFMain::BtLearnDataPauseClick(TObject *Sender)
{
BtLearnDataPause ->Visible = false; // hide 'Pause' button
BtLearnDataPause ->Refresh();
LoadDataThread ->Suspended = true; // suspend thread
LoadDataTimer ->Enabled = false; // stop progress indication timer
BtLearnDataContinue->Visible = true; // show 'Continue' button
BtLearnDataContinue->Refresh();
ActiveControl = BtLearnDataContinue; // set focus to button 'Continue'
LaLearnDataStatus->Caption = "Paused"; // display status
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Continue' on tab sheet 'Learn' clicked: Resume loading of learn data file
void __fastcall TFMain::BtLearnDataContinueClick(TObject *Sender)
{
BtLearnDataContinue->Visible = false; // hide 'Continue' button
BtLearnDataContinue->Refresh();
LoadDataThread->Suspended = false; // continue thread
LoadDataTimer->Enabled = true; // enable progress indication timer again
BtLearnDataPause->Visible = true; // show 'Pause' button
BtLearnDataPause->Refresh();
ActiveControl = BtLearnDataPause;
LaLearnDataStatus->Caption = AnsiString(data_L->StatusText());
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Abort' on tab sheet 'Basic' clicked: Ask user and abort loading of learn data file
void __fastcall TFMain::BtLearnDataAbortClick(TObject *Sender)
{
// a) suspend thread note: necessary cause otherwise the code in c) could cause an exception
BtLearnDataPauseClick(this);
// b) ask user if he really wants to abort
if(f_DisableQuestions || Application->MessageBox("I'm loading the learn data file! Do you really want to abort ??"
, "Question", MB_YESNO | MB_ICONQUESTION)== ID_YES)
{
// c) abort
BtLearnDataContinue->Visible = false; // hide button 'Continue'
f_Stop = true; // set stop flag, this will cause thread to terminate
}
BtLearnDataContinueClick(this); // continue thread
}
//----------------------------------------------------------------------------------------------------------------------
// respond to changes of classifciation check box
void __fastcall TFMain::CbClassificationClick(TObject *Sender)
{
// a) return if nothing has changed
const bool f_Regression = !CbClassification->Checked; // abbreviation
if(prj.Regression()==f_Regression)
return;
// b) ask user if tune results or parameter sets are present because they would be lost
// or inform him that his change does not have any effect until ...
if(tuneResults || prj.nParaSets()>0)
{
if(Application->MessageBox("All defined parameters sets and tune results will be\
lost.\nDo you really want to change the problem type ??", "Question", MB_YESNO | MB_ICONQUESTION)== ID_NO)
{
// if user selects 'No' ...
CbClassification->Checked = !prj.Regression(); // ... restore old setting ...
return; // ... and return
}
}
// inform user that this does not have any effect on learned model until model is re-learned
else
if(model)
Application->MessageBox("This change does not have any effect on the learned model until you re-learn it!",
"Information", MB_OK | MB_ICONINFORMATION);
// c) delete tune tasks and results
ActionList(DeleteTuningTasks); // tune tasks
ActionList(DeleteTuningResults); // tune results
SetSavedFlag(false); // project unsaved now
// d) update regression project
prj.Regression() = f_Regression;
// e) update GUI
EvOutputType();
SetNParameterSets(); // display # parameter sets (maybe they've been deleted)
}
//----------------------------------------------------------------------------------------------------------------------
// output column controls
// update output column
void __fastcall TFMain::EOutColExit(TObject *Sender){ ChangeOutCol(atof(EOutCol->Text.c_str())-1); }
void __fastcall TFMain::EOutColKeyDown(TObject*, WORD& Key, TShiftState)
{
if(Key==VK_RETURN) EOutColExit(this); // enter pressed -> update output column
if(Key==VK_END) ChangeOutCol(data_L->nVar()-1); // 'End' pressed -> set maximal possible output column
if(Key==VK_HOME) ChangeOutCol(0); // 'Pos 1' pressed -> set minimal possible output column
if(Key==VK_UP) ChangeOutCol(prj.GetOutCol()+1); // 'Arrow Up' pressed -> increment output column
if(Key==VK_DOWN) ChangeOutCol(prj.GetOutCol()-1); // 'Arrow Down' pressed -> decrement output column
if(Key==VK_PRIOR) ChangeOutCol(prj.GetOutCol()+10); // 'Page Up' pressed -> decrement output column by 10
if(Key==VK_NEXT) ChangeOutCol(prj.GetOutCol()-10); // 'Page Down' pressed -> decrement output column by 10
}
void __fastcall TFMain::EOutColClick(TObject*){ EOutCol->SelectAll();} // select text
void __fastcall TFMain::BtOutColUpClick(TObject*) // button with arrow up clicked
{
ChangeOutCol(prj.GetOutCol()+1); // increment output column by one update
ActiveControl = EOutCol; // give focus back
}
void __fastcall TFMain::BtOutColDownClick(TObject*) // button with arrow down clicked
{
ChangeOutCol(prj.GetOutCol()-1); // decrement output columns by one and update
ActiveControl = EOutCol; // give focus back
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Edit Types' in tab sheet 'Basic' clicked: Open variable type selection dialog
void __fastcall TFMain::BtEditTypesClick(TObject *Sender)
{
DoIt(); // write through output column and set data and project in TVarTypes object
FVarTypes->ShowModal(); // show dialog
}
//----------------------------------------------------------------------------------------------------------------------
// respond to tune type radio buttons and 'Skip tuning' check box changes
void __fastcall TFMain::RbRepetitionClick (TObject*) { EvTuneType(); }
void __fastcall TFMain::RbCrossValidationClick(TObject*) { EvTuneType(); }
void __fastcall TFMain::RbLoocvClick (TObject*) { EvTuneType(); }
void __fastcall TFMain::CbSkipTuningClick(TObject*)
{
if(!data_L)
return;
// a) initialize parameter texts in group box 'Parameters' if this has not been done so far
if(CbSkipTuning->Checked && !f_LearnParaInitialized)
{
DoItExt(); // write through output column, calculate weights and initialize standard parameters
SetParameters(stdPara); // set standard parameters
}
// b) enable/disable controls in group box 'Parameters' or 'Tune parameters'
EnableTuneCtrls(!CbSkipTuning->Checked);
EnableParameterCtrls(CbSkipTuning->Checked);
prj.SetTuning(!CbSkipTuning->Checked); // write to project
// set appropriate focus
if(PageControl->ActivePage==TsBasic)
SetTsLearnFocus();
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// changes of data splitting settings
void __fastcall TFMain::TbDataSplittingChange(TObject *Sender)
{
char text[256];
sprintf(text, "Data Splitting %d\%", TbDataSplitting->Position);
LaSplitting->Caption = text; // update text about slider bar
prj.SetDataSplitting(TbDataSplitting->Position); // set data splitting in project
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// write check box changes to project
void __fastcall TFMain::CbRandomizeClick(TObject *Sender)
{
prj.Randomize() = CbRandomize->Checked;
SetSavedFlag(false); // project not saved anymore
}
void __fastcall TFMain::CbSkippingClick(TObject *Sender)
{
prj.Skipping() = CbSkipping->Checked;
SetSavedFlag(false); // project not saved anymore
EnableTuneCtrls(!CbSkipTuning->Checked); // enable/disable skipping parameters using this call
}
//----------------------------------------------------------------------------------------------------------------------
// controls for # repetitions/cross-validation
void __fastcall TFMain::ERepetitionExit(TObject*)
{
Set_N_R_Tune(atof(ERepetition->Text.c_str())); // set (will be checked)
}
void __fastcall TFMain::BtRepetitionUpClick(TObject*) // arrow up clicked
{
int inc = 1; // increment by one for Cross-Validation
if(RbRepetition->Checked) // increment by five for repetition
inc = 5;
Set_N_R_Tune(prj.Get_N_R_Tune()+inc); // set in project and re-write(will be checked against constraints)
ActiveControl = ERepetition; // give focus back
}
void __fastcall TFMain::BtRepetitionDownClick(TObject*)// arrow down clicked
{
int inc = 1; // decrement by one for Cross-Validation
if(RbRepetition->Checked) // decrement by five for repetition
inc = 5;
Set_N_R_Tune(prj.Get_N_R_Tune()-inc); // set in project and re-write (will be checked against constraints)
ActiveControl = ERepetition; // give focus back
}
void __fastcall TFMain::ERepetitionClick(TObject*)
{
ERepetition->SelectAll();
}
void __fastcall TFMain::ERepetitionKeyDown(TObject*, WORD &Key, TShiftState)
{
if(Key==VK_RETURN)
ERepetitionExit(this); // enter pressed -> update
else
{ // else: alter repetition count
if(Key==VK_END) Set_N_R_Tune(MAX_N_R_TUNE); // 'End' pressed -> set maximal possible
if(Key==VK_HOME) Set_N_R_Tune(0); // 'Pos 1' pressed -> set minimal possible
if(Key==VK_UP) Set_N_R_Tune(prj.Get_N_R_Tune()+1); // 'Arrow Up' pressed -> increment
if(Key==VK_DOWN) Set_N_R_Tune(prj.Get_N_R_Tune()-1); // 'Arrow Down' pressed -> decrement
if(Key==VK_PRIOR) Set_N_R_Tune(prj.Get_N_R_Tune()+10); // 'Page Up' pressed -> increment by 10
if(Key==VK_NEXT) Set_N_R_Tune(prj.Get_N_R_Tune()-10); // 'Page Down' pressed -> decrement by 10
}
}
void TFMain::Set_N_R_Tune(const int N_R_Tune)
{
if(!data_L)// return if learn data is not loaded note: may happen if 'File|New' is hit when focus is on ERepetition
return;
prj.Set_N_R_Tune(N_R_Tune); // set in project
ERepetition->Text = prj.Get_N_R_Tune(); // re-write text
ERepetition->SelectAll(); // select text
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// controls for maximum model size
void __fastcall TFMain::EMaxSizeExit(TObject*)
{
SetMaxSize(atof(EMaxSize->Text.c_str()));
}
void __fastcall TFMain::BtMaxSizeUpClick(TObject*) // arrow up clicked
{
int act = prj.GetMaxSize(); // get actual setting
int inc =1; // increment by 1 if actual value is below 15, by 5 else
if(act>=15)
inc = 5;
SetMaxSize(act+inc); // set new value
ActiveControl = EMaxSize; // give focus back
}
void __fastcall TFMain::BtMaxSizeDownClick(TObject*) // arrow down clicked
{
int act = prj.GetMaxSize(); // get actual setting
int dec =1; // decrement by 1 if actual value is below 15, by 5 else
if(act>15)
dec = 5;
SetMaxSize(act-dec); // set new value
ActiveControl = EMaxSize; // give focus back
}
void __fastcall TFMain::EMaxSizeKeyDown(TObject*, WORD &Key, TShiftState)
{
if(Key==VK_RETURN)
EMaxSizeExit(this); // enter pressed -> update
else
{ // else: alter max size setting
if(Key==VK_END) SetMaxSize(MAX_MAX_SIZE); // 'End' pressed -> set maximal possible
if(Key==VK_HOME) SetMaxSize(MIN_MAX_SIZE); // 'Pos 1' pressed -> set minimal possible
if(Key==VK_UP) SetMaxSize(prj.GetMaxSize()+1); // 'Arrow Up' pressed -> increment by 1
if(Key==VK_DOWN) SetMaxSize(prj.GetMaxSize()-1); // 'Arrow Down' pressed -> decrement by 1
if(Key==VK_PRIOR) SetMaxSize(prj.GetMaxSize()+10); // 'Page Up' pressed -> increment by 10
if(Key==VK_NEXT) SetMaxSize(prj.GetMaxSize()-10); // 'Page Down' pressed -> decrement by 10
}
}
void __fastcall TFMain::EMaxSizeClick(TObject*){ EMaxSize->SelectAll(); }
void TFMain::SetMaxSize(const int maxSize)
{
prj.SetMaxSize(maxSize); // set in project
// (will be checked against constraints)
EMaxSize->Text = AnsiString(prj.GetMaxSize()) + " %"; // re-write text
EMaxSize->SelectAll(); // select text
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// controls for minimum compression
void __fastcall TFMain::EMinCmprExit(TObject*)
{
SetMinCmpr(atof(EMinCmpr->Text.c_str()));
}
void __fastcall TFMain::BtMinCmprUpClick(TObject*) // arrow up clicked
{
int act = prj.GetMinCompression(); // get actual setting
SetMinCmpr(act+5); // increment by 5
ActiveControl = EMinCmpr; // give focus back
}
void __fastcall TFMain::BtMinCmprDownClick(TObject*) // arrow down clicked
{
int act = prj.GetMinCompression(); // get actual setting
SetMinCmpr(act-5); // set new value
ActiveControl = EMinCmpr; // give focus back
}
void __fastcall TFMain::EMinCmprKeyDown(TObject*, WORD& Key, TShiftState)
{
if(Key==VK_RETURN)
EMinCmprExit(this); // enter pressed -> update
else
{ // else: alter max size setting
if(Key==VK_END) SetMinCmpr(MAX_MIN_COMPRESSION); // 'End' pressed -> set maximal possible
if(Key==VK_HOME) SetMinCmpr(MIN_MIN_COMPRESSION); // 'Pos 1' pressed -> set minimal possible
if(Key==VK_UP) SetMinCmpr(prj.GetMinCompression()+1); // 'Arrow Up' pressed -> increment by 1
if(Key==VK_DOWN) SetMinCmpr(prj.GetMinCompression()-1); // 'Arrow Down' pressed -> decrement by 1
if(Key==VK_PRIOR) SetMinCmpr(prj.GetMinCompression()+10); // 'Page Up' pressed -> increment by 10
if(Key==VK_NEXT) SetMinCmpr(prj.GetMinCompression()-10); // 'Page Down' pressed -> decrement by 10
}
}
void __fastcall TFMain::EMinCmprClick(TObject *Sender){ EMinCmpr->SelectAll(); }
void TFMain::SetMinCmpr(const int minCmpr)
{
prj.SetMinCompression(minCmpr); // set in project
// (will be checked against constraints)
EMinCmpr->Text = AnsiString(prj.GetMinCompression()) + " %"; // re-write text
EMinCmpr->SelectAll(); // select text
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Edit Tasks' in tab sheet 'Basic' clicked: Open tune tasks dialog
void __fastcall TFMain::BtEditSetsClick(TObject *Sender)
{
DoItExt(); // write through output column, calculate weights and initialize standard parameters
FEditSets->ShowModal(); // show dialog
SetNParameterSets(); // afterwards: display # runs
BtTune->Enabled = (prj.nParaSets()>0); // enable button 'Tune' if tune parameter sets are defined
SetTsLearnFocus(); // set appropriate focus
if(FEditSets->SomethingChanged()) // ask if somth. has changed and eventually unset save flag
SetSavedFlag(false);
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Basic' group box 'Parameters': functions which get called if one of the edit fields (TEdit) exits,
// i.e. looses focus -> parse and check entered text using CheckParameterString() and update learn parameter
// note: the commands are always the same: a) buffer text, b) select text in edit control, c) check parameter string
// and in case of an error give the focus back to edit control and write back buffered text. Or set new value if
// all's ok.
void __fastcall TFMain::EIntervalsExit(TObject *Sender)
{
// note: will be disabled for classification tasks
AnsiString tmp = EIntervals->Text; // buffer text
EIntervals->SelectAll();
if(CheckParameterString(true, tmp, LaIntervals->Caption, stdPara.N_Int, MIN_N_INT, INT_N_INT, MAX_N_INT))
{
ActiveControl = EIntervals; // error? -> give focus back
EIntervals->Text = tmp; // write back
}
else
{
learnPara.N_Int = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::EWminExit(TObject *Sender)
{
AnsiString tmp = EWmin->Text; // buffer text
EWmin->SelectAll();
if(CheckParameterString(true, tmp, LaWmin->Caption, stdPara.w_COD, MIN_W_COD, INT_W_COD, Max_w_COD(data_L)))
{
ActiveControl = EWmin; // error? -> give focus back
EWmin->Text = tmp; // write back
}
else
{
learnPara.w_COD = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::EEtaExit(TObject *Sender)
{
AnsiString tmp = EEta->Text; // buffer text
EEta->SelectAll();
if(CheckParameterString(true, tmp, LaEta->Caption, stdPara.Eta, MIN_ETA, INT_ETA, MAX_ETA))
{
ActiveControl = EEta; // error? -> give focus back
EEta->Text = tmp; // write back
}
else
{
learnPara.Eta = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::ECardinalityExit(TObject *Sender)
{
AnsiString tmp = ECardinality->Text; // buffer text
ECardinality->SelectAll();
if(CheckParameterString(true, tmp, LaCardinality->Caption, stdPara.p_min, MIN_P_MIN, INT_P_MIN, Max_P_Min(data_L)))
{
ActiveControl = ECardinality; // error? -> give focus back
ECardinality->Text = tmp; // write back
}
else
{
learnPara.p_min = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::ESpecialExit(TObject *Sender)
{
AnsiString tmp = ESpecial->Text; // buffer text
ESpecial->SelectAll();
if(CheckParameterString(true, tmp, LaSpecial->Caption, stdPara.W_Kernel, MIN_W_KERNEL, INT_W_KERNEL, MAX_W_KERNEL))
{
ActiveControl = ESpecial; // error? -> give focus back
ESpecial->Text = tmp; // write back
}
else
{
learnPara.W_Kernel = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::ESigmaExit(TObject *Sender)
{
AnsiString tmp = ESigma->Text; // buffer text
ESigma->SelectAll();
if(CheckParameterString(true, tmp, LaSigma->Caption, stdPara.Sigma, MIN_SIGMA, INT_SIGMA, MAX_SIGMA))
{
ActiveControl = ESigma; // error? -> give focus back
ESigma->Text = tmp; // write back
}
else
{
learnPara.Sigma = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Basic' group box 'Parameters': One of the check boxes was clicked -> update corresponding learn
// parameter value
// actualize learn parameter 'Prune' and enable/disable 'Prune Any Way' check box
void __fastcall TFMain::CbPruneClick(TObject *Sender)
{
learnPara.Prune = CbPrune->Checked; // actualize setting
if(!CbPrune->Checked)
CbPruneAnyWay->Enabled = CbPrune->Enabled;
else
CbPruneAnyWay->Enabled = false;
SetSavedFlag(false); // project not saved anymore
}
// actualize project setting 'PruneAnyway'
void __fastcall TFMain::CbPruneAnyWayClick(TObject*)
{
prj.PruneAnyway() = CbPruneAnyWay->Checked;
SetSavedFlag(false); // project not saved anymore
}
// actualize project setting 'KillCuboids'
void __fastcall TFMain::CbKillCuboidsClick(TObject *Sender)
{
prj.KillCuboids() = CbKillCuboids->Checked;
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// actualize learn parameter 'p' (city-block or euclidian distance)
void __fastcall TFMain::CbEuclideanClick(TObject *Sender)
{
learnPara.Metric = 1;
if(CbEuclidean->Checked) // mapping of parameter 'p' from 'false/true' to '1/2'
learnPara.Metric = 2;
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// actualize learn parameter 'Weights'
void __fastcall TFMain::CbWeightsClick(TObject *Sender)
{
learnPara.Weights = CbWeights->Checked;
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Basic' group box 'Parameters': One of the edit fields was clicked -> select/highlight text
void __fastcall TFMain::EIntervalsClick (TObject *Sender){ EIntervals ->SelectAll(); }
void __fastcall TFMain::EWminClick (TObject *Sender){ EWmin ->SelectAll(); }
void __fastcall TFMain::EEtaClick (TObject *Sender){ EEta ->SelectAll(); }
void __fastcall TFMain::ECardinalityClick(TObject *Sender){ ECardinality->SelectAll(); }
void __fastcall TFMain::ESpecialClick (TObject *Sender){ ESpecial ->SelectAll(); }
void __fastcall TFMain::ESigmaClick (TObject *Sender){ ESigma ->SelectAll(); }
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Basic' group box 'Parameters': User hits enter -> forward to exit functions
void __fastcall TFMain::EIntervalsKeyDown (TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)EIntervalsExit(this); }
void __fastcall TFMain::EWminKeyDown (TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)EWminExit(this);}
void __fastcall TFMain::EEtaKeyDown (TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)EEtaExit(this);}
void __fastcall TFMain::ECardinalityKeyDown(TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)ECardinalityExit(this);}
void __fastcall TFMain::ESpecialKeyDown (TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)ESpecialExit(this);}
void __fastcall TFMain::ESigmaKeyDown (TObject*,WORD& Key,TShiftState){if(Key==VK_RETURN)ESigmaExit(this);}
//-----------------------------------------------------------------------------------------------
//
// Tab Sheet 'Tuning Results'
//
//----------------------------------------------------------------------------------------------------------------------
// double click on list view: same as button 'Select' if item (parameter set) is highlighted
void __fastcall TFMain::LvTuneResultsDblClick(TObject* )
{
if(BtSelect->Enabled)
BtSelectClick(this);
}
//----------------------------------------------------------------------------------------------------------------------
// column header in listview on tab sheet 'Tuning Results' clicked: Sort with repect to the column clicked
void __fastcall TFMain::LvTuneResultsColumnClick(TObject*, TListColumn *Column)
{
ColumnToSort = Column->Index; // store column for LvTuningResultsCompare()
LvTuneResults->AlphaSort(); // sort
}
//----------------------------------------------------------------------------------------------------------------------
// OnCompare event handler for sorting of rows in listview on tab sheet 'Tuning Results'
void __fastcall TFMain::LvTuneResultsCompare(TObject*, TListItem* Item1, TListItem* Item2, int Data, int &Compare)
{
// a) convert list item text to floating point numbers mapping 'true'/'false' to '1'/'0'
float a,b;
if(ColumnToSort==0) // first column: access using 'Caption'
{
a = atof(Item1->Caption.c_str());
b = atof(Item2->Caption.c_str());
}
else // all other columns: access using 'SubItems->Strings[]'
{
int ix = ColumnToSort-1;
const char* szA = Item1->SubItems->Strings[ix].c_str(); // get first item's text
const char* szB = Item2->SubItems->Strings[ix].c_str(); // get 2th item's text
if(strcmp(szA, "true")==0) // convert to float
a = 1;
else
if(strcmp(szA, "false")==0)
a = 0;
else
a = atof(szA);
if(strcmp(szB, "true")==0) // convert to float
b = 1;
else
if(strcmp(szB, "false")==0)
b = 0;
else
b = atof(szB);
}
// b) compare
if(a==b)
Compare = 0;
else
if(a>b)
Compare = 1;
else
Compare = -1;
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Tune' in tab sheet 'Basic' clicked: Start parameter tuning
void __fastcall TFMain::BtTuneClick(TObject *Sender)
{
// 1. ask user if there are existing tune results because these will be lost
if(tuneResults)
if(!f_DisableWarnings && Application->MessageBox("Previous tune results will be lost! Do you want to continue ??"
, "Warning", MB_YESNO | MB_ICONWARNING)==ID_NO)
return; // return if user selects 'No'
else
ActionList(DeleteTuningResults); // else: delete old tune results
SetSavedFlag(false); // unset flag that project is saved
// 2. misc.
DoItExt(); // write through output column and calculate weights etc.
// 3. instantiate tune results object and thread object
f_Tuning = true;
f_Stop = false;
tuneResults = new TTune(prj.ToParaSetList(), &prj, data_L); // new tune results object
TuneThread = new ThrTune(false, this, tuneResults); // new thread object note: deletes itself
tuneStartTime = clock(); // get start time
tuneTime = 0; // ini
// 4. enable/show and disable/hide controls
PbTune->Position = 0; // reset
LaTuneTime->Caption = ""; // clear string
PbTune ->Visible = true; // show progress bar
BtTunePause->Enabled = true; // enable 'Pause'
BtTuneAbort->Enabled = true; // enable 'Abort'
TuningTimer->Enabled = true; // start progress indication timer
EnableMenus(false); // disable menu entries
TsTuneResults->TabVisible = true; // show tab sheet 'Tune Results' and
PageControl->ActivePage = TsTuneResults; // ... change to it
ActiveControl = BtTunePause;
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Pause' on tab sheet 'Tune Results' clicked: Pause tuning
void __fastcall TFMain::BtTunePauseClick(TObject *Sender)
{
BtTunePause ->Visible = false; // hide 'Pause' button
BtTunePause ->Refresh();
TuneThread ->Suspended = true; // suspend thread
TuningTimer ->Enabled = false; // stop progress indication timer
BtTuneContinue->Visible = true; // show 'Continue' button
BtTuneContinue->Refresh();
ActiveControl = BtTuneContinue;
tuneTime += clock()-tuneStartTime; // sum up time consumed so far
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Abort' on tab sheet 'Tuning Results' clicked: Ask user and abort tuning
void __fastcall TFMain::BtTuneAbortClick(TObject *Sender)
{
// a) suspend thread note: necessary cause otherwise the code in c) could cause an exception
BtTunePauseClick(this);
// b) ask user if he really wants to abort
if(f_DisableQuestions || Application->MessageBox("I'm tuning! Do you really want to abort ??" , "Question",
MB_YESNO | MB_ICONQUESTION)== ID_YES)
{
// c) abort
BtTuneContinue->Visible = false; // hide button 'Continue'
f_Stop = true; // set stop flag, this will cause thread to terminate
}
BtTuneContinueClick(this); // continue thread
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Continue' on tab sheet 'Tune Results' clicked: Resume parameter tuning
void __fastcall TFMain::BtTuneContinueClick(TObject *Sender)
{
BtTuneContinue->Visible = false; // hide 'Continue' button
BtTuneContinue->Refresh();
TuneThread->Suspended = false; // continue thread
TuningTimer->Enabled = true; // enable progress indication timer again
BtTunePause->Visible = true; // show 'Pause' button
BtTunePause->Refresh();
ActiveControl = BtTunePause;
LaTuneStatus->Caption = AnsiString(tuneResults->GetStatusText());
tuneStartTime = clock(); // get new start time
}
//----------------------------------------------------------------------------------------------------------------------
// write tune results (as necessary) to list view
void TFMain::AddTuningResults()
{
for(int i=LvTuneResults->Items->Count;i<tuneResults->GetResultsOk();i++)
AddTuningResult(i);
}
//----------------------------------------------------------------------------------------------------------------------
// write one(!) new tune result to list view
void TFMain::AddTuningResult(const int& id)
{
TListItem* item = LvTuneResults->Items->Add(); // add new list item
// copy parameter strings to list view
TParaSet para = tuneResults->GetParameter(id); // abbreviation
item->Caption = LvTuneResults->Items->Count; // task id
item->SubItems->Add(ValueToText1(para.N_Int)); // # output intervals
item->SubItems->Add(ValueToText1(para.w_COD, 0, PREC_PARA)); // w_COD
item->SubItems->Add(ValueToText1(para.Eta)); // eta
item->SubItems->Add(ValueToText1(para.p_min)); // min. cuboid mass
if(prj.Regression())
item->SubItems->Add(ValueToText1(para.Sigma, 0, PREC_PARA)); // sigma
else
item->SubItems->Add(ValueToText1(para.W_Kernel)); // special (kernel width)
// boolean parameters: initialize check boxes
item->SubItems->Add(FlagToString(para.Weights)); // use weights
item->SubItems->Add(FlagToString(para.Prune)); // prune cuboids
item->SubItems->Add(FlagToString(para.Metric==2));
for(int i=0;i<N_TUNE_RES;i++)
item->SubItems->Add(ValueToText1(tuneResults->GetResults(id)[i], 0, 1)); // model characteristics
}
//----------------------------------------------------------------------------------------------------------------------
// timer functions: gets called while parameters are tuned, display progress
void __fastcall TFMain::TuningTimerTimer(TObject *Sender)
{
PbTune->Position = tuneResults->GetProgress(); // set progress bar
clock_t time = tuneTime + clock()-tuneStartTime; // get elapsed time and ...
LaTuneTime->Caption = WriteTime2(time); // display it
LaTuneStatus->Caption = AnsiString(tuneResults->GetStatusText()); // actualize status text
AddTuningResults(); // add tune results as necessary to list view
}
//----------------------------------------------------------------------------------------------------------------------
// gets called if tune thread terminates: disable thread controls etc.
void TFMain::OnTuningFinished()
{
// a)
PbTune ->Visible = false; // hide progress bar
BtTunePause ->Enabled = false; // disable 'Pause'
BtTuneAbort ->Enabled = false; // disable 'Abort'
TuningTimer ->Enabled = false; // stop progress indication timer
EnableMenus(true); // enable menu entries
ActiveControl = PageControl; // give focus to page control (tab sheets)
// b) add tune results as necessary to list view
AddTuningResults();
// c) check if at least one parameter set is displayed with results
if(LvTuneResults->Items->Count==0)
{
Application->MessageBox("Tuning aborted! No results present!", "Error"
, MB_OK | MB_ICONERROR);
ActionList(DeleteTuningResults); // delete tune results
PageControl->ActivePage = TsBasic; // ... change to tab sheet 'Basic'
return;
}
// d)
f_Tuning = false;
LaTuneStatus->Caption = "Finished";
LaSelectText->Visible = true; // show hint text how to select parameter set
TListItem* item = LvTuneResults->Selected; // enable select button if a parameter set is highlighted in list view
if(item)
BtSelect->Enabled = true;
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Select' on tab sheet 'Tuning Results' clicked: write actually highlighted parameter set to learn parameters
// and change back to tab sheet 'Basic'
void __fastcall TFMain::BtSelectClick(TObject *Sender)
{
// a) get selected item and it's index, return if none is selected
TListItem* item = LvTuneResults->Selected;
if(!item)
return;
const int index = ((int) atof(item->Caption.c_str()))-1;
// b) set parameters
SetParameters(tuneResults->GetParameter(index));
// c)
if(prj.DoTuning()) // if not enabled so far ...
CbSkipTuning->Checked = true; // ... enable 'Skip Tuning' checkbox now
PageControl->ActivePage = TsBasic; // change to tab sheet 'Basics'
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Tuning Results': enable button 'Select' if an list item is selected
void __fastcall TFMain::LvTuneResultsSelectItem(TObject*, TListItem *Item, bool Selected)
{
BtSelect->Enabled = Selected && !f_Tuning;
}
//----------------------------------------------------------------------------------------------------------------------
// display tune results filename if present
void TFMain::ActTuningResultsStatus()
{
if(!f_Tuning) // note: do not change anything if model is learned rigth now, because status is displayed via
// on timer event handler
if(szTuningFile.IsEmpty()) // display model filename if present
{
LaTuneStatusHeader->Caption = "Status";
LaTuneStatus->Caption = "Finished";
}
else
{
LaTuneStatusHeader->Caption = "File";
LaTuneStatus->Caption = MinimizeName(szTuningFile.c_str(), LaTuneStatus->Canvas, LaTuneStatus->Width);
}
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status on tab sheet 'Tuning Results' note: useful for display of filenames with MinimizeName()
void __fastcall TFMain::PageControlResize(TObject *Sender)
{
ActTuningResultsStatus();
}
//-----------------------------------------------------------------------------------------------
//
// Tab Sheet 'Model'
//
//----------------------------------------------------------------------------------------------------------------------
// button 'Default' on tab sheet 'Basic' clicked: restore default parameters
void __fastcall TFMain::BtDefaultClick(TObject *Sender)
{
DoItExt(); // calculate weights, initialize standard parameters
prj.PruneAnyway() = DEF_PRUNE_ANYWAY; // reset defaults and ...
prj.KillCuboids() = DEF_KILL_CUBOIDS;
SetParameters(stdPara); // ... set/display them
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Learn' in tab sheet 'Basic' clicked: Learn model
void __fastcall TFMain::BtLearnClick(TObject *Sender)
{
// 1. ask user if there is an existing model because this will be lost
if(model)
if(!f_DisableWarnings && Application->MessageBox("The learned model will be lost! Do you want to continue ??"
, "Warning", MB_YESNO | MB_ICONWARNING)==ID_NO)
return; // return if user selects 'No'
else
ActionList(DeleteModel); // else: release old model
SetSavedFlag(false); // unset flag that project is saved
// 2. convert parameters from TParaSet and project settings (TProjectG) to TParameter which is used by TPnc
para = ToTParameter(learnPara, &prj); // use utility function ...
if(prj.Regression())
para.N_Int = learnPara.N_Int; // ... and overwrite some settings
else
para.N_Int = prj.nClasses();
// 3. misc.
DoItExt(); // write through output column and calculate weights etc.
data_L->Sort(0); // sort tuples regarding output values (ToDo: move sorting in 2nd thread)
// 4. instantiate pnc object and thread object
int p_min = 0; // initialize
if(prj.KillCuboids()) // if cuboids with a small mass should be deleted ...
p_min = para.p_min; // ... set min. cuboid mass
f_Learning = true;
f_Stop = false;
pnc = new TPnc(data_L, para);
// new thread object note: deletes itself
LearnModelThread = new ThrLearnModel(false, this, pnc, para.Prune || prj.PruneAnyway(), p_min);
learnStartTime = clock(); // get start time
learnTime = 0;
// 5. enable/show and disable/hide controls
PbLearning->Position = 0; // reset
LaModelTime ->Caption = ""; // clear string
PbModelSize ->Position = 100;
PbLearning ->Visible = true; // show progress bar
BtModelPause ->Enabled = true; // enable 'Pause'
BtModelAbort ->Enabled = true; // enable 'Abort'
LearningTimer->Enabled = true; // start progress indication timer
EnableMenus(false); // disable menu entries
PageControl->ActivePage = TsModel; // ... change to tab sheet 'Model'
ActiveControl = BtModelPause;
ActModelParameters(); // initialize displayed parameters and values
ActionList(ClearResults); // clear loss results
}
//----------------------------------------------------------------------------------------------------------------------
// gets called with learn thread has finished: update controls
void TFMain::OnLearnModelFinished(TCluster* _model)
{
// a)
PbLearning ->Visible = false; // hide progress bar
BtModelPause ->Enabled = false; // disable 'Pause'
BtModelAbort ->Enabled = false; // disable 'Abort'
LearningTimer->Enabled = false; // stop progress indication timer
EnableMenus(true); // enable menu entries
ActiveControl = PageControl; // give focus to page control (tab sheets)
f_Learning = false;
// b) check if learning was finished (i.e. not aborted) and prepare model (set cardinality)
model = _model;
if(f_Stop) // stoped, i.e. aborted ...
{
PageControl->ActivePage = TsBasic; // ... change to tab sheet 'Basic'
ActionList(DeleteModel); // and delete model again
}
// c) delete learn object as it is not needed anymore
delete pnc;
pnc = NULL;
// d)
learnTime += clock()-learnStartTime; // sum up time consumed so far
ActModelParameters(); // initialize displayed parameters and values
MnSaveModel->Enabled = true; // enable menu entry 'Export Model' and toolbar button
TbSaveModel->Enabled = true; //
ActModelStatus(); // display "Finished"
}
//----------------------------------------------------------------------------------------------------------------------
// timer functions: gets called while model is learned, display progress
void __fastcall TFMain::OnLearningTimer(TObject *Sender)
{
if(!pnc) // security check: return if no object is present
return;
PbLearning ->Position = 100*pnc->GetProgress(learnPara.Prune || prj.PruneAnyway()); // set progress bar
PbModelSize ->Position = 100*pnc->GetSizeRatio(); // set model size bar
LaModelStatus->Caption = pnc->GetStatusText(); // set status text
clock_t time = learnTime + clock()-learnStartTime; // get elapsed time and ...
LaModelTime->Caption = WriteTime2(time); // display it
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Pause' on tab sheet 'Model' clicked: Pause learning of pnc model
void __fastcall TFMain::BtModelPauseClick(TObject *Sender)
{
BtModelPause ->Visible = false; // hide 'Pause' button
BtModelPause ->Refresh();
LearnModelThread->Suspended = true; // suspend thread
LearningTimer ->Enabled = false; // stop progress indication timer
BtModelContinue->Visible = true; // show 'Continue' button
BtModelContinue->Refresh();
ActiveControl = BtModelContinue;
LaModelStatus->Caption = "Paused"; // display status
learnTime += clock()-learnStartTime; // sum up time consumed so far
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Abort' on tab sheet 'Model' clicked: Ask user and abort learning of pnc model
void __fastcall TFMain::BtModelAbortClick(TObject *Sender)
{
// a) suspend thread note: necessary cause otherwise the code in c) could cause an exception
BtModelPauseClick(this);
// b) ask user if he really wants to abort
if(f_DisableQuestions || Application->MessageBox("I'm learning! Do you really want to abort ??", "Question",
MB_YESNO|MB_ICONQUESTION)==ID_YES)
{
// c) abort
BtModelContinue->Visible = false; // hide button 'Continue'
f_Stop = true; // set stop flag, this will cause thread to terminate
}
BtModelContinueClick(this); // continue thread
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Continue' on tab sheet 'Model' clicked: Resume learning of pnc model
void __fastcall TFMain::BtModelContinueClick(TObject *Sender)
{
BtModelContinue->Visible = false; // hide 'Continue' button
BtModelContinue->Refresh();
LearnModelThread->Suspended = false; // continue thread
LearningTimer ->Enabled = true; // enable progress indication timer again
BtModelPause ->Visible = true; // show 'Pause' button
BtModelPause ->Refresh();
ActiveControl = BtModelPause;
learnStartTime = clock(); // get new start time
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status on tab sheet 'Model' note: useful for display of filenames with MinimizeName()
void __fastcall TFMain::TsModelResize(TObject *Sender)
{
ActModelStatus();
}
//----------------------------------------------------------------------------------------------------------------------
// write model parameters to labels in tab sheets 'Model' and 'Use Model'
// note: call immediately after learn thread was started ('para' will be used) and call again after learning is
// finished (TCluster::para will be used but the two objects are identical. Also call after model has been loaded
void TFMain::ActModelParameters()
{
// a) get parameters, either from TPnc object (while learning) or from model (when finished)
const TParameter* para;
if(model)
para = model->GetParameters(); // parameters from model
else
if(pnc)
para = pnc->GetParameters(); // parameters from TPnc learn object
else
return; // note: should be an error ?
// b) tab sheet 'Model' group box 'Parameters'
TsModel->TabVisible = true; // show tab sheet 'Model'
// b1) set label texts
LaModelIntervalsValue ->Caption = ValueToText1(para->N_Int); // # intervals
LaModelWminValue ->Caption = ValueToText1(para->w_COD, 0, PREC_PARA); // w_COD
LaModelEtaValue ->Caption = ValueToText1(para->Eta); // eta
LaModelWeightValue ->Caption = AnsiString(FlagToString(para->Weights)); // use feature weights
LaModelEuclideanValue ->Caption = AnsiString(FlagToString(para->Metric==2)); // euclidean distance
// c) tab sheet 'Model' group box 'Model'
if(!model)
return;
TsUseModel->TabVisible = true; // show tab sheet 'Use Model'
// else:
GbModel->Visible = true; // show group box 'Model'
LaNCuboids1Value ->Caption = model->nCuboids(); // # cuboids
LaNCuboids2Value ->Caption = model->nCuboidsRed(); // # cuboids (reduced)
LaCuboidMassValue->Caption = ValueToText1(model->AvrMass(), 0, 1); // average cuboid mass
LaCuboidSizeValue->Caption = ValueToText1(model->AvrVarPerCub(para->Prune), 0, 1); // avr. # variables per cuboid
LaHitrateValue ->Caption = WritePercentage(model->AvrHitRate(), 0, 1, true); // average hitrate
PbModelSize->Position = 100*model->GetSizeRatio(); // model size
// histogram # cuboids versus mass
model->CalculateHistogram(); // calculate histogram counts
CubHistChart->Visible = true; // show histogram control
Series1->Clear(); // clear
for(int h=0;h<N_BARS;h++) // set bar values
if(model->Histogram(h)==0)
Series1->AddNull("");
else
if(h==N_BARS-1) // last bar collects all masses above
Series1->AddXY(h+1, model->Histogram(h), AnsiString(model->Histogram(h)), clBlue);
else
if(h<model->GetParameters()->p_min)
Series1->AddXY(h+1, model->Histogram(h), AnsiString(model->Histogram(h)), clYellow);
else
Series1->AddXY(h+1, model->Histogram(h), AnsiString(model->Histogram(h)), clGreen);
// d) tab sheet 'Use Model' group boxes '... Parameters'
SetTestParameter1(); // initialize learn and test parameters
SetTestParameter2(); // initialize test parameters
}
//----------------------------------------------------------------------------------------------------------------------
// display model filename if present
void TFMain::ActModelStatus()
{
if(!f_Learning) // note: do not change anything if model is learnd rigth now, because status is displayed vi
// on timer event handler
if(szModelFile.IsEmpty()) // display model filename if present
{
LaModelStatusHeader->Caption = "Status";
LaModelStatus->Caption = "Finished";
}
else
{
LaModelStatusHeader->Caption = "File";
LaModelStatus->Caption = MinimizeName(szModelFile.c_str(), LaModelStatus->Canvas, LaModelStatus->Width);
}
}
//-------------------------------------------------------------------------------------------------------------------
//
// Tab Sheet 'Use Model'
//
//----------------------------------------------------------------------------------------------------------------------
// Gets called if tab sheet 'Use Model' is shown: Enable test data controls if test data file is loaded etc.
void __fastcall TFMain::TsUseModelShow(TObject *Sender)
{
EnableTestDataCtrls(data_T!=NULL); // a) enable test data controls if test data is loaded
ActTestStatus(); // ... file name if simulation output file is given
ActTestDataStatus();
if(!data_T) // set focus ...
ActiveControl = BtTestData; // ... or else to 'Load' button
// note: the focus was already given to button 'Test' or 'Set Output' in EnableTestDataCtrl() if test data is given
if(!model) // return if no model exists note: function should not be called in this case
return;
// c) group box 'Loss Function Results'
const bool f_Regression = model->GetParameters()->f_Regression; // abbreviation
// c1) hide 2nd row of loss result values if it's a classification task
LaLossName2 ->Visible = f_Regression;
LaOverallLoss2->Visible = f_Regression;
LaInsideLoss2 ->Visible = f_Regression;
LaOutsideLoss2->Visible = f_Regression;
BeLossLine2 ->Visible = f_Regression;
// c2) set loss names and height of separating vertical lines
LaLossName1->Caption = "Mae"; // name ini
LaLossName2->Caption = "Mse";
int height = 80; // height ini
if(!f_Regression)
{
height = 50;
LaLossName1->Caption = "Mce"; // name
}
BeLossHorLine1->Height = height; // set heights
BeLossHorLine2->Height = height;
BeLossHorLine3->Height = height;
}
//----------------------------------------------------------------------------------------------------------------------
// Called while deploying (testing) model: Actualize progress bar and status text.
void __fastcall TFMain::OnTestTimer(TObject *Sender)
{
PbTestModel->Position = 100*UseModelThread->Progress()/data_T->nTup(); // set gauge position
clock_t time = testTime + clock()-testStartTime; // get elapsed time and ...
LaTestTime->Caption = WriteTime2(time); // display it
ActLossFunctionResults(); // display actual loss function results
}
//----------------------------------------------------------------------------------------------------------------------
// Called while test data is loaded: Actualize progress bar and status text
void __fastcall TFMain::OnLoadTestDataTimer(TObject*)
{
LaTestDataStatus->Caption = AnsiString(data_T->StatusText());
PbTestData->Position = data_T->LoadDataProgress(); // set gauge position
}
//----------------------------------------------------------------------------------------------------------------------
// hide and show, enable and disable controls in tab sheet 'Use Model'
void TFMain::EnableTestDataCtrls(const bool& f_Enable)
{
// a) group boxes '... Parameters' (parameter editing)
CbModify1->Enabled = f_Enable;
CbModify2->Enabled = f_Enable;
EnableTestTestParameterCtrls (f_Enable && CbModify1->Checked); // enable only if check box 'Modify' is enabled
EnableTestLearnAndTestParameterCtrls(f_Enable && CbModify2->Checked);
// b) group box 'Simulation'
LaSimulationFileHeader->Visible = f_Enable;
LaTestStatusHeader ->Visible = f_Enable;
LaTestTimeHeader ->Visible = f_Enable;
BtTestOutput->Enabled = f_Enable;
LaTestStatus->Visible = f_Enable;
LaTestTime ->Visible = f_Enable;
// enable only if additionally either the test data is with output or an output filename is given
BtTest->Enabled = f_Enable && (f_IsWithOutput || !szSimOutputFile.IsEmpty());
// enable only if additionally the output filename is given and the test data is with output
CbWritePredictions->Enabled = f_Enable && !szSimOutputFile.IsEmpty() && f_IsWithOutput;
// c) group box 'Loss Function Results' note: enable loss related objects only if test data is with output
LaLossName1 ->Enabled = f_Enable && f_IsWithOutput;
LaLossName2 ->Enabled = f_Enable && f_IsWithOutput;
LaOverallLoss1 ->Enabled = f_Enable && f_IsWithOutput;
LaOverallLoss2 ->Enabled = f_Enable && f_IsWithOutput;
LaInsideLoss1 ->Enabled = f_Enable && f_IsWithOutput;
LaInsideLoss2 ->Enabled = f_Enable && f_IsWithOutput;
LaOutsideLoss1 ->Enabled = f_Enable && f_IsWithOutput;
LaOutsideLoss2 ->Enabled = f_Enable && f_IsWithOutput;
LaInsideRatio ->Enabled = f_Enable;
LaTestCuboids ->Enabled = f_Enable;
LaResultHeader1->Enabled = f_Enable && f_IsWithOutput;
LaResultHeader2->Enabled = f_Enable && f_IsWithOutput;
LaResultHeader3->Enabled = f_Enable && f_IsWithOutput;
LaResultHeader4->Enabled = f_Enable; // inside ratio
LaResultHeader5->Enabled = f_Enable; // # cuboids
// d) if enable flag is set: give focus to button 'Test' or 'Set Output'
if(f_Enable)
if(f_IsWithOutput || !szSimOutputFile.IsEmpty())
ActiveControl = BtTest;
else
ActiveControl = BtTestOutput;
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status on tab sheet 'Use Model' note: useful for display of filenames with MinimizeName()
void __fastcall TFMain::TsUseModelResize(TObject *Sender)
{
// call to update displayed filename (because mabe it have been or now has to be minimized)
ActTestDataStatus();
ActTestStatus();
}
//----------------------------------------------------------------------------------------------------------------------
// actualize test data status on tab sheet 'Use Model'
void TFMain::ActTestDataStatus(const bool& f_ActFilename)
{
// group box 'Test Data': display bold hint if no test data file is loaded or sdisplay filename etc.
if(data_T)
{
LaTestFileHeader->Caption = "File";
// set filename note: file name was set after it was specified in OnLoad...
if(f_ActFilename)
LaTestFile->Caption = MinimizeName(data_T->LoadFileName(), LaTestFile->Canvas, LaTestFile->Width);
LaTestDataStatusHeader->Visible = true;
LaTestDataStatus ->Visible = true;
if(!f_Loading)
{
// display # variables and tuples
char text[256];
sprintf(text, "%d variables and %d tuples", data_T->nVar(), data_T->nTup());
LaTestDataStatus->Caption = text;
}
// note: "Loading" is displayed via OnTimer event handler
}
else
{
LaTestFileHeader->Caption = "Hit button to load test data file!"; // display hint that no test data is loaded
LaTestFile ->Caption = "";
LaTestDataStatusHeader->Visible = false;
LaTestDataStatus ->Visible = false;
}
}
//----------------------------------------------------------------------------------------------------------------------
// enable/disable controls in tab sheet 'Use Model' group box 'Test Parameters'
void TFMain::EnableTestTestParameterCtrls(const bool& f_Enable)
{
// enable/disable parameter controls
ETestCardinality ->Enabled = f_Enable;
ETestSigma ->Enabled = f_Enable;
ETestSpecial ->Enabled = f_Enable;
LaTestCardinality->Enabled = f_Enable;
LaTestSigma ->Enabled = f_Enable;
LaTestSpecial ->Enabled = f_Enable;
// disable pruning flag if it cannot be changed, i.e. must be either true (no original cuboids) or false
// (no pruning info)
CbTestPrune->Enabled = f_Enable; // normal operation
if(model)
if(!model->HasPruningInformation() || !model->HasOriginalCuboids()) // but eventually disable
CbTestPrune->Enabled = false;
}
//----------------------------------------------------------------------------------------------------------------------
// enable/disable controls in tab sheet 'Use Model' group box 'Learn and Test Parameters'
void TFMain::EnableTestLearnAndTestParameterCtrls(const bool& f_Enable)
{
CbTestWeights ->Enabled = f_Enable;
CbTestEuclidean->Enabled = f_Enable;
}
//----------------------------------------------------------------------------------------------------------------------
// initialize parameter controls in tab sheet 'Use Model' group box 'Test Parameters' with parameters stored in
// model
void TFMain::SetTestParameter1()
{
// a) check and get parameter object
if(!model) // check: return if no model is present
return;
const TParameter* para = model->GetParameters(); // get parameter object from model
// b) copy parameters from model to project if modify flag is not set
if(!CbModify1->Checked)
{
prj.p_min() = para->p_min;
prj.Sigma() = para->Sigma;
prj.W_Kernel() = para->W_Kernel;
prj.Prune() = para->Prune;
}
// c) set parameter edit fields and check box states
ETestCardinality->Text = prj.p_min();
ETestSigma ->Text = ValueToText1(prj.Sigma(), 0, PREC_PARA);
ETestSpecial ->Text = ValueToText1(prj.W_Kernel());
CbTestPrune->Checked = prj.Prune();
// d) adjust parameter names and visibility depending on regression flag
LaTestSpecial ->Visible = !para->f_Regression; // classification only
ETestSpecial ->Visible = !para->f_Regression;
LaTestSigma ->Visible = para->f_Regression; // regression only
ETestSigma ->Visible = para->f_Regression;
}
//----------------------------------------------------------------------------------------------------------------------
// initialize parameter controls in tab sheet 'Use Model' group box 'Learn and Test Parameters' with parameters
// stored in model
void TFMain::SetTestParameter2()
{
// a) check and get parameter object
if(!model) // check: return if no model is present
return;
const TParameter* para = model->GetParameters(); // get parameter object from model
// b) set parameters if modify flag is set
if(!CbModify2->Checked)
{
prj.UseWeights() = para->Weights;
prj.Euclid() = (para->Metric==2); // map from 'p' to euclidian distance flag
}
// c) set parameter check box states
CbTestWeights ->Checked = prj.UseWeights();
CbTestEuclidean->Checked = prj.Euclid();
}
//----------------------------------------------------------------------------------------------------------------------
// Check box 'Edit' group box 'Test Parameters' in tab sheet 'Use Model' clicked: enable/disable test parameter
// editing
void __fastcall TFMain::CbModify1Click(TObject*)
{
// enable or disable controls
EnableTestTestParameterCtrls(CbModify1->Checked);
// restore parameters from model if box is unchecked
if(!CbModify1->Checked)
SetTestParameter1();
// set in project
prj.Modify1() = CbModify1->Checked;
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// Check box 'Edit' group box 'Learn and Test Parameters' in tab sheet 'Use Model' clicked: enable/disable test
// and learn parameter editing
void __fastcall TFMain::CbModify2Click(TObject*)
{
// enable/disbale controls
EnableTestLearnAndTestParameterCtrls(CbModify2->Checked);
// restore parameters from model if box is unchecked
if(!CbModify2->Checked)
SetTestParameter2();
// set in project
prj.Modify2() = CbModify2->Checked;
SetSavedFlag(false); // project not saved anymore
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Load' on tab sheet 'Use Model' group box 'Test Data' clicked: Open file open dialog and load selected
// test data file
void __fastcall TFMain::BtTestDataClick(TObject *Sender)
{
// a) if test data is already loaded
if(data_T)
{
if(!f_DisableWarnings) // ask user if he wants to load another file
if(Application->MessageBox(szTestDataLoaded, "Warning", MB_YESNO | MB_ICONWARNING)== ID_NO)
return;
ActionList(ClearTestData);
SetSavedFlag(false); // project not saved anymore
}
// b) set dialog caption/options and execute it
OpenDialog->Title = "Open test data file ...";
OpenDialog->Options << ofFileMustExist << ofPathMustExist;
OpenDialog->DefaultExt = "dat";
OpenDialog->Filter = "ASCII data files (*.dat)|*.dat|Any file (*.*)|*.*";
OpenDialog->FileName = "";
if(!OpenDialog->Execute())
return; // return if closed with 'Cancel' button
SetSavedFlag(false); // project not saved anymore
// c) set flags and load selected data file in additional thread showing actual progress
f_Loading = true;
f_Stop = false;
data_T = new TData(); // create data object
// create thread object note: deletes itself
LoadDataThread = new ThrLoadData(false, data_T,OpenDialog->FileName,&CallLoadTestDataFinish,&f_Stop,model->GetDataData());
// d) enable/show & disable/hide controls
PbTestData->Position = 0; // reset progress bar
PbTestData->Visible = true; // show progress bar
BtTestData ->Enabled = false; // disable 'Load Data'
BtTestDataPause->Enabled = true; // enable 'Pause'
BtTestDataAbort->Enabled = true; // enable 'Abort'
LoadDataTimer ->OnTimer = &OnLoadTestDataTimer; // set OnTimer function
LoadDataTimer ->Enabled = true; // start progress indication timer
ActiveControl = BtTestDataPause;
EnableMenus(false); // disable menu entries
// set filename note: done here; see note below
LaTestFile->Caption = MinimizeName(OpenDialog->FileName, LaTestFile->Canvas, LaTestFile->Width);
ActTestDataStatus(false);// ... but do not(!) actualize filename cause maybe it's not initialized in TData object yet
}
//----------------------------------------------------------------------------------------------------------------------
// Called by 'LoadData' thread object on termination: Disable/enable controls and display number of tuples and variables
// callback wrapper function
void CallLoadTestDataFinish(const bool& f_Error){
FMain->OnLoadTestDataFinish(f_Error);}
void TFMain::OnLoadTestDataFinish(const bool& f_Error)
{
// a) enable/disable controls
f_Loading = false; // reset flag
LoadDataTimer ->Enabled = false; // disable progress indication timer
BtTestDataPause ->Enabled = false; // disable button 'Pause'
BtTestDataAbort ->Enabled = false; // disable button 'Abort'
BtTestData ->Enabled = true; // enable button 'Load'
PbTestData ->Visible = false; // hide progress bar
EnableMenus(true); // enable menu entries
// b) if an error occured while loading -> release data object and return
if(f_Error)
{
ActionList(ClearTestData);
ActiveControl = BtTestData; // set focus back to 'Load' button
return; // and return
}
// c)
prj.SetData2(data_T); // set data filename in project
f_IsWithOutput = LoadDataThread->IsWithOutput(); // move flag in project and check in WriteThroughOutCol()
// d) enable/show controls and set focus to 'Test' button
if(!f_IsWithOutput)
CbWritePredictions->Checked = true; // ensure that it is checked if no output is present
EnableTestDataCtrls(true);
// e) display # variables and tuples
ActTestDataStatus();
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Pause' on tab sheet 'Use Model' group box 'Test Data' clicked: Pause loading of test data file
void __fastcall TFMain::BtTestDataPauseClick(TObject *Sender)
{
BtTestDataPause->Visible = false; // hide 'Pause' button
BtTestDataPause->Refresh();
LoadDataThread->Suspended = true; // suspend thread
LoadDataTimer->Enabled = false; // stop progress indication timer
BtTestDataContinue->Visible = true; // show 'Continue' button
BtTestDataContinue->Refresh();
ActiveControl = BtTestDataContinue;
LaTestDataStatus->Caption = "Paused"; // display status
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Continue' on tab sheet 'Use Model' group box 'Test Data' clicked: Continue loading of test data file
void __fastcall TFMain::BtTestDataContinueClick(TObject *Sender)
{
BtTestDataContinue->Visible = false; // hide 'Continue' button
BtTestDataContinue->Refresh();
LoadDataThread->Suspended = false; // continue thread
LoadDataTimer->Enabled = true; // enable progress indication timer again
BtTestDataPause->Visible = true; // show 'Pause' button
BtTestDataPause->Refresh();
ActiveControl = BtTestDataPause;
LaTestDataStatus->Caption = AnsiString(data_L->StatusText()); // display status
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Abort' on tab sheet 'Use Model' group box 'Test Data' clicked: Ask user and abort loading of test data
// file
void __fastcall TFMain::BtTestDataAbortClick(TObject *Sender)
{
// a) suspend thread note: necessary cause otherwise the code in c) could cause an exception
BtTestDataPauseClick(this);
// b) ask user if he really wants to abort
if(f_DisableQuestions || Application->MessageBox("I'm loading the test data file! Do you really want to abort ??"
, "Question", MB_YESNO | MB_ICONQUESTION)== ID_YES)
// c) abort
{
BtTestDataContinue->Visible = false; // hide button 'Continue'
f_Stop = true; // set stop flag, this will cause thread to terminate
}
BtTestDataContinueClick(this); // continue thread
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Set Output' on tab sheet 'Use Model' group box 'Simulation' clicked: Ask the user for the
// simulation output file
void __fastcall TFMain::BtTestOutputClick(TObject *Sender)
{
// a) set dialog caption and options and execute it
SaveDialog->Title = "Set simulation output file ...";
SaveDialog->Options << ofPathMustExist << ofOverwritePrompt << ofNoReadOnlyReturn;
SaveDialog->DefaultExt = SIM_FILE_EXTENSION;
SaveDialog->Filter = "Simulation output file (*." + AnsiString(SIM_FILE_EXTENSION) + ")|*."
+ AnsiString(SIM_FILE_EXTENSION);
SaveDialog->FileName = szSimOutputFile;
if(!SaveDialog->Execute())
szSimOutputFile = ""; // clear output file if closed with 'Cancel' button
else
szSimOutputFile = SaveDialog->FileName; // else copy selected filename
SetSavedFlag(false); // project not saved anymore
// b) enable/disable check box 'Write Predictions' and button 'Test'
EnableTestDataCtrls(true);
// c) call evaluate function
ActTestStatus();
// note: simulation output filename in project is set just before saving
}
//----------------------------------------------------------------------------------------------------------------------
// update (learn and) test parameter object, i.e. initialize from model and perform modifications
void TFMain::UpdatePara()
{
para = *(model->GetParameters()); // initialize from model parameters
if(prj.Modify1()) // if alternate settings should be used ...
{
para.p_min = prj.p_min(); // ... overwrite with settings from project
para.W_Kernel = prj.W_Kernel();
para.Sigma = prj.Sigma();
para.Prune = prj.Prune();
}
if(prj.Modify2()) // if alternate settings should be used ...
{
para.Weights = prj.UseWeights(); // ... overwrite with settings from project
para.Metric = 1;
if(prj.Euclid()) // map from flag to 1 (city block distance) or 2 (euclidean distance)
para.Metric = 2;
}
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Test' on tab sheet 'Use Model' group box 'Status' clicked: Start simulation
void __fastcall TFMain::BtTestClick(TObject *Sender)
{
// a) initialize simulation output file (ofstream)
ofstream* file = NULL;
if(!szSimOutputFile.IsEmpty()) // if filename specified
{
file = new ofstream(szSimOutputFile.c_str()); // create file ... (will be deleted in thread object)
if(!file) // ... and check success
{
Application->MessageBox("Unable to open simulation output file!", "Error", MB_OK | MB_ICONERROR);
return; // abort if failed
}
}
// b) set flags
f_Testing = true;
f_Stop = false;
// c) create loss object
// note: pass # tuples to loss object if preditions shall be stored (and later written to output file)
int nTup=-1;
if(CbWritePredictions->Checked)
nTup = data_T->nTup();
// new loss object note: gets deleted in finish function
loss = new TLossFunction(model->GetDataData()->MeanY(), nTup);
testStartTime = clock(); // get start time
testTime = 0;
// d) update test parameters
UpdatePara();
// e) create thread object: will call TPrediction::Test() in its Execute() function
UseModelThread = new ThrUseModel(false, this, data_T, f_IsWithOutput, loss, model, ¶, file);
// f) enable/show and disable/hide controls
LaTestTime ->Caption = "0m00s"; // reset
TFontStyles style = LaTestStatus->Font->Style; // get control's font style
style >> fsBold; // unset bold style
LaTestStatus->Font->Color = clBlack; // set normal color
LaTestStatus->Font->Style = style; // set style
LaTestStatus->Caption = "Testing"; // display status
PbTestModel->Position = 0; // reset progress bar position
PbTestModel->Visible = true; // show progress bar
BtTest ->Visible = false; // hide 'Test' Button (will show 'Abort' button below)
BtTestAbort->Enabled = true;
BtTestPause->Enabled = true; // enable 'Pause' Button
TestTimer ->Enabled = true; // start progress indication timer
ActiveControl = BtTestPause;
EnableMenus(false); // disable menu entries
ActionList(ClearResults); // clear displayed results
GbTestPara1->Enabled = false; // disable group boxes while testing
GbTestPara2->Enabled = false;
GbTestData ->Enabled = false;
}
//----------------------------------------------------------------------------------------------------------------------
// Called by 'ThrUseModel' thread object on termination: Diable/enable controls and display loss results
void TFMain::OnDeployFinish()
{
// a) alter control states
f_Testing = false; // reset
TestTimer ->Enabled = false; // disable progress indication timer
BtTestPause ->Enabled = false; // disable button 'Pause'
BtTestAbort ->Enabled = false; // disable button 'Abort'
BtTest ->Visible = true; // show 'Test' button
PbTestModel ->Position = 0; // reset progress bar
PbTestModel ->Visible = false; // hide progress bar
EnableMenus(true); // enable menu entries
GbTestPara1->Enabled = true; // enable group boxes again
GbTestPara2->Enabled = true;
GbTestData ->Enabled = true;
// display status
TFontStyles style = LaTestStatus->Font->Style; // get control's font style
if(f_Stop)
{
style << fsBold; // set bold style
LaTestStatus->Font->Color = clRed; // set highlighted color
LaTestStatus->Caption = "Aborted";
}
else
LaTestStatus->Caption = "Finished";
LaTestStatus->Font->Style = style; // set style
// display warning if module is empty
if(model->nCuboidsRed()==0 && !f_DisableWarnings)
Application->MessageBox(szModuleIsEmpty, "Warning", MB_OK | MB_ICONWARNING);
// b) display loss function results
if(f_IsWithOutput) // if test data is with output ...
{
ActLossFunctionResults(); // ... then display loss function results and additionally ...
if(!model->GetParameters()->f_Regression) // ... display a pie chart for classification problems
{
MceChart->Visible = true; // show chart
Series2->Clear(); // clear chart data
Series2->Add(100*loss->Mce(), AnsiString(loss->Mce()), clRed); // set pies
Series2->Add(100-(100*loss->Mce()), AnsiString(loss->Mce()), clGreen);
}
}
// c) ratio of inside predictions and # cuboids
LaInsideRatio->Caption = WritePercentage(loss->InsideRatio(), 0, 1, true);
LaTestCuboids->Caption = model->nCuboidsRed();
// d) clean up and set focus to 'Test' button (again)
delete loss;
loss = NULL;
ActiveControl = BtTest;
}
//----------------------------------------------------------------------------------------------------------------------
// display actual loss function results on tab sheet 'Use'
void TFMain::ActLossFunctionResults()
{
const bool f_Classification = !model->GetParameters()->f_Regression; // flag: classification task
if(f_Classification)
// a) classification: show mean classification error (Mce)
{
LaOverallLoss1->Caption = WritePercentage(loss->Mce(), 6, PREC_LOSS_PERCENTAGE, true); // overall
LaInsideLoss1 ->Caption = WritePercentage(loss->MceIns(), 6, PREC_LOSS_PERCENTAGE, true); // inside
LaOutsideLoss1->Caption = WritePercentage(loss->MceOut(), 6, PREC_LOSS_PERCENTAGE, true); // outside
}
else
// b) regression: show mean absolute and mean square error (Mae and Mse)
{
LaOverallLoss1->Caption = ValueToText1(loss->Mae(), 0, PREC_LOSS, true); // Mae overall
LaInsideLoss1 ->Caption = ValueToText1(loss->MaeIns(), 0, PREC_LOSS, true); // inside
LaOutsideLoss1->Caption = ValueToText1(loss->MaeOut(), 0, PREC_LOSS, true); // outside
LaOverallLoss2->Caption = ValueToText1(loss->Mse(), 0, PREC_LOSS, true); // Mse overall
LaInsideLoss2 ->Caption = ValueToText1(loss->MseIns(), 0, PREC_LOSS, true); // inside
LaOutsideLoss2->Caption = ValueToText1(loss->MseOut(), 0, PREC_LOSS, true); // outside
}
// c) ratio of inside predictions note: partly redundant. Added here as this function gets called
// by an Ontimer event handler while testing is done ...
LaInsideRatio->Caption = WritePercentage(loss->InsideRatio(), 0, 1, true);
// d) # cuboids note: if the model size is zero, then display it highlighted as warning
if(model->nCuboidsRed()==0)
SetLabelFontStyleAndColor(LaTestCuboids, true, clHighlight);
else
SetLabelFontStyleAndColor(LaTestCuboids, false, clWindowText);
LaTestCuboids->Caption = model->nCuboidsRed();
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Pause' on tab sheet 'Use Model' group box 'Simulation' clicked: Resume simulation
void __fastcall TFMain::BtTestPauseClick(TObject *Sender)
{
BtTestPause ->Visible = false; // hide 'Pause' button
BtTestPause ->Refresh();
UseModelThread ->Suspended = true; // suspend thread
TestTimer ->Enabled = false; // stop progress indication timer
BtTestContinue->Visible = true; // show 'Continue' button
BtTestContinue->Refresh();
ActiveControl = BtTestContinue;
LaTestStatus ->Caption = "Paused"; // display status
testTime += clock()-testStartTime; // sum up time consumed so far
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Continue' on tab sheet 'Use Model' group box 'Simulation' clicked: Resume simulation
void __fastcall TFMain::BtTestContinueClick(TObject *Sender)
{
BtTestContinue->Visible = false; // hide 'Continue' button
BtTestContinue->Refresh();
UseModelThread->Suspended = false; // continue thread
TestTimer ->Enabled = true; // enable progress indication timer again
BtTestPause ->Visible = true; // show 'Pause' button
BtTestPause ->Refresh();
ActiveControl = BtTestPause;
LaTestStatus ->Caption = "Testing"; // display status
testStartTime = clock(); // get new start time
}
//----------------------------------------------------------------------------------------------------------------------
// Button 'Abort' on tab sheet 'Use Model' group box 'Simulation' clicked: Ask user and abort simulation
void __fastcall TFMain::BtTestAbortClick(TObject *Sender)
{
// a) suspend thread note: necessary cause otherwise the code in c) could cause an exception
BtTestPauseClick(this);
// b) ask user if he really wants to abort
if(f_DisableQuestions || Application->MessageBox("I'm tesing! Do you really want to abort ??", "Question",
MB_YESNO|MB_ICONQUESTION)== ID_YES)
{
// c) abort
BtTestContinue->Visible = false; // hide button 'Continue'
f_Stop = true; // set stop flag, this will cause thread to terminate
}
BtTestContinueClick(this); // continue thread
}
//----------------------------------------------------------------------------------------------------------------------
// actualize status in group box 'Simulation' in tab sheet 'Use Model'
void TFMain::ActTestStatus()
{
const bool f_File = !szSimOutputFile.IsEmpty(); // check if filename is given
// display simulation output filename if it's specified
if(f_File)
{
LaSimulationFile->Visible = true;
LaSimulationFileHeader->Caption = "File";
LaSimulationFile->Caption = MinimizeName(szSimOutputFile, LaSimulationFile->Canvas, LaSimulationFile->Width); // set filename
}
else
{
// show hint that no simulation output file is specified
LaSimulationFile->Visible = false;
LaSimulationFileHeader->Caption = "Hit button to set output file!";
}
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Use Model' group box '... Parameters': functions which get called if one of the edit fields (TEdit)
// exits, i.e. looses focus -> parse and check entered text using CheckParameterString() and update corresponding learn
// parameter
// note: the commands are always the same: a) buffer text, b) select text in edit control, c) check parameter string
// and in case of an error give the focus back to edit control and write back buffered text. Or set new value if
// all's ok.
void __fastcall TFMain::ETestCardinalityExit(TObject *Sender)
{
AnsiString tmp = ETestCardinality->Text; // buffer text
ETestCardinality->SelectAll();
if(CheckParameterString(true, tmp, LaTestCardinality->Caption, DEF_P_MIN, MIN_P_MIN, INT_P_MIN)) // check text
{
ActiveControl = ETestCardinality; // error? -> give focus back
ETestCardinality->Text = tmp; // write back
}
else
{
prj.p_min() = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::ETestSpecialExit(TObject *Sender)
{
AnsiString tmp = ETestSpecial->Text; // buffer text
ETestSpecial->SelectAll();
if(CheckParameterString(true, tmp, LaTestSpecial->Caption, DEF_W_KERNEL, MIN_W_KERNEL, INT_W_KERNEL, MAX_W_KERNEL))
{
ActiveControl = ETestSpecial; // error? -> give focus back
ETestSpecial->Text = tmp; // write back
}
else
{
prj.W_Kernel() = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
void __fastcall TFMain::ETestSigmaExit(TObject *Sender)
{
AnsiString tmp = ETestSigma->Text; // buffer text
ETestSigma->SelectAll();
if(CheckParameterString(true, tmp, LaTestSigma->Caption, DEF_SIGMA, MIN_SIGMA, INT_SIGMA, MAX_SIGMA))
{
ActiveControl = ETestSigma; // error? -> give focus back
ETestSigma->Text = tmp; // write back
}
else
{
prj.Sigma() = atof(tmp.c_str()); // set new value
SetSavedFlag(false); // project not saved anymore
}
}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Use Model' group box '.. Parameters': One of the check boxes clicked -> update corresponding parameter
void __fastcall TFMain::CbTestPruneClick(TObject*){ prj.Prune()=CbTestPrune->Checked; SetSavedFlag(false);}
void __fastcall TFMain::CbTestWeightsClick(TObject*){ prj.UseWeights()=CbTestWeights->Checked; SetSavedFlag(false);}
void __fastcall TFMain::CbTestEuclideanClick(TObject*){ prj.Euclid()=CbTestEuclidean->Checked; SetSavedFlag(false);}
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Use Model' group box '... Parameters': User hits enter -> forward to exit functions
void __fastcall TFMain::ETestCardinalityKeyDown(TObject*, WORD& Key, TShiftState){
if(Key==VK_RETURN)
ETestCardinalityExit(this); }
void __fastcall TFMain::ETestSpecialKeyDown(TObject*, WORD& Key, TShiftState){
if(Key==VK_RETURN)
ETestSpecialExit(this); }
void __fastcall TFMain::ETestSigmaKeyDown(TObject*, WORD& Key, TShiftState){
if(Key==VK_RETURN)
ETestSigmaExit(this); }
//----------------------------------------------------------------------------------------------------------------------
// tab sheet 'Use Model' group box '.. Parameters': One of the edit fields/check boxes was clicked -> highlight text
void __fastcall TFMain::ETestCardinalityClick(TObject*) { ETestCardinality->SelectAll(); }
void __fastcall TFMain::ETestSpecialClick (TObject*) { ETestSpecial ->SelectAll(); }
void __fastcall TFMain::ETestSigmaClick (TObject*) { ETestSigma ->SelectAll(); }
//----------------------------------------------------------------------------------------------------------------------
// set saved flag and enable save project menu item and toolbar button if learn data is present
void TFMain::SetSavedFlag(const bool& f_Set)
{
f_Saved = f_Set; // set flag
MnSaveProject->Enabled = !f_Saved && data_L; // enable/disable menu and tool bar button
TbSaveProject->Enabled = !f_Saved && data_L;
}
//----------------------------------------------------------------------------------------------------------------------
// response to check box 'Write Predictions' on tab sheet 'Use Model'
void __fastcall TFMain::CbWritePredictionsClick(TObject *Sender)
{
prj.WritePredictions() = CbWritePredictions->Checked;
SetSavedFlag(false);
}
//----------------------------------------------------------------------------------------------------------------------
// change background in listview on tab sheet 'Tuning Results' to warn the user not to chose "bad" parameter sets
void __fastcall TFMain::LvTuneResultsCustomDrawSubItem(TCustomListView *Sender, TListItem *Item, int SubItem,
TCustomDrawState State, bool &DefaultDraw)
{
// initialize with default (white background)
// note: there seems to be a bug in the component if one uses real white!
Sender->Canvas->Brush->Color=TColor(RGB(254, 254, 254));
// change background of some columns/parameters/characteristics if some thresholds are exceeded ...
float nCub, nCubRed, fac, nVarPerCub, size;
switch(SubItem)
{
// a) parameter 'Weights': set to light yellow if disabled
case 6 : if(strcmp("false", Item->SubItems->Strings[SubItem-1].c_str())==0) // check if it is disabled and ...
Sender->Canvas->Brush->Color=TColor(RGB(255, 255, 125)); // ... set color to yellow if it is
break;
// b) parameter 'Prune': set to light red if pruning is disabled
case 7 : if(strcmp("false", Item->SubItems->Strings[SubItem-1].c_str())==0) // check if it is disabled and ...
Sender->Canvas->Brush->Color=TColor(RGB(255, 125,125)); // ... set color to red if it is
break;
// c) # cuboids: Check if minimum compression rate approaches threshold
case 9 : nCub = atof(Item->SubItems->Strings[SubItem-1].c_str()); // # cubooids
fac = (nCub/prj.Get_N_L_Tune()-prj.GetMinCompression()/200.0) // warn if actual value exceeds
/(prj.GetMinCompression()/100.0); // half of the threshold
fac = 1-max((float) 0.0, min(fac, (float) 1.0)); // bound to [0,1] and "invert"
Sender->Canvas->Brush->Color=TColor(RGB(255, 255,fac*125+124)); // set color
break;
// d) # cubooids (reduced): Check if model size approaches threshold
case 10: nCubRed = atof(Item->SubItems->Strings[SubItem-1].c_str()); // # cuboids reduced
nVarPerCub = atof(Item->SubItems->Strings[SubItem].c_str()); // avr. # variables per cuboid
size = 2*nCubRed*nVarPerCub/(data_L->nVar()-1)/prj.Get_N_L_Tune(); // model size in percent
fac = (size-prj.GetMaxSize()/200.0)/(prj.GetMaxSize()/100.0); // warn if actual value exceeds
// half of the threshold
fac = 1-max((float) 0.0, min(fac, (float) 1.0)); // bound to [0,1] and "invert"
Sender->Canvas->Brush->Color=TColor(RGB(255, 255,fac*125+124));
break;
}
}