text: // gmm/mle-am-diag-gmm-test.cc
  
  // Copyright 2009-2012  Arnab Ghoshal
  
  // See ../../COPYING for clarification regarding multiple authors
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //  http://www.apache.org/licenses/LICENSE-2.0
  //
  // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  // MERCHANTABLITY OR NON-INFRINGEMENT.
  // See the Apache 2 License for the specific language governing permissions and
  // limitations under the License.
  
  #include "gmm/model-test-common.h"
  #include "gmm/am-diag-gmm.h"
  #include "gmm/mle-am-diag-gmm.h"
  #include "util/kaldi-io.h"
  
  using kaldi::AmDiagGmm;
  using kaldi::AccumAmDiagGmm;
  using kaldi::int32;
  using kaldi::BaseFloat;
  namespace ut = kaldi::unittest;
  using namespace kaldi;
  
  // Tests the Read() and Write() methods for the accumulators, in both binary
  // and ASCII mode.
  void TestAmDiagGmmAccsIO(const AmDiagGmm &am_gmm,
                           const Matrix<BaseFloat> &feats) {
    kaldi::GmmFlagsType flags = kaldi::kGmmAll;
    AccumAmDiagGmm accs;
    accs.Init(am_gmm, flags);
    BaseFloat loglike = 0.0;
    for (int32 i = 0; i < feats.NumRows(); i++) {
      int32 state = RandInt(0, am_gmm.NumPdfs()-1);
      loglike += accs.AccumulateForGmm(am_gmm, feats.Row(i), state, 1.0);
    }
    KALDI_LOG << "Data log-likelihood = " << loglike << " over "
              << feats.NumRows() << " frames.";
    KALDI_LOG << "Accumulated values: log-like = " << accs.TotLogLike()
              << ", # frames = " << accs.TotCount();
    AssertEqual(accs.TotLogLike(), loglike, 1e-5);
    AssertEqual(accs.TotCount(), static_cast<BaseFloat>(feats.NumRows()), 1e-5);
  
    MleDiagGmmOptions config;
    AmDiagGmm *am_gmm1 = new AmDiagGmm();
    am_gmm1->CopyFromAmDiagGmm(am_gmm);
    MleAmDiagGmmUpdate(config, accs, flags, am_gmm1, NULL, NULL);
  
    int32 check_pdf = RandInt(0, am_gmm.NumPdfs()-1),
        check_frame = RandInt(0, feats.NumRows()-1);
    BaseFloat loglike1 = am_gmm1->LogLikelihood(check_pdf, feats.Row(check_frame));
    delete am_gmm1;
  
    // First, non-binary write
    accs.Write(kaldi::Output("tmpf", false).Stream(), false);
    bool binary_in;
    AccumAmDiagGmm *accs1 = new AccumAmDiagGmm();
    // Non-binary read
    kaldi::Input ki1("tmpf", &binary_in);
    accs1->Read(ki1.Stream(), binary_in, false);
    AmDiagGmm *am_gmm2 = new AmDiagGmm();
    am_gmm2->CopyFromAmDiagGmm(am_gmm);
    MleAmDiagGmmUpdate(config, accs, flags, am_gmm2, NULL, NULL);
    BaseFloat loglike2 = am_gmm2->LogLikelihood(check_pdf, feats.Row(check_frame));
    kaldi::AssertEqual(loglike1, loglike2, 1e-6);
    delete am_gmm2;
    delete accs1;
  
    // Next, binary write
    accs.Write(kaldi::Output("tmpfb", true).Stream(), true);
    AccumAmDiagGmm *accs2 = new AccumAmDiagGmm();
    // Binary read
    kaldi::Input ki2("tmpfb", &binary_in);
    accs2->Read(ki2.Stream(), binary_in, false);
    AmDiagGmm *am_gmm3 = new AmDiagGmm();
    am_gmm3->CopyFromAmDiagGmm(am_gmm);
    MleAmDiagGmmUpdate(config, accs, flags, am_gmm3, NULL, NULL);
    BaseFloat loglike3 = am_gmm3->LogLikelihood(check_pdf, feats.Row(check_frame));
    kaldi::AssertEqual(loglike1, loglike3, 1e-6);
    delete am_gmm3;
    delete accs2;
  
    unlink("tmpf");
    unlink("tmpfb");
  }
  
  void UnitTestMleAmDiagGmm() {
    int32 dim = 1 + kaldi::RandInt(0, 9),  // random dimension of the gmm
        num_pdfs = 5 + kaldi::RandInt(0, 9);  // random number of states
  
    AmDiagGmm am_gmm;
    int32 total_num_comp = 0;
    for (int32 i = 0; i < num_pdfs; i++) {
      int32 num_comp = 1 + kaldi::RandInt(0, 9);  // random mixture size
      kaldi::DiagGmm gmm;
      ut::InitRandDiagGmm(dim, num_comp, &gmm);
      am_gmm.AddPdf(gmm);
      total_num_comp += num_comp;
    }
  
    kaldi::Matrix<BaseFloat> feats;
  
    {  // First, generate random means and variances
      int32 num_feat_comp = total_num_comp + kaldi::RandInt(-total_num_comp/2,
                                                            total_num_comp/2);
      kaldi::Matrix<BaseFloat> means(num_feat_comp, dim),
          vars(num_feat_comp, dim);
      for (int32 m = 0; m < num_feat_comp; m++) {
        for (int32 d= 0; d < dim; d++) {
          means(m, d) = kaldi::RandGauss();
          vars(m, d) = Exp(kaldi::RandGauss()) + 1e-2;
        }
      }
      // Now generate random features with those means and variances.
      feats.Resize(num_feat_comp * 200, dim);
      for (int32 m = 0; m < num_feat_comp; m++) {
        kaldi::SubMatrix<BaseFloat> tmp(feats, m*200, 200, 0, dim);
        ut::RandDiagGaussFeatures(200, means.Row(m), vars.Row(m), &tmp);
      }
    }
    TestAmDiagGmmAccsIO(am_gmm, feats);
  }
  
  
  int main() {
  //  std::srand(time(NULL));
    for (int i = 0; i < 10; i++)
      UnitTestMleAmDiagGmm();
    std::cout << "Test OK.\n";
    return 0;
  }
  