#ifndef _FITTER_H_
#define _FITTER_H_
/*
* Base Class for Numerical Fitters -- Draft 1
*
* To build the documentation, do
* doc++ fitter.h
*
* (C) 1997 Patrick Schemitz
* KOrigin (C) 1997 Patrick Schemitz, Martin Häfner
*
*/
#include <qlist.h>
#include <kconfig.h>
#include "column.h"
class QPopupMenu;
/** Abstract Base Class for Generic Fitters.
This is as generic as possible, just an interface to (hopefully) *any*
kind of fitter.
The basic idea is the following. What do fitter have in common?
They all take input data and create output data, in form of columns of
numbers. This has been taken into account by providing the functions
setInputColumns() and setOutputColumns().
The number of columns they take as input and fill as output, however,
varies, as does the meaning of the columns. In respect to this, the
functions getInputColumnCount(), getOutputColumnCount(),
getInputColumnName(), and getOutputColumnName() have been made
pure virtual: each fitter must implement them for itself.
Every fitter might offer some specific options, which can be queried
in some dialogs as well as stored/retrieved to/from a config file.
to offer this functionality, the pure virtual functions
execOptionsDialog(), saveSettings(), and loadSettings() have been
introducted.
Finally, every fitter must actually *do* something, namely a fit.
Therefore, a pure virtual function, fit() has been declared, and
each fit must implement it.
For an example for a fit, see the @ref LinearRegression fitter.
@see LinearRegression
@author Patrick Schemitz
*/
class Fitter
{
public:
/** Default constructor.
Just initializes some pointers to zero.
*/
Fitter ();
/** Destructor - just to ensure that it is virtual.
Fitters are destroyed by deleting Fitter pointers. Since these
actually point to concrete (derived) fitters which may have their
own destructors, the destructor of the base class must be declared
virtual, even if it doesn't do anything.
*/
virtual ~Fitter ();
/** [pure virtual] Return the concrete fitter's name.
@return the fitters name for the "Fit" menu entry.
*/
virtual const char* name () = 0;
/** Pop up the fitter's options dialog box.
The (derived) concrete fitter must implement it's own Options
dialog, of course. That's why this is pure virtual.
@return Your implementation should just pass on the return code from QDialog::exec()
*/
virtual int execOptionsDialog () = 0;
/** [pure virtual] Returns the number of columns a fitter takes for input.
A linear regression fitter would take two columns, namely x and y,
for input.
@return Number of columns the fitter takes for input.
*/
virtual int getInputColumnCount () = 0;
/** [pure virtual] Returns the number of columns a fitter fills with its
output.
A linear regression fitter would fill one column, y_linear, as output.
Note that the caller has to create those columns! They are _not_
created by the Fitter!
@return Number of columns the fitter fills with output.
*/
virtual int getOutputColumnCount () = 0;
/** [pure virtual] Returns the symbolic name of the ith input column the
fitter takes.
For a linear regression fitter, this would be "X" for i=0 and "Y"
for i=1.
@return Name of the ith input column.
*/
virtual const char* getInputColumnName (int i) = 0;
/** [pure virtual] Returns the symbolic name of the ith output column the
fitter fills.
For a linear regression fitter, this would be "YLinear" for i=0.
@return Name of the ith output column.
*/
virtual const char* getOutputColumnName (int i) = 0;
/** [pure virtual] Defines what columns the fitter should take for input.
The array of columns passed to this function is taken as
input data for the fitter. For an interpretation of the ith
entry of the array, check the description returned by
getInputColumnName().
The caller is responsible for deleting the columns! Not the fit!
@param col_array the array of columns to be taken as input data.
@see #getInputColumnCount()
@see #getInputColumnName(int)
@see #setOutputColumns(DoubleColumn*)
*/
void setInputColumns (Column* col_array);
/** [pure virtual] Defines the columns to be filled by the fitter.
The columns passed to this functions will be taken as output
buffer, i.e. the fitter will fill them with the results of the
fit. A linear regression fitter would fill its single output
column with the fitted y values for the appropriate x (input)
value. However, a non-linear fitter would most likely also
fill a column with its own x values, since the input x values
might be too coarse to make sense with fitted y values. It is
important to understand that the columns in the output buffer
are not necessarily of the same length as the input columns. A
fitter might decide that it needs a finer x stepwidth and create
a grid with dx=0.01 whereas the input columns have dx=0.1. With
self-expanding columns, this is a plug to implement.
In analogy with setInputColumns(), the columns handed to this
function must already exist (though they might be empty). Their
meaning can be obtained by getOutputColumnName().
The caller is responsible for deleting the columns! Not the fit!
@param col_array the array of columns to be filled by the fitter.
@see #getOutputColumnCount()
@see #getOutputColumnName(int)
@see #setInputColumns(DoubleColumn*)
*/
void setOutputColumns (Column* col_array);
/** [pure virtual] The actual fitting function.
This is the core of the fitter. In here, the actual fitting algorithm
is implemented. Or, as a matter of fact, the derived concrete fitter
must implement it here. Please do _not_ do any dialogs here! This
function might get called as a thread of its own later. (Currently,
it blocks the program.)
*/
virtual bool fit () = 0;
/** [pure virtual] Save fitter-specific settings to the configuration file.
If your fitter has some specific settings, your implementation of
this function's got the chance to store them in Korigins config
file. A neuronal net fitter might save the (maximum) number of
nodes; an iterative fitter might save some epsilons.
Of course, the implementation of this function must match
loadSettings().
@param conf pointer to Korigins KConfig instance.
@see #loadSettings()
*/
virtual void saveSettings (KConfig* conf) = 0;
/** [pure virtual] Load fitter-specific settings from the configuration
file.
If your fitter has some specific settings, your implementation of
this function's got the chance to restore them from Korigins config
file. A neuronal net fitter might load the (maximum) number of
nodes; an iterative fitter might retrieve some epsilons.
Of course, the implementation of this function must match
saveSettings().
@param conf pointer to Korigins KConfig instance.
@see #saveSettings()
*/
virtual void loadSettings (KConfig* conf) = 0;
/** Main menu entry for the Fitters.
This function builds the main menu entry "Fit".
@see #getFitterOptionsMenu()
*/
static QPopupMenu* getFitterMenu ();
/** Options menu entry for the Fitters.
This function builds the menu entry "Options|Fitter".
@see #getFitterMenu()
*/
static QPopupMenu* getFitterOptionsMenu ();
protected:
/** Input data for the fitter.
This array, filled by the caller and used by the fitter,
contains the input data for the fit. The implementation of
fit() will read it. Note that it must be deleted by the caller,
not by the destructor.
@see #setInputColumns()
@see #fit()
*/
Column* inputColumns;
/** Output buffer for the fitter.
This array, provided by the caller, is filled during the
fit(). Note that it must be deleted by the caller, not by
the destructor!
@see #setOutputColumns()
@see #fit()
*/
Column* outputColumns;
private:
/** Copy constructor is locked.
Fitters should not be copied, so I've locked away the copy
constructor.
*/
Fitter (const Fitter&);
/** Assignment operator is locked.
Fitters should not be copied, so I've locked away the assignment
operator.
*/
Fitter& operator= (const Fitter&);
};
/** Type for the Fitter list.
This is just a template instatiation of Qt's QList for
a list of Fitters. Intelligent as the QList is, it actually
stores a list of pointers, which is exactly what we want here,
since class Fitter is abstract, so it cannot be instantiated.
@see Fitters()
*/
typedef QList<Fitter> FitterList;
/** The list of all fitters.
The FitterList returned by this function contains a list of all
fitters linked to Korigin. The list is filled by using the
REGISTER_FITTER macro in your concrete fitter module.
The fitter list is implemented in a Singleton pattern, because if I
had it implemented as a global variable, I'ld have run into trouble
with the initialization order of global instances -- which is
undefined in the C++ standard. Actually, I had it implemented this
way initially, but then the order files were linked together was
important. (Took me quite a bit of time to figure out why.)
@see FitterList
@see REGISTER_FITTER
@return list of all fitters.
*/
FitterList& Fitters ();
/** For internal use only!
This is an auxillary class. Needed because Qt only allows to connect
to instances but not to global functions. I had to put this in the
header because I need to run the moc on it. (And a separate header
for one method is ridiculous.)
@author Patrick Schemitz
*/
class FitHelper : public QObject
{
Q_OBJECT
public slots:
/// Slot for the Options||Fitter menu entry.
void execFitterOptions(int i);
};
/** Registers *your* fitter in the fitter list.
Use this macro in the .cc file of your fitter module to register
your new concrete fitter to Korigin. If you forget to do so, your
fitter will not be accessible from Korigin.
Usage:
class MyFitter : public Fitter { ... };
REGISTER_FITTER(MyFitter);
(Don't forget the semicolon after REGISTER_FITTER!)
@see Fitters
@see FitterList
*/
#define REGISTER_FITTER(type) \
\
class Registrator##type { \
public: \
Registrator##type () { \
Fitters().append(new type); \
} \
}; \
\
static Registrator##type _register##type
#endif
Documentation generated by mh@jeff_clever on Thu Feb 5 14:15:25 MET 1998