// File: /workspace/github_c_makefile_star2_O1/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, %rbp
movq %rdx, %r12
movq %rsi, 0x90(%rsp)
movq %rdi, %rbx
movq 0xd0(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x10(%rdi), %rax
movq %rax, 0x28(%rsp)
xorps %xmm0, %xmm0
cmpl $0x2, 0x30(%rdi)
jl 0x13be7
callq 0x9180
movq %rax, %rcx
leaq 0x1fa02(%rip), %rdi     # 0x335e0
xorl %eax, %eax
callq *%rcx
callq 0x9350
movsd %xmm0, 0x60(%rsp)
movq 0x28(%rsp), %r15
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, 0x78(%rsp)
movq %r12, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x9400
movq 0x8(%rbx), %rdx
imulq %r14, %rdx
movq %r13, 0x70(%rsp)
movq %r13, %rdi
xorl %esi, %esi
callq 0x9400
imulq 0x8(%rbx), %r14
movq %rbp, 0x68(%rsp)
movq %rbp, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x9400
movl $0x4, %edi
movq %r15, %rsi
callq 0x98f0
movq %rax, 0x38(%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 0x8(%rsp), %rax
movq %r15, %xmm0
movdqa %xmm0, 0x50(%rsp)
movq %rax, 0x80(%rsp)
testq %rax, %rax
jle 0x13f47
movapd 0x50(%rsp), %xmm0
unpcklps 0x1f4b3(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1f4bb(%rip), %xmm0    # 0x33190
movslq 0x28(%rsp), %r14
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1f80a(%rip), %xmm2    # 0x334f8
divsd %xmm1, %xmm2
movq $0x0, 0x40(%rsp)
xorl %r15d, %r15d
movq %rbx, 0x48(%rsp)
movsd %xmm2, 0x88(%rsp)
testq %r14, %r14
jle 0x13f30
xorl %ebp, %ebp
xorl %r12d, %r12d
movq 0x10(%rbx), %rax
imulq %r15, %rax
movq 0x90(%rsp), %rcx
leaq (%rcx,%r12,4), %rcx
movss (%rcx,%rax,4), %xmm1
xorps %xmm0, %xmm0
cvtss2sd %xmm1, %xmm0
ucomisd %xmm0, %xmm2
ja 0x13f20
movq 0x38(%rsp), %rax
movss (%rax,%r12,4), %xmm0
movss %xmm1, 0x8(%rsp)
addss %xmm1, %xmm0
movss %xmm0, (%rax,%r12,4)
callq 0x9210
testl %eax, %eax
je 0x13def
callq 0x92f0
testl %eax, %eax
je 0x13def
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r12, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rax
imulq %r15, %rax
movq 0x30(%rsp), %r13
leaq (,%rax,4), %rdx
addq %r13, %rdx
movss 0x8(%rsp), %xmm0
callq 0x9870
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r12, %rax
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rcx
imulq %r15, %rcx
leaq (,%rcx,4), %rdx
addq %r13, %rdx
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,4), %rcx
movss 0x8(%rsp), %xmm0
callq 0x9470
movl $0x1, %r13d
movb $0x1, %bl
jmp 0x13df4
xorl %ebx, %ebx
xorl %r13d, %r13d
callq 0x9210
testl %eax, %eax
je 0x13e96
callq 0x9620
testl %eax, %eax
sete %al
orb %al, %bl
movq 0x48(%rsp), %rbx
movss 0x8(%rsp), %xmm0
jne 0x13ea1
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r12, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rax
imulq %r15, %rax
movq 0x30(%rsp), %r13
leaq (,%rax,4), %rdx
addq %r13, %rdx
callq 0x9870
movq 0x8(%rbx), %rdi
movq %rdi, %rax
imulq %r12, %rax
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,4), %rsi
movq %rdi, %rcx
imulq %r15, %rcx
leaq (,%rcx,4), %rdx
addq %r13, %rdx
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,4), %rcx
movss 0x8(%rsp), %xmm0
callq 0x9470
movss 0x8(%rsp), %xmm0
movl $0x1, %r13d
jmp 0x13ea1
movq 0x48(%rsp), %rbx
movss 0x8(%rsp), %xmm0
testl %r13d, %r13d
movsd 0x88(%rsp), %xmm2
jne 0x13f20
movq 0x8(%rbx), %rax
testq %rax, %rax
je 0x13f20
movq %rax, %rcx
imulq %rbp, %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), %xmm3
movaps %xmm3, %xmm1
subss (%rsi,%r8,4), %xmm1
mulss %xmm0, %xmm3
addss (%rdx,%r8,4), %xmm3
movss %xmm3, (%rdx,%r8,4)
mulss %xmm1, %xmm1
mulss %xmm0, %xmm1
addss (%rcx,%r8,4), %xmm1
movss %xmm1, (%rcx,%r8,4)
incq %r8
cmpq %r8, %rax
jne 0x13ee5
incq %r12
addq $0x4, %rbp
cmpq %r14, %r12
jne 0x13d1a
incq %r15
addq $0x4, 0x40(%rsp)
cmpq 0x80(%rsp), %r15
jne 0x13d0c
movslq 0x28(%rsp), %r12
testq %r12, %r12
movq 0x78(%rsp), %r14
movq 0x70(%rsp), %r15
movq 0x68(%rsp), %r13
jle 0x13fdd
movq 0x8(%rbx), %rax
leaq (,%rax,4), %rcx
xorl %edx, %edx
movq 0x18(%rsp), %rsi
movq %r15, %rdi
movq %r13, %r8
movq 0x10(%rsp), %r9
movq 0x38(%rsp), %r10
movss (%r10,%rdx,4), %xmm0
addss (%r14,%rdx,4), %xmm0
movss %xmm0, (%r14,%rdx,4)
testq %rax, %rax
je 0x13fc9
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 0x13f9d
incq %rdx
addq %rcx, %r9
addq %rcx, %r8
addq %rcx, %rdi
addq %rcx, %rsi
cmpq %r12, %rdx
jne 0x13f7e
movq 0x18(%rsp), %rdi
callq 0x9580
movq 0x10(%rsp), %rdi
callq 0x9580
movq 0x38(%rsp), %rdi
callq 0x9580
testq %r12, %r12
jle 0x14096
movapd 0x50(%rsp), %xmm0
unpcklps 0x1f16f(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1f177(%rip), %xmm0    # 0x33190
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1f383(%rip), %xmm0    # 0x333b0
divsd %xmm1, %xmm0
xorl %eax, %eax
xorl %ecx, %ecx
movss (%r14,%rcx,4), %xmm1
xorps %xmm2, %xmm2
cvtss2sd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
jb 0x1408a
movq 0x8(%rbx), %rdx
testq %rdx, %rdx
je 0x1408a
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%r15,%rsi), %rdi
addq %r13, %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 0x14062
incq %rcx
addq $0x4, %rax
cmpq %r12, %rcx
jne 0x14035
testq %r12, %r12
jle 0x14135
movapd 0x50(%rsp), %xmm0
unpcklps 0x1f0d4(%rip), %xmm0    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1f0dc(%rip), %xmm0    # 0x33190
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1f2e8(%rip), %xmm0    # 0x333b0
divsd %xmm1, %xmm0
xorl %eax, %eax
xorl %ecx, %ecx
xorps %xmm1, %xmm1
cvtss2sd (%r14,%rcx,4), %xmm1
ucomisd %xmm0, %xmm1
jb 0x14129
movq 0x8(%rbx), %rdx
testq %rdx, %rdx
je 0x14129
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%rsi,%r13), %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 0x14101
incq %rcx
addq $0x4, %rax
cmpq %r12, %rcx
jne 0x140d0
movq %rbx, %rdi
callq 0x141cd
pxor %xmm0, %xmm0
testq %r12, %r12
jle 0x14156
xorl %eax, %eax
addss (%r14,%rax,4), %xmm0
incq %rax
cmpq %rax, %r12
jne 0x14148
xorps %xmm1, %xmm1
cvtss2sd %xmm0, %xmm1
ucomisd 0x1f25b(%rip), %xmm1    # 0x333c0
ja 0x1416f
movss 0x1f261(%rip), %xmm0    # 0x333d0
testq %r12, %r12
jle 0x1418e
xorl %eax, %eax
movss (%r14,%rax,4), %xmm1
divss %xmm0, %xmm1
movss %xmm1, (%r14,%rax,4)
incq %rax
cmpq %rax, %r12
jne 0x14176
cmpl $0x2, 0x30(%rbx)
jl 0x141b2
callq 0x9180
movq %rax, %rbx
callq 0x9350
subsd 0x60(%rsp), %xmm0
leaq 0x1f457(%rip), %rdi     # 0x33605
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