// File: tomfunkhouser[P]gaps/pkgs/R3Surfels/R3SurfelPointGraph.cpp
// Function: gaps::R3SurfelPointGraph::RemoveOutlierEdges(double)
void R3SurfelPointGraph::
RemoveOutlierEdges(RNScalar max_zscore)
{
  // Allocate temporary memory for edge length statistics
  RNScalar *means = new RNScalar [ NPoints() ];
  RNScalar *stddevs = new RNScalar [ NPoints() ];

  // Compute edge length statistics
  for (int i = 0; i < NPoints(); i++) {
    // Compute sum
    RNLength sum = 0;
    R3SurfelPoint *point0 = Point(i);
    R3Point position0 = point0->Position();
    for (int j = 0; j < NNeighbors(i); j++) {
      R3SurfelPoint *point1 = Neighbor(i,j);
      R3Point position1 = point1->Position();
      RNLength edge_length = R3Distance(position0, position1);
      sum += edge_length;
    }
    
    // Compute mean
    means[i] = (NNeighbors(i)) ? sum / NNeighbors(i) : 0;

    // Compute sum of squared residuals
    RNLength ssd = 0;
    for (int j = 0; j < NNeighbors(i); j++) {
      R3SurfelPoint *point1 = Neighbor(i,j);
      R3Point position1 = point1->Position();
      RNLength edge_length = R3Distance(position0, position1);
      RNLength delta = edge_length - means[i];
      ssd += delta * delta;
    }

    // Compute standard deviation
    RNScalar variance = (NNeighbors(i)) ? ssd / NNeighbors(i) : 0; 
    stddevs[i] = sqrt(variance);
  }

  // Remove outlier edges
  for (int i = 0; i < NPoints(); i++) {
    if (stddevs[i] == 0) continue;
    R3SurfelPoint *point0 = Point(i);
    R3Point position0 = point0->Position();
    for (int j = 0; j < neighbors[i].NEntries(); j++) {
      R3SurfelPoint *point1 = neighbors[i].Kth(j);
      R3Point position1 = point1->Position();
      RNLength edge_length = R3Distance(position0, position1);
      RNScalar zscore = (edge_length - means[i]) / stddevs[i];
      if (zscore > max_zscore) {
        // Remove edge
        RNArrayEntry *entry = neighbors[i].KthEntry(j);
        neighbors[i].EntryContents(entry) = neighbors[i].Tail();
        neighbors[i].RemoveTail();
        j--;
      }
    }
  }    

  // Delete temporary memory for edge length statistics
  delete [] means;
  delete [] stddevs;
}

