// File: /workspace/github_c_makefile_star2_O3/zpole[P]IICV/vl/gmm.c
// Function: vl_gmm_maximization_f
static void
VL_XCAT(_vl_gmm_maximization_, SFX)
(VlGMM * self,
 TYPE * posteriors,
 TYPE * priors,
 TYPE * covariances,
 TYPE * means,
 TYPE const * data,
 vl_size numData)
{
  vl_size numClusters = self->numClusters;
  vl_index i_d, i_cl;
  vl_size dim ;
  TYPE * oldMeans ;
  double time = 0 ;

  if (self->verbosity > 1) {
    VL_PRINTF("gmm: em: entering maximization step\n") ;
    time = vl_get_cpu_time() ;
  }

  oldMeans = vl_malloc(sizeof(TYPE) * self->dimension * numClusters) ;
  memcpy(oldMeans, means, sizeof(TYPE) * self->dimension * numClusters) ;

  memset(priors, 0, sizeof(TYPE) * numClusters) ;
  memset(means, 0, sizeof(TYPE) * self->dimension * numClusters) ;
  memset(covariances, 0, sizeof(TYPE) * self->dimension * numClusters) ;

#if defined(_OPENMP)
#pragma omp parallel default(shared) private(i_d, i_cl, dim) \
                     num_threads(vl_get_max_threads())
#endif
  {
    TYPE * clusterPosteriorSum_, * means_, * covariances_ ;

#if defined(_OPENMP)
#pragma omp critical
#endif
    {
      clusterPosteriorSum_ = vl_calloc(sizeof(TYPE), numClusters) ;
      means_ = vl_calloc(sizeof(TYPE), self->dimension * numClusters) ;
      covariances_ = vl_calloc(sizeof(TYPE), self->dimension * numClusters) ;
    }

    /*
      Accumulate weighted sums and sum of square differences. Once normalized,
      these become the means and covariances of each Gaussian mode.

      The squared differences will be taken w.r.t. the old means however. In this manner,
      one avoids doing two passes across the data. Eventually, these are corrected to account
      for the new means properly. In principle, one could set the old means to zero, but
      this may cause numerical instabilities (by accumulating large squares).
    */

#if defined(_OPENMP)
#pragma omp for
#endif
    for (i_d = 0 ; i_d < (signed)numData ; ++i_d) {
      for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) {
        TYPE p = posteriors[i_cl + i_d * self->numClusters] ;
        vl_bool calculated = VL_FALSE ;

        /* skip very small associations for speed */
        if (p < VL_GMM_MIN_POSTERIOR / numClusters) { continue ; }

        clusterPosteriorSum_ [i_cl] += p ;

        #ifndef VL_DISABLE_AVX
        if (vl_get_simd_enabled() && vl_cpu_has_avx()) {
          VL_XCAT(_vl_weighted_mean_sse2_, SFX)
          (self->dimension,
           means_+ i_cl * self->dimension,
           data + i_d * self->dimension,
           p) ;

          VL_XCAT(_vl_weighted_sigma_sse2_, SFX)
          (self->dimension,
           covariances_ + i_cl * self->dimension,
           data + i_d * self->dimension,
           oldMeans + i_cl * self->dimension,
           p) ;

          calculated = VL_TRUE;
        }
        #endif
        #ifndef VL_DISABLE_SSE2
        if (vl_get_simd_enabled() && vl_cpu_has_sse2() && !calculated) {
          VL_XCAT(_vl_weighted_mean_sse2_, SFX)
          (self->dimension,
           means_+ i_cl * self->dimension,
           data + i_d * self->dimension,
           p) ;

           VL_XCAT(_vl_weighted_sigma_sse2_, SFX)
          (self->dimension,
           covariances_ + i_cl * self->dimension,
           data + i_d * self->dimension,
           oldMeans + i_cl * self->dimension,
           p) ;

          calculated = VL_TRUE;
        }
        #endif
        if(!calculated) {
          for (dim = 0 ; dim < self->dimension ; ++dim) {
            TYPE x = data[i_d * self->dimension + dim] ;
            TYPE mu = oldMeans[i_cl * self->dimension + dim] ;
            TYPE diff = x - mu ;
            means_ [i_cl * self->dimension + dim] += p * x ;
            covariances_ [i_cl * self->dimension + dim] += p * (diff*diff) ;
          }
        }
      }
    }

    /* accumulate */
#if defined(_OPENMP)
#pragma omp critical
#endif
    {
      for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) {
        priors [i_cl] += clusterPosteriorSum_ [i_cl];
        for (dim = 0 ; dim < self->dimension ; ++dim) {
          means [i_cl * self->dimension + dim] += means_ [i_cl * self->dimension + dim] ;
          covariances [i_cl * self->dimension + dim] += covariances_ [i_cl * self->dimension + dim] ;
        }
      }
      vl_free(means_);
      vl_free(covariances_);
      vl_free(clusterPosteriorSum_);
    }
  } /* parallel section */

  /* at this stage priors[] contains the total mass of each cluster */
  for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) {
    TYPE mass = priors[i_cl] ;
    /* do not update modes that do not recieve mass */
    if (mass >= 1e-6 / numClusters) {
      for (dim = 0 ; dim < self->dimension ; ++dim) {
        means[i_cl * self->dimension + dim] /= mass ;
        covariances[i_cl * self->dimension + dim] /= mass ;
      }
    }
  }

  /* apply old to new means correction */
  for (i_cl = 0 ; i_cl < (signed)numClusters ; ++ i_cl) {
    TYPE mass = priors[i_cl] ;
    if (mass >= 1e-6 / numClusters) {
      for (dim = 0 ; dim < self->dimension ; ++dim) {
        TYPE mu = means[i_cl * self->dimension + dim] ;
        TYPE oldMu = oldMeans[i_cl * self->dimension + dim] ;
        TYPE diff = mu - oldMu ;
        covariances[i_cl * self->dimension + dim] -= diff * diff ;
      }
    }
  }

  VL_XCAT(_vl_gmm_apply_bounds_,SFX)(self) ;

  {
    TYPE sum = 0;
    for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) {
      sum += priors[i_cl] ;
    }
    sum = VL_MAX(sum, 1e-12) ;
    for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) {
      priors[i_cl] /= sum ;
    }
  }

  if (self->verbosity > 1) {
    VL_PRINTF("gmm: em: maximization step completed in %.2f s\n",
              vl_get_cpu_time() - time) ;
  }

  vl_free(oldMeans);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %r9, 0x30(%rsp)
