// File: /workspace/github_cpp_makefile_star2_O2/cdalitz[P]kdtree-cpp/demo_kdtree.cpp
// Function: main
int main(int argc, char** argv) {

  //
  // functionality tests
  //
  cout << "Functionality tests" << endl;
  cout << "-------------------" << endl;
  
  // 1.1) construction of kd-tree
  Kdtree::KdNodeVector nodes;
  double points[10][2] = {{1, 1}, {2, 1}, {1, 2}, {2, 4}, {3, 4},
                          {7, 2}, {8, 3}, {8, 5}, {7, 3}, {7, 3}};
  for (int i = 0; i < 10; ++i) {
    std::vector<double> point(2);
    point[0] = points[i][0];
    point[1] = points[i][1];
    nodes.push_back(Kdtree::KdNode(point));
  }
  Kdtree::KdTree tree(&nodes);
  cout << "Points in kd-tree:\n  ";
  print_nodes(tree.allnodes);

  // 1.2) kNN search
  Kdtree::KdNodeVector result;
  std::vector<double> test_point(2);
  test_point[0] = 8;
  test_point[1] = 3;
  tree.k_nearest_neighbors(test_point, 3, &result);
  cout << "3NNs of (" << test_point[0] << "," << test_point[1] << "):\n  ";
  print_nodes(result);

  // 1.3) kNN search with predicate
  struct Predicate : Kdtree::KdNodePredicate {
    std::vector<double> point;
    Predicate(std::vector<double> p) {
      this->point = p;
    }
    // only search for points with smaller y-coordinate
    bool operator()(const Kdtree::KdNode& kn) const {
      return this->point[1] > kn.point[1];
    }
  };
  Predicate pred(test_point);
  tree.k_nearest_neighbors(test_point, 3, &result, &pred);
  cout << "3NNs of (" << test_point[0] << "," << test_point[1] << ") with smaller y-coordinate:\n  ";
  print_nodes(result);

  // 1.4) range query
  test_point[0] = 8;
  test_point[1] = 2;
  tree.range_nearest_neighbors(test_point, 1.1, &result);
  cout << "Neighbors of (" << test_point[0] << "," << test_point[1] << ") with distance <= 1.1:\n  ";
  print_nodes(result);
  // same with maximum distance (distance_type=0)
  Kdtree::KdTree tree0(&nodes, 0);
  tree0.range_nearest_neighbors(test_point, 1.1, &result);
  cout << "Neighbors of (" << test_point[0] << "," << test_point[1] << ") with maximum distance <= 1.1:\n  ";
  print_nodes(result);

  //
  // speed tests
  //
  cout << "\nSpeed tests" << endl;
  cout << "-----------" << endl;

  double diff;
  size_t N = 500000;
  nodes.clear();
  for (size_t i = 0; i < N; ++i) {
    std::vector<double> point(2);
    point[0] = (double)rand() / RAND_MAX;
    point[1] = (double)rand() / RAND_MAX;
    nodes.push_back(Kdtree::KdNode(point));
  }
  
  // 2.1) build time
  clock_t begin = clock();
  Kdtree::KdTree tree2(&nodes);
  clock_t end = clock();
  diff = double(end - begin) / CLOCKS_PER_SEC;
  cout << "Creation time for " << N << " random points:\n  " << diff << "s" << endl;

  // 2.2) one kNN query
  test_point[0] = (double)rand() / RAND_MAX;
  test_point[1] = (double)rand() / RAND_MAX;
  begin = clock();
  tree.k_nearest_neighbors(test_point, 3, &result);
  end = clock();
  diff = double(end - begin) / CLOCKS_PER_SEC;
  cout << "3NN search time for one random point:\n  " << diff << "s" << endl;

  // 2.3) all NN query
  begin = clock();
  for (size_t i = 0; i < N; ++i) {
    std::vector<double> point(2);
    tree.k_nearest_neighbors(nodes[i].point, 2, &result);
  }
  end = clock();
  diff = double(end - begin) / CLOCKS_PER_SEC;
  cout << "Time for all nearest neighbor search:\n  " << diff << "s" << endl;

  // 2.4) range query
  double r = 0.3;
  begin = clock();
  tree.range_nearest_neighbors(test_point, r, &result);
  end = clock();
  diff = double(end - begin) / CLOCKS_PER_SEC;
  cout << "Range search time for one random point (r=" << r << "):\n  " << diff << endl;

  // 2.5) for comparison: loop version
  std::vector<Kdtree::CoordPoint> res;
  begin = clock();
  for (size_t i = 0; i < N; ++i) {
    if ((nodes[i].point[0] - test_point[0]) *
        (nodes[i].point[0] - test_point[0]) +
        (nodes[i].point[1] - test_point[1]) *
        (nodes[i].point[1] - test_point[1]) < r * r)
        res.push_back(nodes[i].point);
    }
    end = clock();
    diff = double(end - begin) / CLOCKS_PER_SEC;
    cout << "Loop version of a single range search for comparison:\n  " << diff << "s" << endl;

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x208, %rsp            # imm = 0x208
movq 0x7c11(%rip), %rbx      # 0x9fc8
leaq 0x3c9c(%rip), %rsi      # 0x605a
movq %rbx, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
leaq 0x3c99(%rip), %rsi      # 0x606e
movq %rbx, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
leaq 0x40(%rsp), %rax
andq $0x0, 0x10(%rax)
xorpd %xmm0, %xmm0
movapd %xmm0, (%rax)
pushq $0x8
popq %r13
leaq 0x128(%rsp), %r14
pushq $0x2
popq %r15
leaq 0xb8(%rsp), %r12
leaq 0x3e3a(%rip), %rbx      # 0x6250
pushq $-0x1
popq %rbp
cmpq $0xa8, %r13
je 0x2475
movq %r14, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x2cfe
movapd -0x8(%r13,%rbx), %xmm0
movq 0x128(%rsp), %rax
movupd %xmm0, (%rax)
movq %r12, %rdi
movq %r14, %rsi
xorl %edx, %edx
movl %ebp, %ecx
callq 0x2d50
leaq 0x40(%rsp), %rdi
movq %r12, %rsi
callq 0x30c4
movq %r12, %rdi
callq 0x2fac
movq %r14, %rdi
callq 0x2fac
addq $0x10, %r13
jmp 0x2419
leaq 0xb8(%rsp), %rdi
leaq 0x40(%rsp), %rsi
pushq $0x2
popq %rdx
callq 0x35f4
movq 0x7b37(%rip), %rdi      # 0x9fc8
leaq 0x3bea(%rip), %rsi      # 0x6082
callq 0x20f0
leaq 0x100(%rsp), %rdi
callq 0x22cc
xorpd %xmm0, %xmm0
movapd %xmm0, 0x20(%rsp)
andq $0x0, 0x30(%rsp)
leaq 0x8(%rsp), %rdi
pushq $0x2
popq %rsi
leaq 0x128(%rsp), %rdx
callq 0x2cfe
leaq 0x8(%rsp), %rsi
movq (%rsi), %rax
movapd 0x3b31(%rip), %xmm0     # 0x6010
movupd %xmm0, (%rax)
leaq 0xb8(%rsp), %rdi
pushq $0x3
popq %rdx
leaq 0x20(%rsp), %rcx
xorl %r8d, %r8d
callq 0x39ac
movq 0x7ac6(%rip), %rdi      # 0x9fc8
leaq 0x3b8f(%rip), %rsi      # 0x6098
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd (%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3b32(%rip), %rsi      # 0x6058
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd 0x8(%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3b5b(%rip), %rsi      # 0x60a2
movq %rax, %rdi
callq 0x20f0
leaq 0x20(%rsp), %rdi
callq 0x22cc
leaq 0x80(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x2d8c
leaq 0x764e(%rip), %rax      # 0x9bc0
leaq 0xa0(%rsp), %r14
movq %rax, -0x8(%r14)
xorpd %xmm0, %xmm0
movupd %xmm0, (%r14)
andq $0x0, 0x10(%r14)
leaq 0x80(%rsp), %rsi
movq %r14, %rdi
callq 0x2e52
leaq 0x80(%rsp), %rdi
callq 0x2fac
leaq 0xb8(%rsp), %rdi
leaq 0x8(%rsp), %rsi
pushq $0x3
popq %rdx
leaq 0x20(%rsp), %rcx
leaq 0x98(%rsp), %r8
callq 0x39ac
movq 0x79f6(%rip), %rdi      # 0x9fc8
leaq 0x3abf(%rip), %rsi      # 0x6098
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd (%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3a62(%rip), %rsi      # 0x6058
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd 0x8(%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3a91(%rip), %rsi      # 0x60a8
movq %rax, %rdi
callq 0x20f0
leaq 0x20(%rsp), %rdi
callq 0x22cc
leaq 0x8(%rsp), %rsi
movq (%rsi), %rax
movaps 0x39e8(%rip), %xmm0     # 0x6020
movups %xmm0, (%rax)
leaq 0xb8(%rsp), %rdi
movsd 0x39e5(%rip), %xmm0     # 0x6030
leaq 0x20(%rsp), %rdx
callq 0x3d7c
movq 0x796c(%rip), %rdi      # 0x9fc8
leaq 0x3a65(%rip), %rsi      # 0x60c8
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd (%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x39d8(%rip), %rsi      # 0x6058
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd 0x8(%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3a36(%rip), %rsi      # 0x60d7
movq %rax, %rdi
callq 0x20f0
leaq 0x20(%rsp), %rdi
callq 0x22cc
leaq 0x128(%rsp), %rdi
leaq 0x40(%rsp), %rsi
xorl %edx, %edx
callq 0x35f4
leaq 0x128(%rsp), %rdi
leaq 0x8(%rsp), %rsi
movsd 0x3954(%rip), %xmm0     # 0x6030
leaq 0x20(%rsp), %rdx
callq 0x3d7c
movq 0x78db(%rip), %rdi      # 0x9fc8
leaq 0x39d4(%rip), %rsi      # 0x60c8
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd (%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x3947(%rip), %rsi      # 0x6058
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rsp), %rcx
movsd 0x8(%rcx), %xmm0
movq %rax, %rdi
callq 0x2140
leaq 0x39c0(%rip), %rsi      # 0x60f2
movq %rax, %rdi
callq 0x20f0
leaq 0x20(%rsp), %rdi
callq 0x22cc
movq 0x787d(%rip), %rdi      # 0x9fc8
leaq 0x39c3(%rip), %rsi      # 0x6115
callq 0x20f0
movq %rax, %rdi
callq 0x2070
movq 0x7862(%rip), %rdi      # 0x9fc8
leaq 0x3909(%rip), %rsi      # 0x6076
callq 0x20f0
movq %rax, %rdi
callq 0x2070
leaq 0x40(%rsp), %rbx
movq %rbx, %rdi
callq 0x2dda
movl $0x7a120, %r13d         # imm = 0x7A120
leaq 0x60(%rsp), %r14
pushq $0x2
popq %r15
leaq 0x198(%rsp), %r12
pushq $-0x1
popq %rbp
subq $0x1, %r13
jb 0x281a
movq %r14, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x2cfe
callq 0x2030
cvtsi2sd %eax, %xmm0
movsd 0x3872(%rip), %xmm1     # 0x6038
divsd %xmm1, %xmm0
movq 0x60(%rsp), %rax
movsd %xmm0, (%rax)
callq 0x2030
cvtsi2sd %eax, %xmm0
divsd 0x3854(%rip), %xmm0     # 0x6038
movq 0x60(%rsp), %rax
movsd %xmm0, 0x8(%rax)
movq %r12, %rdi
movq %r14, %rsi
xorl %edx, %edx
movl %ebp, %ecx
callq 0x2d50
movq %rbx, %rdi
movq %r12, %rsi
callq 0x30c4
movq %r12, %rdi
callq 0x2fac
movq %r14, %rdi
callq 0x2fac
jmp 0x27a1
callq 0x20a0
movq %rax, %rbx
leaq 0x198(%rsp), %rdi
leaq 0x40(%rsp), %rsi
pushq $0x2
popq %rdx
callq 0x35f4
callq 0x20a0
movq %rax, %r14
movq 0x7782(%rip), %rdi      # 0x9fc8
leaq 0x38d5(%rip), %rsi      # 0x6122
callq 0x20f0
movl $0x7a120, %esi          # imm = 0x7A120
movq %rax, %rdi
callq 0x20b0
leaq 0x38cf(%rip), %rsi      # 0x6135
movq %rax, %rdi
callq 0x20f0
subq %rbx, %r14
cvtsi2sd %r14, %xmm0
divsd 0x37c2(%rip), %xmm0     # 0x6040
movq %rax, %rdi
callq 0x2140
leaq 0x3893(%rip), %rsi      # 0x6120
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
callq 0x2030
cvtsi2sd %eax, %xmm0
movsd 0x378a(%rip), %xmm1     # 0x6038
divsd %xmm1, %xmm0
leaq 0x8(%rsp), %r14
movq (%r14), %rax
movsd %xmm0, (%rax)
callq 0x2030
cvtsi2sd %eax, %xmm0
divsd 0x3769(%rip), %xmm0     # 0x6038
movq (%r14), %rax
movsd %xmm0, 0x8(%rax)
callq 0x20a0
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
pushq $0x3
popq %rdx
leaq 0x20(%rsp), %rcx
movq %r14, %rsi
xorl %r8d, %r8d
callq 0x39ac
callq 0x20a0
movq %rax, %r14
movq 0x76bf(%rip), %rdi      # 0x9fc8
leaq 0x3838(%rip), %rsi      # 0x6148
callq 0x20f0
subq %rbx, %r14
cvtsi2sd %r14, %xmm0
divsd 0x371b(%rip), %xmm0     # 0x6040
movq %rax, %rdi
callq 0x2140
leaq 0x37ec(%rip), %rsi      # 0x6120
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
xorl %ebx, %ebx
callq 0x20a0
movq %rax, 0x78(%rsp)
leaq 0x60(%rsp), %r14
pushq $0x2
popq %r15
leaq 0x7(%rsp), %r12
leaq 0xb8(%rsp), %r13
leaq 0x20(%rsp), %rbp
cmpq $0x1312d00, %rbx        # imm = 0x1312D00
je 0x29a9
movq %r14, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x2cfe
movq 0x40(%rsp), %rsi
addq %rbx, %rsi
movq %r13, %rdi
movq %r15, %rdx
movq %rbp, %rcx
xorl %r8d, %r8d
callq 0x39ac
movq %r14, %rdi
callq 0x2fac
addq $0x28, %rbx
jmp 0x296b
callq 0x20a0
movq %rax, %r14
movq 0x7610(%rip), %rdi      # 0x9fc8
leaq 0x37b2(%rip), %rsi      # 0x6171
callq 0x20f0
subq 0x78(%rsp), %r14
cvtsi2sd %r14, %xmm0
divsd 0x366a(%rip), %xmm0     # 0x6040
movq %rax, %rdi
callq 0x2140
leaq 0x373b(%rip), %rsi      # 0x6120
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
callq 0x20a0
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
leaq 0x8(%rsp), %rsi
movsd 0x3636(%rip), %xmm0     # 0x6048
leaq 0x20(%rsp), %rdx
callq 0x3d7c
callq 0x20a0
movq %rax, %r14
movq 0x759d(%rip), %rdi      # 0x9fc8
leaq 0x3768(%rip), %rsi      # 0x619a
callq 0x20f0
movsd 0x3609(%rip), %xmm0     # 0x6048
movq %rax, %rdi
callq 0x2140
leaq 0x3654(%rip), %rsi      # 0x60a2
movq %rax, %rdi
callq 0x20f0
subq %rbx, %r14
cvtsi2sd %r14, %xmm0
divsd 0x35da(%rip), %xmm0     # 0x6040
movq %rax, %rdi
callq 0x2140
movq %rax, %rdi
callq 0x2070
xorpd %xmm0, %xmm0
leaq 0x60(%rsp), %r14
movapd %xmm0, (%r14)
andq $0x0, 0x10(%r14)
xorl %r15d, %r15d
callq 0x20a0
movq %rax, %rbx
movsd 0x35b4(%rip), %xmm2     # 0x6050
cmpq $0x1312d00, %r15        # imm = 0x1312D00
je 0x2af0
movq 0x40(%rsp), %rsi
movq (%rsi,%r15), %rax
movq 0x8(%rsp), %rcx
movsd (%rax), %xmm0
subsd (%rcx), %xmm0
movsd 0x8(%rax), %xmm1
subsd 0x8(%rcx), %xmm1
mulsd %xmm1, %xmm1
mulsd %xmm0, %xmm0
addsd %xmm1, %xmm0
ucomisd %xmm0, %xmm2
jbe 0x2aea
addq %r15, %rsi
movq %r14, %rdi
callq 0x2de2
movsd 0x3566(%rip), %xmm2     # 0x6050
addq $0x28, %r15
jmp 0x2a9c
callq 0x20a0
movq %rax, %r14
movq 0x74c9(%rip), %rdi      # 0x9fc8
leaq 0x36bf(%rip), %rsi      # 0x61c5
callq 0x20f0
subq %rbx, %r14
cvtsi2sd %r14, %xmm0
divsd 0x3525(%rip), %xmm0     # 0x6040
movq %rax, %rdi
callq 0x2140
leaq 0x35f6(%rip), %rsi      # 0x6120
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x2070
leaq 0x60(%rsp), %rdi
callq 0x2e0e
leaq 0x198(%rsp), %rdi
callq 0x35a0
leaq 0x128(%rsp), %rdi
callq 0x35a0
leaq 0x98(%rsp), %rdi
callq 0x2cbe
leaq 0x8(%rsp), %rdi
callq 0x2fac
leaq 0x20(%rsp), %rdi
callq 0x2e30
leaq 0xb8(%rsp), %rdi
callq 0x35a0
leaq 0x40(%rsp), %rdi
callq 0x2e30
xorl %eax, %eax
addq $0x208, %rsp            # imm = 0x208
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2c24
jmp 0x2bed
movq %rax, %rbx
movq %r14, %rdi
callq 0x2fac
leaq 0x80(%rsp), %rdi
callq 0x2fac
jmp 0x2c62
jmp 0x2be6
movq %rax, %rbx
jmp 0x2c6c
jmp 0x2c85
movq %rax, %rbx
jmp 0x2c76
jmp 0x2bf4
jmp 0x2c03
movq %rax, %rbx
jmp 0x2c62
jmp 0x2c24
movq %rax, %rbx
jmp 0x2c55
jmp 0x2c03
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x2e0e
jmp 0x2c15
movq %rax, %rbx
jmp 0x2c15
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x2fac
leaq 0x198(%rsp), %rdi
callq 0x35a0
jmp 0x2c48
movq %rax, %rbx
jmp 0x2c48
movq %rax, %rbx
jmp 0x2c3e
movq %rax, %rbx
leaq 0x198(%rsp), %rdi
callq 0x2fac
leaq 0x60(%rsp), %rdi
callq 0x2fac
leaq 0x128(%rsp), %rdi
callq 0x35a0
leaq 0x98(%rsp), %rdi
callq 0x2cbe
leaq 0x8(%rsp), %rdi
callq 0x2fac
leaq 0x20(%rsp), %rdi
callq 0x2e30
leaq 0xb8(%rsp), %rdi
callq 0x35a0
jmp 0x2cac
movq %rax, %rbx
jmp 0x2cac
movq %rax, %rbx
jmp 0x2c9f
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x2fac
leaq 0x128(%rsp), %rdi
callq 0x2fac
leaq 0x40(%rsp), %rdi
callq 0x2e30
movq %rbx, %rdi
callq 0x2180