// File: /workspace/github_c_makefile_star2_O2/zpole[P]IICV/vl/gmm.c
// Function: vl_gmm_maximization_d
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, 0x48(%rsp)
movq %rcx, 0x40(%rsp)
movq %rdx, %r15
movq %rsi, 0x78(%rsp)
movq %rdi, %r14
movq 0xd0(%rsp), %r13
movq 0x10(%rdi), %rbp
xorps %xmm0, %xmm0
cmpl $0x2, 0x30(%rdi)
jl 0x12db3
callq 0x9180
movq %rax, %rcx
leaq 0x1a7f6(%rip), %rdi     # 0x2d5a0
xorl %eax, %eax
callq *%rcx
callq 0x9370
movsd %xmm0, 0x60(%rsp)
leaq (,%rbp,8), %rbx
movq 0x8(%r14), %rdi
imulq %rbx, %rdi
callq 0x95e0
movq 0x8(%r14), %rdx
imulq %rbx, %rdx
movq %rax, 0x10(%rsp)
movq %rax, %rdi
movq %r14, 0x8(%rsp)
movq 0x48(%rsp), %r12
movq %r12, %rsi
callq 0x95d0
xorl %r14d, %r14d
movq %r15, 0x68(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x9420
movq 0x8(%rsp), %rax
movq 0x8(%rax), %rdx
imulq %rbx, %rdx
movq %r12, %rdi
movq 0x8(%rsp), %r12
xorl %esi, %esi
callq 0x9420
imulq 0x8(%r12), %rbx
movq 0x40(%rsp), %rdi
xorl %esi, %esi
movq %rbx, %rdx
callq 0x9420
pushq $0x8
popq %r15
movq %r15, %rdi
movq %rbp, %rsi
callq 0x9960
movq %rax, 0x38(%rsp)
movq 0x8(%r12), %rsi
imulq %rbp, %rsi
movq %r15, %rdi
callq 0x9960
movq %rax, 0x20(%rsp)
movq 0x8(%r12), %rsi
imulq %rbp, %rsi
movq %r15, %rdi
callq 0x9960
movq %rax, 0x18(%rsp)
movslq %r13d, %rcx
movslq %ebp, %r13
movq %rbp, %xmm0
punpckldq 0x1a2d7(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x1a2df(%rip), %xmm0    # 0x2d170
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x1a613(%rip), %xmm2    # 0x2d4b8
movapd %xmm1, 0x80(%rsp)
divsd %xmm1, %xmm2
testq %r13, %r13
cmovleq %r14, %r13
testq %rcx, %rcx
movl $0x0, %eax
movq %rax, 0x50(%rsp)
cmovleq %r14, %rcx
movq %rcx, 0x70(%rsp)
xorl %r15d, %r15d
movsd %xmm2, 0x58(%rsp)
cmpq 0x70(%rsp), %r15
je 0x1310a
xorl %ebp, %ebp
xorl %ebx, %ebx
cmpq %r13, %rbx
je 0x130fc
movq 0x10(%r12), %rax
imulq %r15, %rax
movq 0x78(%rsp), %rcx
leaq (%rcx,%rbx,8), %rcx
movsd (%rcx,%rax,8), %xmm1
ucomisd %xmm1, %xmm2
ja 0x130f0
movq %r13, %r14
movq 0x38(%rsp), %rax
movsd (%rax,%rbx,8), %xmm0
movsd %xmm1, 0x28(%rsp)
addsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rbx,8)
callq 0x9210
movb $0x1, %r13b
testl %eax, %eax
je 0x12fc0
callq 0x9300
testl %eax, %eax
je 0x12fc0
movq 0x8(%r12), %rdi
movq %rdi, %rax
imulq %rbx, %rax
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,8), %rsi
movq %rdi, %rax
imulq %r15, %rax
movq 0x30(%rsp), %r13
leaq (,%rax,8), %rdx
addq %r13, %rdx
movsd 0x28(%rsp), %xmm0
callq 0x9900
movq 0x8(%r12), %rdi
movq %rdi, %rax
imulq %rbx, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,8), %rsi
movq %rdi, %rcx
imulq %r15, %rcx
leaq (,%rcx,8), %rdx
addq %r13, %rdx
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,8), %rcx
movsd 0x28(%rsp), %xmm0
callq 0x9740
movb $0x1, %r12b
xorl %r13d, %r13d
jmp 0x12fc3
xorl %r12d, %r12d
callq 0x9210
testl %eax, %eax
je 0x12fdf
callq 0x9660
testl %eax, %eax
sete %al
orb %al, %r12b
je 0x13070
testb %r13b, %r13b
movq %r14, %r13
movq 0x8(%rsp), %r12
movsd 0x58(%rsp), %xmm2
movsd 0x28(%rsp), %xmm3
je 0x130f0
movq 0x8(%r12), %rax
movq %rax, %rcx
imulq %rbp, %rcx
movq 0x18(%rsp), %rdx
addq %rcx, %rdx
movq 0x50(%rsp), %rsi
imulq %rax, %rsi
addq 0x30(%rsp), %rsi
movq 0x20(%rsp), %rdi
addq %rcx, %rdi
addq 0x10(%rsp), %rcx
xorl %r8d, %r8d
cmpq %r8, %rax
je 0x130f0
movsd (%rsi,%r8,8), %xmm0
movapd %xmm0, %xmm1
subsd (%rcx,%r8,8), %xmm1
mulsd %xmm3, %xmm0
addsd (%rdi,%r8,8), %xmm0
movsd %xmm0, (%rdi,%r8,8)
mulsd %xmm1, %xmm1
mulsd %xmm3, %xmm1
addsd (%rdx,%r8,8), %xmm1
movsd %xmm1, (%rdx,%r8,8)
incq %r8
jmp 0x1302e
movq 0x8(%rsp), %r12
movq 0x8(%r12), %rdi
movq %rdi, %rax
imulq %rbx, %rax
movq 0x20(%rsp), %rcx
leaq (%rcx,%rax,8), %rsi
movq %rdi, %rax
imulq %r15, %rax
movq 0x30(%rsp), %r13
leaq (,%rax,8), %rdx
addq %r13, %rdx
movsd 0x28(%rsp), %xmm0
callq 0x9900
movq 0x8(%r12), %rdi
movq %rdi, %rax
imulq %rbx, %rax
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,8), %rsi
movq %rdi, %rcx
imulq %r15, %rcx
leaq (,%rcx,8), %rdx
addq %r13, %rdx
movq 0x10(%rsp), %rcx
leaq (%rcx,%rax,8), %rcx
movsd 0x28(%rsp), %xmm0
callq 0x9740
movq %r14, %r13
movsd 0x58(%rsp), %xmm2
incq %rbx
addq $0x8, %rbp
jmp 0x12ee7
incq %r15
addq $0x8, 0x50(%rsp)
jmp 0x12ed8
xorl %eax, %eax
xorl %ecx, %ecx
movq 0x68(%rsp), %rbx
movq 0x48(%rsp), %r15
movq 0x40(%rsp), %r12
cmpq %r13, %rcx
je 0x13195
movq 0x38(%rsp), %rdx
movsd (%rdx,%rcx,8), %xmm0
addsd (%rbx,%rcx,8), %xmm0
movsd %xmm0, (%rbx,%rcx,8)
movq 0x8(%rsp), %rdx
movq 0x8(%rdx), %rdx
movq %rdx, %rsi
imulq %rax, %rsi
movq 0x18(%rsp), %rdi
addq %rsi, %rdi
leaq (%r12,%rsi), %r8
leaq (%r15,%rsi), %r9
addq 0x20(%rsp), %rsi
xorl %r10d, %r10d
cmpq %r10, %rdx
je 0x1318c
movsd (%rsi,%r10,8), %xmm0
addsd (%r9,%r10,8), %xmm0
movsd %xmm0, (%r9,%r10,8)
movsd (%rdi,%r10,8), %xmm0
addsd (%r8,%r10,8), %xmm0
movsd %xmm0, (%r8,%r10,8)
incq %r10
jmp 0x1315e
incq %rcx
addq $0x8, %rax
jmp 0x1311d
movq 0x20(%rsp), %rdi
callq 0x95b0
movq 0x18(%rsp), %rdi
callq 0x95b0
movq 0x38(%rsp), %rdi
callq 0x95b0
movsd 0x1a1d5(%rip), %xmm0    # 0x2d390
divsd 0x80(%rsp), %xmm0
xorl %eax, %eax
xorl %ecx, %ecx
cmpq %r13, %rcx
je 0x13225
movsd (%rbx,%rcx,8), %xmm1
ucomisd %xmm0, %xmm1
jae 0x131e1
incq %rcx
addq $0x8, %rax
jmp 0x131c8
movq 0x8(%rsp), %rdx
movq 0x8(%rdx), %rdx
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%r12,%rsi), %rdi
addq %r15, %rsi
xorl %r8d, %r8d
cmpq %r8, %rdx
je 0x131d8
movsd (%rsi,%r8,8), %xmm2
divsd %xmm1, %xmm2
movsd %xmm2, (%rsi,%r8,8)
movsd (%rdi,%r8,8), %xmm2
divsd %xmm1, %xmm2
movsd %xmm2, (%rdi,%r8,8)
incq %r8
jmp 0x131fb
xorl %eax, %eax
xorl %ecx, %ecx
cmpq %r13, %rcx
je 0x1328e
movsd (%rbx,%rcx,8), %xmm1
ucomisd %xmm0, %xmm1
jae 0x13242
incq %rcx
addq $0x8, %rax
jmp 0x13229
movq 0x8(%rsp), %rdx
movq 0x8(%rdx), %rdx
movq %rdx, %rsi
imulq %rax, %rsi
leaq (%r12,%rsi), %rdi
movq 0x10(%rsp), %r8
addq %rsi, %r8
addq %r15, %rsi
xorl %r9d, %r9d
cmpq %r9, %rdx
je 0x13239
movsd (%rsi,%r9,8), %xmm1
subsd (%r8,%r9,8), %xmm1
movsd (%rdi,%r9,8), %xmm2
mulsd %xmm1, %xmm1
subsd %xmm1, %xmm2
movsd %xmm2, (%rdi,%r9,8)
incq %r9
jmp 0x13264
movq 0x8(%rsp), %r14
movq %r14, %rdi
callq 0x13312
xorpd %xmm0, %xmm0
xorl %eax, %eax
cmpq %rax, %r13
je 0x132b0
addsd (%rbx,%rax,8), %xmm0
incq %rax
jmp 0x132a1
maxsd 0x1a0e8(%rip), %xmm0    # 0x2d3a0
xorl %eax, %eax
cmpq %rax, %r13
je 0x132d2
movsd (%rbx,%rax,8), %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%rbx,%rax,8)
incq %rax
jmp 0x132ba
cmpl $0x2, 0x30(%r14)
jl 0x132f7
callq 0x9180
movq %rax, %rbx
callq 0x9370
subsd 0x60(%rsp), %xmm0
leaq 0x1a2d2(%rip), %rdi     # 0x2d5c5
movb $0x1, %al
callq *%rbx
movq 0x10(%rsp), %rdi
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x95b0