movq %r8, %r13
movq %rcx, 0x38(%rsp)
movq %rdx, %r12
movq %rsi, 0x78(%rsp)
movq %rdi, %rbx
movq 0xd0(%rsp), %rbp
movq 0x10(%rdi), %r15
xorps %xmm0, %xmm0
cmpl $0x2, 0x30(%rdi)
jl 0x13bfa
callq 0x9180
movq %rax, %rcx
leaq 0x1e9ef(%rip), %rdi     # 0x325e0
xorl %eax, %eax
callq *%rcx
callq 0x9350
movsd %xmm0, 0x58(%rsp)
leaq (,%r15,4), %r14
movq 0x8(%rbx), %rdi
imulq %r14, %rdi
callq 0x95b0
movq 0x8(%rbx), %rdx
imulq %r14, %rdx
movq %rax, 0x20(%rsp)
movq %rax, %rdi
movq %r13, %rsi
callq 0x95a0
movq %r12, 0x68(%rsp)
movq %r12, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x9400
movq 0x8(%rbx), %rdx
imulq %r14, %rdx
movq %r13, 0x60(%rsp)
movq %r13, %rdi
xorl %esi, %esi
callq 0x9400
imulq 0x8(%rbx), %r14
movq 0x38(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x9400
movl $0x4, %edi
movq %r15, %rsi
callq 0x98f0
movq %rax, 0x28(%rsp)
movq 0x8(%rbx), %rsi
imulq %r15, %rsi
movl $0x4, %edi
callq 0x98f0
movq %rax, 0x18(%rsp)
movq 0x8(%rbx), %rsi
imulq %r15, %rsi
movl $0x4, %edi
callq 0x98f0
movq %rax, 0x10(%rsp)
movslq %ebp, %rax
movslq %r15d, %rbp
movq %r15, %xmm0
movdqa %xmm0, 0x80(%rsp)
movq %rax, 0x70(%rsp)
testq %rax, %rax
jle 0x13f23
movapd 0x80(%rsp), %xmm0
unpcklps 0x1e4a4(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1e4ac(%rip), %xmm0    # 0x32190
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1e800(%rip), %xmm2    # 0x324f8
divsd %xmm1, %xmm2
movq $0x0, 0x40(%rsp)
xorl %r14d, %r14d
movq %rbp, 0x50(%rsp)
movsd %xmm2, 0x48(%rsp)
testq %rbp, %rbp
jle 0x13f0f
xorl %r13d, %r13d
xorl %r15d, %r15d
movq 0x10(%rbx), %rax
imulq %r14, %rax
movq 0x78(%rsp), %rcx
leaq (%rcx,%r15,4), %rcx
movss (%rcx,%rax,4), %xmm1
xorps %xmm0, %xmm0
cvtss2sd %xmm1, %xmm0
ucomisd %xmm0, %xmm2
ja 0x13eff
movq 0x28(%rsp), %rax
movss (%rax,%r15,4), %xmm0
movss %xmm1, 0xc(%rsp)
addss %xmm1, %xmm0
movss %xmm0, (%rax,%r15,4)
callq 0x9210
movb $0x1, %r12b
testl %eax, %eax
je 0x13de3
callq 0x92f0
testl %eax, %eax
je 0x13de3
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r15, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rax
imulq %r14, %rax
movq 0x30(%rsp), %r12
leaq (%r12,%rax,4), %rdx
movss 0xc(%rsp), %xmm0
callq 0x9870
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r15, %rax
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rcx
imulq %r14, %rcx
leaq (%r12,%rcx,4), %rdx
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,4), %rcx
movss 0xc(%rsp), %xmm0
callq 0x9470
movb $0x1, %bpl
xorl %r12d, %r12d
jmp 0x13de5
xorl %ebp, %ebp
callq 0x9210
testl %eax, %eax
je 0x13e01
callq 0x9620
testl %eax, %eax
sete %al
orb %al, %bpl
je 0x13e92
testb %r12b, %r12b
movq 0x50(%rsp), %rbp
movsd 0x48(%rsp), %xmm2
movss 0xc(%rsp), %xmm3
je 0x13eff
movq 0x8(%rbx), %rax
testq %rax, %rax
je 0x13eff
movq %rax, %rcx
imulq %r13, %rcx
movq 0x18(%rsp), %rdx
addq %rcx, %rdx
movq 0x20(%rsp), %rsi
addq %rcx, %rsi
movq 0x40(%rsp), %rdi
imulq %rax, %rdi
addq 0x30(%rsp), %rdi
addq 0x10(%rsp), %rcx
xorl %r8d, %r8d
movss (%rdi,%r8,4), %xmm0
movaps %xmm0, %xmm1
subss (%rsi,%r8,4), %xmm1
mulss %xmm3, %xmm0
addss (%rdx,%r8,4), %xmm0
movss %xmm0, (%rdx,%r8,4)
mulss %xmm1, %xmm1
mulss %xmm3, %xmm1
addss (%rcx,%r8,4), %xmm1
movss %xmm1, (%rcx,%r8,4)
incq %r8
cmpq %r8, %rax
jne 0x13e55
jmp 0x13eff
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r15, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rax
imulq %r14, %rax
movq 0x30(%rsp), %r12
leaq (%r12,%rax,4), %rdx
movss 0xc(%rsp), %xmm0
callq 0x9870
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r15, %rax
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rcx
imulq %r14, %rcx
leaq (%r12,%rcx,4), %rdx
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,4), %rcx
movss 0xc(%rsp), %xmm0
callq 0x9470
movq 0x50(%rsp), %rbp
movsd 0x48(%rsp), %xmm2
incq %r15
addq $0x4, %r13
cmpq %rbp, %r15
jne 0x13d22
incq %r14
addq $0x4, 0x40(%rsp)
cmpq 0x70(%rsp), %r14
jne 0x13d13
testq %rbp, %rbp
jle 0x14141
movq 0x8(%rbx), %rax
leaq (,%rax,4), %rcx
xorl %edx, %edx
movq 0x18(%rsp), %rsi
movq 0x60(%rsp), %r15
movq %r15, %rdi
movq 0x38(%rsp), %r12
movq %r12, %r8
movq 0x10(%rsp), %r9
movq 0x68(%rsp), %r14
movq 0x28(%rsp), %r10
movss (%r10,%rdx,4), %xmm0
addss (%r14,%rdx,4), %xmm0
movss %xmm0, (%r14,%rdx,4)
testq %rax, %rax
je 0x13fa4
xorl %r10d, %r10d
movss (%rsi,%r10,4), %xmm0
addss (%rdi,%r10,4), %xmm0
movss %xmm0, (%rdi,%r10,4)
movss (%r9,%r10,4), %xmm0
addss (%r8,%r10,4), %xmm0
movss %xmm0, (%r8,%r10,4)
incq %r10
cmpq %r10, %rax
jne 0x13f78
incq %rdx
addq %rcx, %r9
addq %rcx, %r8
addq %rcx, %rdi
addq %rcx, %rsi
cmpq %rbp, %rdx
jne 0x13f59
movq 0x18(%rsp), %rdi
callq 0x9580
movq 0x10(%rsp), %rdi
callq 0x9580
movq 0x28(%rsp), %rdi
callq 0x9580
testq %rbp, %rbp
jle 0x1415f
movapd 0x80(%rsp), %xmm0
unpcklps 0x1e191(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1e199(%rip), %xmm0    # 0x32190
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1e3b5(%rip), %xmm0    # 0x323c0
divsd %xmm1, %xmm0
xorl %eax, %eax
xorl %ecx, %ecx
movss (%r14,%rcx,4), %xmm1
xorps %xmm2, %xmm2
cvtss2sd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
jb 0x14068
movq 0x8(%rbx), %rdx
testq %rdx, %rdx
je 0x14068
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%r15,%rsi), %rdi
addq %r12, %rsi
xorl %r8d, %r8d
movss (%rdi,%r8,4), %xmm2
divss %xmm1, %xmm2
movss %xmm2, (%rdi,%r8,4)
movss (%rsi,%r8,4), %xmm2
divss %xmm1, %xmm2
movss %xmm2, (%rsi,%r8,4)
incq %r8
cmpq %r8, %rdx
jne 0x14040
incq %rcx
addq $0x4, %rax
cmpq %rbp, %rcx
jne 0x14013
testq %rbp, %rbp
jle 0x1415f
xorl %eax, %eax
xorl %ecx, %ecx
xorps %xmm1, %xmm1
cvtss2sd (%r14,%rcx,4), %xmm1
ucomisd %xmm0, %xmm1
jb 0x140da
movq 0x8(%rbx), %rdx
testq %rdx, %rdx
je 0x140da
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%r12,%rsi), %rdi
movq 0x20(%rsp), %r8
addq %rsi, %r8
addq %r15, %rsi
xorl %r9d, %r9d
movss (%rsi,%r9,4), %xmm1
subss (%r8,%r9,4), %xmm1
movss (%rdi,%r9,4), %xmm2
mulss %xmm1, %xmm1
subss %xmm1, %xmm2
movss %xmm2, (%rdi,%r9,4)
incq %r9
cmpq %r9, %rdx
jne 0x140b2
incq %rcx
addq $0x4, %rax
cmpq %rbp, %rcx
jne 0x14081
movq %rbx, %rdi
callq 0x141a6
testq %rbp, %rbp
jle 0x14167
xorpd %xmm0, %xmm0
xorl %eax, %eax
addss (%r14,%rax,4), %xmm0
incq %rax
cmpq %rax, %rbp
jne 0x140f9
xorps %xmm1, %xmm1
cvtss2sd %xmm0, %xmm1
ucomisd 0x1e2ba(%rip), %xmm1    # 0x323d0
ja 0x14120
movss 0x1e2c0(%rip), %xmm0    # 0x323e0
testq %rbp, %rbp
jle 0x14167
xorl %eax, %eax
movss (%r14,%rax,4), %xmm1
divss %xmm0, %xmm1
movss %xmm1, (%r14,%rax,4)
incq %rax
cmpq %rax, %rbp
jne 0x14127
jmp 0x14167
movq 0x18(%rsp), %rdi
callq 0x9580
movq 0x10(%rsp), %rdi
callq 0x9580
movq 0x28(%rsp), %rdi
callq 0x9580
movq %rbx, %rdi
callq 0x141a6
cmpl $0x2, 0x30(%rbx)
jl 0x1418b
callq 0x9180
movq %rax, %rbx
callq 0x9350
subsd 0x58(%rsp), %xmm0
leaq 0x1e47e(%rip), %rdi     # 0x32605
movb $0x1, %al
callq *%rbx
movq 0x20(%rsp), %rdi
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x9580