28 HMM::HMM(
const UINT hmmType,
const UINT modelType,
const UINT delta,
const bool useScaling,
const bool useNullRejection)
31 this->modelType = modelType;
33 this->useScaling = useScaling;
34 this->useNullRejection = useNullRejection;
46 autoEstimateSigma =
true;
48 supportsNullRejection =
false;
49 classifierMode = TIMESERIES_CLASSIFIER_MODE;
51 classifierType = classType;
52 debugLog.setProceedingText(
"[DEBUG HMM]");
53 errorLog.setProceedingText(
"[ERROR HMM]");
54 warningLog.setProceedingText(
"[WARNING HMM]");
58 classifierMode = TIMESERIES_CLASSIFIER_MODE;
60 classifierType = classType;
61 debugLog.setProceedingText(
"[DEBUG HMM]");
62 errorLog.setProceedingText(
"[ERROR HMM]");
63 warningLog.setProceedingText(
"[WARNING HMM]");
74 this->modelType = rhs.modelType;
75 this->delta = rhs.delta;
76 this->numStates = rhs.numStates;
77 this->numSymbols = rhs.numSymbols;
78 this->downsampleFactor = rhs.downsampleFactor;
79 this->committeeSize = rhs.committeeSize;
80 this->sigma = rhs.sigma;
81 this->autoEstimateSigma = rhs.autoEstimateSigma;
82 this->discreteModels = rhs.discreteModels;
83 this->continuousModels = rhs.continuousModels;
93 if( classifier == NULL )
return false;
98 HMM *ptr = (
HMM*)classifier;
102 this->modelType = ptr->modelType;
103 this->delta = ptr->delta;
104 this->numStates = ptr->numStates;
105 this->numSymbols = ptr->numSymbols;
106 this->downsampleFactor = ptr->downsampleFactor;
107 this->committeeSize = ptr->committeeSize;
108 this->sigma = ptr->sigma;
109 this->autoEstimateSigma = ptr->autoEstimateSigma;
110 this->discreteModels = ptr->discreteModels;
111 this->continuousModels = ptr->continuousModels;
120 errorLog <<
"train(ClassificationData trainingData) - The HMM classifier should be trained using the train(TimeSeriesClassificationData &trainingData) method" << std::endl;
129 return train_discrete( trainingData );
132 return train_continuous( trainingData );
136 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Failed to train model, unknown HMM type!" << std::endl;
146 errorLog <<
"train_discrete(TimeSeriesClassificationData &trainingData) - There are no training samples to train the HMM classifer!" << std::endl;
151 errorLog <<
"train_discrete(TimeSeriesClassificationData &trainingData) - The number of dimensions in the training data must be 1. If your training data is not 1 dimensional then you must quantize the training data using one of the GRT quantization algorithms" << std::endl;
158 discreteModels.
resize( numClasses );
159 classLabels.
resize( numClasses );
162 for(UINT k=0; k<numClasses; k++){
163 discreteModels[k].resetModel(numStates,numSymbols,modelType,delta);
164 discreteModels[k].setMaxNumEpochs( maxNumEpochs );
165 discreteModels[k].setMinChange( minChange );
169 for(UINT k=0; k<numClasses; k++){
172 classLabels[k] = classID;
177 if( !convertDataToObservationSequence( classData, observationSequences ) ){
182 if( !discreteModels[k].
train( observationSequences ) ){
183 errorLog <<
"train_discrete(TimeSeriesClassificationData &trainingData) - Failed to train HMM for class " << classID << std::endl;
189 nullRejectionThresholds.
resize(numClasses);
191 for(UINT k=0; k<numClasses; k++){
194 classLabels[k] = classID;
199 if( !convertDataToObservationSequence( classData, observationSequences ) ){
204 Float loglikelihood = 0;
205 Float avgLoglikelihood = 0;
206 for(UINT i=0; i<observationSequences.size(); i++){
207 loglikelihood = discreteModels[k].predict( observationSequences[i] );
208 avgLoglikelihood += fabs( loglikelihood );
210 nullRejectionThresholds[k] = -( avgLoglikelihood / Float( observationSequences.size() ) );
225 errorLog <<
"train_continuous(TimeSeriesClassificationData &trainingData) - There are no training samples to train the CHMM classifer!" << std::endl;
232 classLabels.
resize( numClasses );
233 for(UINT k=0; k<numClasses; k++){
240 trainingData.
scale(0, 1);
244 const UINT numTrainingSamples = trainingData.
getNumSamples();
245 continuousModels.
resize( numTrainingSamples );
248 for(UINT k=0; k<numTrainingSamples; k++){
251 continuousModels[k].setDownsampleFactor( downsampleFactor );
252 continuousModels[k].setModelType( modelType );
253 continuousModels[k].setDelta( delta );
254 continuousModels[k].setSigma( sigma );
255 continuousModels[k].setAutoEstimateSigma( autoEstimateSigma );
256 continuousModels[k].enableScaling(
false );
259 if( !continuousModels[k].
train_( trainingData[k] ) ){
260 errorLog <<
"train_continuous(TimeSeriesClassificationData &trainingData) - Failed to train CHMM for sample " << k << std::endl;
267 warningLog <<
"train_continuous(TimeSeriesClassificationData &trainingData) - The committeeSize is larger than the number of training sample. Setting committeeSize to number of training samples: " << trainingData.
getNumSamples() << std::endl;
274 if( useNullRejection ){
276 nullRejectionThresholds.
resize(numClasses);
286 return predict_discrete( inputVector );
289 return predict_continuous( inputVector );
293 errorLog <<
"predict_(VectorFloat &inputVector) - Failed to predict, unknown HMM type!" << std::endl;
298 bool HMM::predict_discrete(
VectorFloat &inputVector ){
300 predictedClassLabel = 0;
301 maxLikelihood = -10000;
304 errorLog <<
"predict_(VectorFloat &inputVector) - The HMM classifier has not been trained!" << std::endl;
308 if( inputVector.size() != numInputDimensions ){
309 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
313 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
314 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
317 bestDistance = -99e+99;
319 UINT newObservation = (UINT)inputVector[0];
321 if( newObservation >= numSymbols ){
322 errorLog <<
"predict_(VectorFloat &inputVector) - The new observation is not a valid symbol! It should be in the range [0 numSymbols-1]" << std::endl;
326 for(UINT k=0; k<numClasses; k++){
327 classDistances[k] = discreteModels[k].predict( newObservation );
330 classLikelihoods[k] = grt_antilog( classDistances[k] );
333 if( classDistances[k] > bestDistance ){
334 bestDistance = classDistances[k];
338 sum += classLikelihoods[k];
342 for(UINT k=0; k<numClasses; k++){
343 classLikelihoods[k] /= sum;
346 maxLikelihood = classLikelihoods[ bestIndex ];
347 predictedClassLabel = classLabels[ bestIndex ];
349 if( useNullRejection ){
350 if( maxLikelihood > nullRejectionThresholds[ bestIndex ] ){
351 predictedClassLabel = classLabels[ bestIndex ];
352 }
else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
358 bool HMM::predict_continuous(
VectorFloat &inputVector ){
361 errorLog <<
"predict_(VectorFloat &inputVector) - The HMM classifier has not been trained!" << std::endl;
365 if( inputVector.size() != numInputDimensions ){
366 errorLog <<
"predict_(VectorFloat &inputVector) - The size of the input vector (" << inputVector.size() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
372 for(UINT i=0; i<numInputDimensions; i++){
373 inputVector[i] =
scale(inputVector[i], ranges[i].minValue, ranges[i].maxValue, 0, 1);
377 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
378 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
380 std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
381 std::fill(classDistances.begin(),classDistances.end(),0);
383 bestDistance = -1000;
385 Float minValue = -1000;
387 const UINT numModels = (UINT)continuousModels.size();
389 for(UINT i=0; i<numModels; i++){
392 if( continuousModels[i].
predict_( inputVector ) ){
393 results[i].value = continuousModels[i].getLoglikelihood();
394 results[i].index = continuousModels[i].getClassLabel();
396 errorLog <<
"predict_(VectorFloat &inputVector) - Prediction failed for model: " << i << std::endl;
400 if( results[i].value < minValue ){
401 if( !grt_isnan(results[i].value) ){
402 minValue = results[i].value;
406 if( results[i].value > bestDistance ){
407 if( !grt_isnan(results[i].value) ){
408 bestDistance = results[i].value;
417 phase = continuousModels[ bestIndex ].getPhase();
420 std::sort(results.begin(),results.end(),IndexedDouble::sortIndexedDoubleByValueDescending);
423 const Float committeeWeight = 1.0 / committeeSize;
424 for(UINT i=0; i<committeeSize; i++){
431 for(UINT k=0; k<numClasses; k++){
432 classLikelihoods[k] = classDistances[k] / sum;
436 for(UINT k=0; k<numClasses; k++){
437 if( classDistances[k] > bestDistance ){
438 bestDistance = classDistances[k];
443 maxLikelihood = classLikelihoods[ bestIndex ];
444 predictedClassLabel = classLabels[ bestIndex ];
448 predictedClassLabel = 0;
458 return predict_discrete( timeseries );
461 return predict_continuous( timeseries );
465 errorLog <<
"predict_(MatrixFloat ×eries) - Failed to predict, unknown HMM type!" << std::endl;
471 bool HMM::predict_discrete(
MatrixFloat ×eries){
474 errorLog <<
"predict_continuous(MatrixFloat ×eries) - The HMM classifier has not been trained!" << std::endl;
479 errorLog <<
"predict_discrete(MatrixFloat ×eries) The number of columns in the input matrix must be 1. It is: " << timeseries.
getNumCols() << std::endl;
487 for(UINT i=0; i<M; i++){
488 observationSequence[i] = (UINT)timeseries[i][0];
490 if( observationSequence[i] >= numSymbols ){
491 errorLog <<
"predict_discrete(VectorFloat &inputVector) - The new observation is not a valid symbol! It should be in the range [0 numSymbols-1]" << std::endl;
496 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
497 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
499 bestDistance = -99e+99;
502 for(UINT k=0; k<numClasses; k++){
503 classDistances[k] = discreteModels[k].predict( observationSequence );
506 classLikelihoods[k] = grt_antilog( classDistances[k] );
509 if( classDistances[k] > bestDistance ){
510 bestDistance = classDistances[k];
514 sum += classLikelihoods[k];
518 for(UINT k=0; k<numClasses; k++){
519 classLikelihoods[k] /= sum;
522 maxLikelihood = classLikelihoods[ bestIndex ];
523 predictedClassLabel = classLabels[ bestIndex ];
525 if( useNullRejection ){
526 if( maxLikelihood > nullRejectionThresholds[ bestIndex ] ){
527 predictedClassLabel = classLabels[ bestIndex ];
528 }
else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
535 bool HMM::predict_continuous(
MatrixFloat ×eries){
538 errorLog <<
"predict_continuous(MatrixFloat ×eries) - The HMM classifier has not been trained!" << std::endl;
542 if( timeseries.
getNumCols() != numInputDimensions ){
543 errorLog <<
"predict_continuous(MatrixFloat ×eries) - The number of columns in the input matrix (" << timeseries.
getNumCols() <<
") does not match the num features in the model (" << numInputDimensions << std::endl;
549 const UINT timeseriesLength = timeseries.
getNumRows();
550 for(UINT j=0; j<numInputDimensions; j++){
551 for(UINT i=0; i<timeseriesLength; i++){
552 timeseries[i][j] =
scale(timeseries[i][j], ranges[j].minValue, ranges[j].maxValue, 0, 1);
557 if( classLikelihoods.size() != numClasses ) classLikelihoods.
resize(numClasses,0);
558 if( classDistances.size() != numClasses ) classDistances.
resize(numClasses,0);
560 std::fill(classLikelihoods.begin(),classLikelihoods.end(),0);
561 std::fill(classDistances.begin(),classDistances.end(),0);
563 bestDistance = -1000;
565 Float minValue = -1000;
567 const UINT numModels = (UINT)continuousModels.size();
569 for(UINT i=0; i<numModels; i++){
572 if( continuousModels[i].
predict_( timeseries ) ){
573 results[i].value = continuousModels[i].getLoglikelihood();
574 results[i].index = continuousModels[i].getClassLabel();
576 errorLog <<
"predict_(VectorFloat &inputVector) - Prediction failed for model: " << i << std::endl;
580 if( results[i].value < minValue ){
581 minValue = results[i].value;
584 if( results[i].value > bestDistance ){
585 bestDistance = results[i].value;
591 phase = continuousModels[ bestIndex ].getPhase();
594 std::sort(results.begin(),results.end(),IndexedDouble::sortIndexedDoubleByValueDescending);
597 const Float committeeWeight = 1.0 / committeeSize;
598 for(UINT i=0; i<committeeSize; i++){
605 for(UINT k=0; k<numClasses; k++){
606 classLikelihoods[k] = classDistances[k] / sum;
610 for(UINT k=0; k<numClasses; k++){
611 if( classDistances[k] > bestDistance ){
612 bestDistance = classDistances[k];
617 maxLikelihood = classLikelihoods[ bestIndex ];
618 predictedClassLabel = classLabels[ bestIndex ];
622 predictedClassLabel = 0;
634 for(
size_t i=0; i<discreteModels.size(); i++){
635 discreteModels[i].reset();
639 for(
size_t i=0; i<continuousModels.size(); i++){
640 continuousModels[i].reset();
653 discreteModels.clear();
654 continuousModels.clear();
661 std::cout <<
"HMM Model\n";
664 std::cout <<
"HmmType: " <<
hmmType << std::endl;
665 std::cout <<
"ModelType: " << modelType << std::endl;
666 std::cout <<
"Delta: " << delta << std::endl;
671 std::cout <<
"NumStates: " << numStates << std::endl;
672 std::cout <<
"NumSymbols: " << numSymbols << std::endl;
673 std::cout <<
"NumRandomTrainingIterations: " << numRandomTrainingIterations << std::endl;
674 std::cout <<
"NumDiscreteModels: " << discreteModels.size() << std::endl;
675 std::cout <<
"DiscreteModels: " << std::endl;
676 for(
size_t i=0; i<discreteModels.size(); i++){
677 if( !discreteModels[i].
print() ){
678 errorLog <<
"saveModelToFile(fstream &file) - Failed to print discrete model " << i <<
" to file!" << std::endl;
684 std::cout <<
"DownsampleFactor: " << downsampleFactor << std::endl;
685 std::cout <<
"CommitteeSize: " << committeeSize << std::endl;
686 std::cout <<
"Sigma: " << sigma << std::endl;
687 std::cout <<
"AutoEstimateSigma: " << autoEstimateSigma << std::endl;
688 std::cout <<
"NumContinuousModels: " << continuousModels.size() << std::endl;
689 std::cout <<
"ContinuousModels: " << std::endl;
690 for(
size_t i=0; i<continuousModels.size(); i++){
691 if( !continuousModels[i].
print() ){
692 errorLog <<
"saveModelToFile(fstream &file) - Failed to print continuous model " << i <<
" to file!" << std::endl;
706 errorLog <<
"saveModelToFile( fstream &file ) - File is not open!" << std::endl;
711 file <<
"HMM_MODEL_FILE_V2.0\n";
715 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
720 file <<
"HmmType: " <<
hmmType << std::endl;
721 file <<
"ModelType: " << modelType << std::endl;
722 file <<
"Delta: " << delta << std::endl;
727 file <<
"NumStates: " << numStates << std::endl;
728 file <<
"NumSymbols: " << numSymbols << std::endl;
729 file <<
"NumRandomTrainingIterations: " << numRandomTrainingIterations << std::endl;
730 file <<
"NumDiscreteModels: " << discreteModels.size() << std::endl;
731 file <<
"DiscreteModels: " << std::endl;
732 for(
size_t i=0; i<discreteModels.size(); i++){
734 errorLog <<
"saveModelToFile(fstream &file) - Failed to save discrete model " << i <<
" to file!" << std::endl;
740 file <<
"DownsampleFactor: " << downsampleFactor << std::endl;
741 file <<
"CommitteeSize: " << committeeSize << std::endl;
742 file <<
"Sigma: " << sigma << std::endl;
743 file <<
"NumContinuousModels: " << continuousModels.size() << std::endl;
744 file <<
"ContinuousModels: " << std::endl;
745 for(
size_t i=0; i<continuousModels.size(); i++){
747 errorLog <<
"saveModelToFile(fstream &file) - Failed to save continuous model " << i <<
" to file!" << std::endl;
763 errorLog <<
"loadModelFromFile( fstream &file ) - File is not open!" << std::endl;
773 if(word !=
"HMM_MODEL_FILE_V2.0"){
774 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find Model File Header!" << std::endl;
780 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << std::endl;
786 if(word !=
"HmmType:"){
787 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find HmmType." << std::endl;
793 if(word !=
"ModelType:"){
794 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find ModelType." << std::endl;
800 if(word !=
"Delta:"){
801 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find Delta." << std::endl;
811 if(word !=
"NumStates:"){
812 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find NumStates." << std::endl;
818 if(word !=
"NumSymbols:"){
819 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find NumSymbols." << std::endl;
825 if(word !=
"NumRandomTrainingIterations:"){
826 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find NumRandomTrainingIterations." << std::endl;
829 file >> numRandomTrainingIterations;
832 if(word !=
"NumDiscreteModels:"){
833 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find NumDiscreteModels." << std::endl;
839 if(word !=
"DiscreteModels:"){
840 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find DiscreteModels." << std::endl;
845 discreteModels.
resize(numModels);
846 for(
size_t i=0; i<discreteModels.size(); i++){
848 errorLog <<
"loadModelFromFile(fstream &file) - Failed to load discrete model " << i <<
" from file!" << std::endl;
857 if(word !=
"DownsampleFactor:"){
858 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find DownsampleFactor." << std::endl;
861 file >> downsampleFactor;
864 if(word !=
"CommitteeSize:"){
865 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find CommitteeSize." << std::endl;
868 file >> committeeSize;
871 if(word !=
"Sigma:"){
872 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find Sigma." << std::endl;
878 if(word !=
"NumContinuousModels:"){
879 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find NumContinuousModels." << std::endl;
885 if(word !=
"ContinuousModels:"){
886 errorLog <<
"loadModelFromFile( fstream &file ) - Could not find ContinuousModels." << std::endl;
891 continuousModels.
resize(numModels);
892 for(
size_t i=0; i<continuousModels.size(); i++){
894 errorLog <<
"loadModelFromFile(fstream &file) - Failed to load continuous model " << i <<
" from file!" << std::endl;
913 for(UINT j=0; j<timeseries.
getNumRows(); j++){
914 if( timeseries[j][0] >= numSymbols ){
915 errorLog <<
"train(TimeSeriesClassificationData &trainingData) - Found an observation sequence with a value outside of the symbol range! Value: " << timeseries[j][0] << std::endl;
918 observationSequences[i][j] = (UINT)timeseries[j][0];
946 return numRandomTrainingIterations;
950 return discreteModels;
954 return continuousModels;
961 if( hmmType == HMM_DISCRETE || hmmType == HMM_CONTINUOUS ){
966 warningLog <<
"setHMMType(const UINT hmmType) - Unknown HMM type!" << std::endl;
974 if( modelType == HMM_ERGODIC || modelType == HMM_LEFTRIGHT ){
975 this->modelType = modelType;
979 warningLog <<
"setModelType(const UINT modelType) - Unknown model type!" << std::endl;
992 warningLog <<
"setDelta(const UINT delta) - Delta must be greater than zero!" << std::endl;
999 if( downsampleFactor > 0 ){
1000 this->downsampleFactor = downsampleFactor;
1008 if( committeeSize > 0 ){
1009 this->committeeSize = committeeSize;
1020 if( numStates > 0 ){
1021 this->numStates = numStates;
1025 warningLog <<
"setNumStates(const UINT numStates) - Num states must be greater than zero!" << std::endl;
1033 if( numSymbols > 0 ){
1034 this->numSymbols = numSymbols;
1038 warningLog <<
"setNumSymbols(const UINT numSymbols) - Num symbols must be greater than zero!" << std::endl;
1046 if( numRandomTrainingIterations > 0 ){
1047 this->numRandomTrainingIterations = numRandomTrainingIterations;
1051 warningLog <<
"setMaxNumIterations(const UINT maxNumIter) - The number of random training iterations must be greater than zero!" << std::endl;
1057 this->sigma = sigma;
1058 for(
size_t i=0; i<continuousModels.size(); i++){
1059 continuousModels[i].setSigma( sigma );
1066 bool HMM::setAutoEstimateSigma(
const bool autoEstimateSigma){
1070 this->autoEstimateSigma = autoEstimateSigma;
virtual bool saveModelToFile(std::fstream &file) const
bool saveBaseSettingsToFile(std::fstream &file) const
virtual bool loadModelFromFile(std::fstream &file)
bool setHMMType(const UINT hmmType)
Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
bool setDownsampleFactor(const UINT downsampleFactor)
static Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
std::string getClassifierType() const
virtual bool predict_(VectorFloat &inputVector)
virtual bool resize(const unsigned int size)
virtual bool deepCopyFrom(const Classifier *classifier)
bool setNumRandomTrainingIterations(const UINT numRandomTrainingIterations)
UINT getClassLabelIndexValue(UINT classLabel) const
bool setNumSymbols(const UINT numStates)
virtual bool train(ClassificationData trainingData)
Vector< DiscreteHiddenMarkovModel > getDiscreteModels() const
Vector< MinMax > getRanges() const
bool setModelType(const UINT modelType)
UINT getModelType() const
virtual bool print() const
Vector< ClassTracker > getClassTracker() const
HMM & operator=(const HMM &rhs)
UINT hmmType
Controls if this is a HMM_DISCRETE or a HMM_CONTINUOUS.
UINT getNumStates() const
bool setSigma(const Float sigma)
virtual bool train_(TimeSeriesClassificationData &trainingData)
HMM(const UINT hmmType=HMM_CONTINUOUS, const UINT modelType=HMM_LEFTRIGHT, const UINT delta=1, const bool useScaling=false, const bool useNullRejection=false)
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
UINT getNumSymbols() const
unsigned int getNumRows() const
unsigned int getNumCols() const
bool setDelta(const UINT delta)
bool setCommitteeSize(const UINT committeeSize)
bool scale(const Float minTarget, const Float maxTarget)
TimeSeriesClassificationData getClassData(const UINT classLabel) const
UINT getNumDimensions() const
This class acts as the main interface for using a Hidden Markov Model.
UINT getNumClasses() const
UINT getNumRandomTrainingIterations() const
bool setNumStates(const UINT numStates)
UINT getNumSamples() const
static Float sum(const VectorFloat &x)
Vector< ContinuousHiddenMarkovModel > getContinuousModels() const