// Assembly:
subq $0x188, %rsp            # imm = 0x188
movq %rdi, 0x180(%rsp)
movsd %xmm0, 0x178(%rsp)
movq 0x180(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x43e20
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x13030
movq 0x50(%rsp), %rdi
movq %rax, 0x170(%rsp)
callq 0x43e20
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x13030
movq %rax, 0x168(%rsp)
movl $0x0, 0x164(%rsp)
movq 0x50(%rsp), %rdi
movl 0x164(%rsp), %eax
movl %eax, 0x4c(%rsp)
callq 0x43e20
movl %eax, %ecx
movl 0x4c(%rsp), %eax
cmpl %ecx, %eax
jge 0x5e4d9
movq 0x50(%rsp), %rdi
xorps %xmm0, %xmm0
movsd %xmm0, 0x158(%rsp)
movl 0x164(%rsp), %esi
callq 0x43e40
movq %rax, 0x150(%rsp)
movq 0x150(%rsp), %rsi
leaq 0x138(%rsp), %rdi
callq 0x18730
movl $0x0, 0x134(%rsp)
movq 0x50(%rsp), %rdi
movl 0x134(%rsp), %eax
movl %eax, 0x48(%rsp)
movl 0x164(%rsp), %esi
callq 0x43ef0
movl %eax, %ecx
movl 0x48(%rsp), %eax
cmpl %ecx, %eax
jge 0x5e2cb
movq 0x50(%rsp), %rdi
movl 0x164(%rsp), %esi
movl 0x134(%rsp), %edx
callq 0x43f20
movq %rax, 0x128(%rsp)
movq 0x128(%rsp), %rsi
leaq 0x110(%rsp), %rdi
callq 0x18730
leaq 0x138(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0x8e7e0
movsd %xmm0, 0x108(%rsp)
movsd 0x108(%rsp), %xmm0
addsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x158(%rsp)
movl 0x134(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x134(%rsp)
jmp 0x5e21d
movq 0x50(%rsp), %rdi
movl 0x164(%rsp), %esi
callq 0x43ef0
cmpl $0x0, %eax
je 0x5e317
movq 0x50(%rsp), %rdi
movsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x38(%rsp)
movl 0x164(%rsp), %esi
callq 0x43ef0
movsd 0x38(%rsp), %xmm0
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x40(%rsp)
jmp 0x5e322
xorps %xmm0, %xmm0
movsd %xmm0, 0x40(%rsp)
jmp 0x5e322
movsd 0x40(%rsp), %xmm0
movq 0x170(%rsp), %rax
movslq 0x164(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
xorps %xmm0, %xmm0
movsd %xmm0, 0x100(%rsp)
movl $0x0, 0xfc(%rsp)
movq 0x50(%rsp), %rdi
movl 0xfc(%rsp), %eax
movl %eax, 0x34(%rsp)
movl 0x164(%rsp), %esi
callq 0x43ef0
movl %eax, %ecx
movl 0x34(%rsp), %eax
cmpl %ecx, %eax
jge 0x5e43a
movq 0x50(%rsp), %rdi
movl 0x164(%rsp), %esi
movl 0xfc(%rsp), %edx
callq 0x43f20
movq %rax, 0xf0(%rsp)
movq 0xf0(%rsp), %rsi
leaq 0xd8(%rsp), %rdi
callq 0x18730
leaq 0x138(%rsp), %rdi
leaq 0xd8(%rsp), %rsi
callq 0x8e7e0
movsd %xmm0, 0xd0(%rsp)
movsd 0xd0(%rsp), %xmm0
movq 0x170(%rsp), %rax
movslq 0x164(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xc8(%rsp)
movsd 0xc8(%rsp), %xmm0
movsd 0xc8(%rsp), %xmm2
movsd 0x100(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x100(%rsp)
movl 0xfc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfc(%rsp)
jmp 0x5e354
movq 0x50(%rsp), %rdi
movl 0x164(%rsp), %esi
callq 0x43ef0
cmpl $0x0, %eax
je 0x5e486
movq 0x50(%rsp), %rdi
movsd 0x100(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movl 0x164(%rsp), %esi
callq 0x43ef0
movsd 0x20(%rsp), %xmm0
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
jmp 0x5e491
xorps %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
jmp 0x5e491
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0xc0(%rsp)
movsd 0xc0(%rsp), %xmm0
callq 0x13420
movq 0x168(%rsp), %rax
movslq 0x164(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl 0x164(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x164(%rsp)
jmp 0x5e1b5
movl $0x0, 0xbc(%rsp)
movq 0x50(%rsp), %rdi
movl 0xbc(%rsp), %eax
movl %eax, 0x1c(%rsp)
callq 0x43e20
movl %eax, %ecx
movl 0x1c(%rsp), %eax
cmpl %ecx, %eax
jge 0x5e718
movq 0x168(%rsp), %rax
movslq 0xbc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x5e52c
jp 0x5e52c
jmp 0x5e702
movq 0x50(%rsp), %rdi
movl 0xbc(%rsp), %esi
callq 0x43e40
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rsi
leaq 0x98(%rsp), %rdi
callq 0x18730
movl $0x0, 0x94(%rsp)
movq 0x50(%rsp), %rax
movl 0x94(%rsp), %ecx
movl %ecx, 0x18(%rsp)
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
callq 0x16d50
movl %eax, %ecx
movl 0x18(%rsp), %eax
cmpl %ecx, %eax
jge 0x5e700
movq 0x50(%rsp), %rax
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movl 0x94(%rsp), %esi
callq 0x44520
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rsi
leaq 0x70(%rsp), %rdi
callq 0x18730
leaq 0x98(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x8e7e0
movsd %xmm0, 0x68(%rsp)
movsd 0x68(%rsp), %xmm0
movq 0x170(%rsp), %rax
movslq 0xbc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm0
movq 0x168(%rsp), %rax
movslq 0xbc(%rsp), %rcx
divsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0x60(%rsp), %xmm0
ucomisd 0x178(%rsp), %xmm0
jbe 0x5e6e8
movq 0x50(%rsp), %rax
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movl 0x94(%rsp), %esi
callq 0x1c080
movq %rax, %rcx
movq 0x50(%rsp), %rax
movq %rcx, 0x58(%rsp)
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
callq 0x43eb0
movq %rax, %rcx
movq 0x50(%rsp), %rax
movq %rcx, 0x10(%rsp)
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movq 0x58(%rsp), %rsi
callq 0x5e760
movq 0x10(%rsp), %rdx
movq %rax, %rcx
movq 0x50(%rsp), %rax
movq %rdx, (%rcx)
movq 0x68(%rax), %rdi
movslq 0xbc(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
callq 0x1c0c0
movl 0x94(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x94(%rsp)
jmp 0x5e6ea
movl 0x94(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x94(%rsp)
jmp 0x5e565
jmp 0x5e702
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xbc(%rsp)
jmp 0x5e4e4
movq 0x170(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x5e735
movq 0x8(%rsp), %rdi
callq 0x13750
movq 0x168(%rsp), %rax
movq %rax, (%rsp)
cmpq $0x0, %rax
je 0x5e750
movq (%rsp), %rdi
callq 0x13750
addq $0x188, %rsp            # imm = 0x188
retq
nopl (%rax,%rax)