// File: tylerwowen[P]movielens/./movielens/main.cpp
// Function: main
int main(int argc, char ** argv) {
  struct arguments args;
  args.method = 0;
  args.matchedOnly = false;
  args.prettyPrint = false;
  args.maxRating = 5;
  
  argp_parse (&argp, argc, argv, 0, 0, &args);
  
  UsersMap trainUsers(args.userNum), testUsers;
  readData(args.trainFile, trainUsers);
  int testSize = readData(args.testFile, testUsers);
  int validTestSize = testSize;

  NeighborsLocator locator(&trainUsers, args.moiveNum, args.k, args.method, args.maxRating);
  double sum = 0, sumSQ = 0;
  int predictedCount = 0;
  int count_not_found = 0;
  if (args.matchedOnly) {
    for (auto& user: testUsers) {
      UsersMap::iterator trainUserItr = trainUsers.find(user.first);
      if (trainUserItr == trainUsers.end()) {
        cout << "not good " << count_not_found++ << " " << user.first << endl;
        validTestSize--;
        continue;
      }
      locator.setTargetUser(user.first, &trainUserItr->second);
      locator.calculateDistancesToNeighbors(args.userNum);
      
      for (auto& rating: user.second.r_list) {
        UsersPtr neighbors = locator.getMatchedKNeighbors(rating.first);
        double actual = rating.second;
        double prediction = getPredication(neighbors, rating.first);
        if (prediction == 0) {
          continue;
        }
        predictedCount++;
        sum += fabs(actual - prediction);
        sumSQ += pow(actual - prediction, 2);
      }
    }
  }
  else {
    for (auto& user: testUsers) {
      UsersMap::iterator trainUserItr = trainUsers.find(user.first);
      if (trainUserItr == trainUsers.end()) {
        cout << "not good\n" ;
        validTestSize--;
        continue;
      }
      locator.setTargetUser(user.first, &trainUserItr->second);
      UsersPtr neighbors = locator.getNeighbors();
      
      for (auto& rating: user.second.r_list) {
        double actual = rating.second;
        double prediction = getPredication(neighbors, rating.first);
        if (prediction == 0) {
          continue;
        }
        predictedCount++;
        sum += fabs(actual - prediction);
        sumSQ += pow(actual - prediction, 2);
      }
    }
  }
  double mae = sum / predictedCount,
  rmse = sqrt(sumSQ / predictedCount),
  recall = (double)predictedCount / (double)validTestSize;
  
  if (args.prettyPrint) {
    cout << "MAE = " << mae << endl;
    cout << "RMSE = " << rmse << endl;
    cout << "Recall = " << recall * 100 << "%" << endl;
  }
  else {
    cout << mae << " " << rmse << " " <<  recall << " ";
  }
  
  exit(0);
}

// Assembly:
subq $0x3a8, %rsp            # imm = 0x3A8
movl $0x0, 0x3a4(%rsp)
movl %edi, 0x3a0(%rsp)
movq %rsi, 0x398(%rsp)
movl $0x0, 0x388(%rsp)
movb $0x0, 0x394(%rsp)
movb $0x0, 0x395(%rsp)
movl $0x5, 0x390(%rsp)
movl 0x3a0(%rsp), %esi
movq 0x398(%rsp), %rdx
leaq 0x10e63(%rip), %rdi     # 0x181d0
xorl %ecx, %ecx
movl %ecx, %r8d
leaq 0x370(%rsp), %r9
callq 0x2050
movslq 0x380(%rsp), %rax
movq %rax, 0xe8(%rsp)
leaq 0x335(%rsp), %rdi
movq %rdi, 0xf0(%rsp)
callq 0x8110
movq 0xe8(%rsp), %rsi
movq 0xf0(%rsp), %r8
leaq 0x338(%rsp), %rdi
leaq 0x337(%rsp), %rdx
leaq 0x336(%rsp), %rcx
callq 0x8120
jmp 0x73d3
leaq 0x335(%rsp), %rdi
callq 0x8160
leaq 0x2e8(%rsp), %rdi
callq 0x8170
movq 0x370(%rsp), %rax
movq %rax, 0xd8(%rsp)
leaq 0x2c7(%rsp), %rdi
movq %rdi, 0xe0(%rsp)
callq 0x2320
movq 0xd8(%rsp), %rsi
movq 0xe0(%rsp), %rdx
leaq 0x2c8(%rsp), %rdi
callq 0x2260
jmp 0x7431
leaq 0x2c8(%rsp), %rdi
leaq 0x338(%rsp), %rsi
callq 0x51d0
jmp 0x7448
leaq 0x2c8(%rsp), %rdi
callq 0x2120
leaq 0x2c7(%rsp), %rdi
callq 0x2200
movq 0x378(%rsp), %rax
movq %rax, 0xc8(%rsp)
leaq 0x29f(%rsp), %rdi
movq %rdi, 0xd0(%rsp)
callq 0x2320
movq 0xc8(%rsp), %rsi
movq 0xd0(%rsp), %rdx
leaq 0x2a0(%rsp), %rdi
callq 0x2260
jmp 0x74a6
leaq 0x2a0(%rsp), %rdi
leaq 0x2e8(%rsp), %rsi
callq 0x51d0
movl %eax, 0xc4(%rsp)
jmp 0x74c4
leaq 0x2a0(%rsp), %rdi
callq 0x2120
leaq 0x29f(%rsp), %rdi
callq 0x2200
movl 0xc4(%rsp), %eax
movl %eax, 0x2c0(%rsp)
movl 0x2c0(%rsp), %eax
movl %eax, 0x298(%rsp)
movl 0x38c(%rsp), %ecx
movl 0x384(%rsp), %edx
movl 0x388(%rsp), %r8d
movl 0x390(%rsp), %r9d
leaq 0x250(%rsp), %rdi
leaq 0x338(%rsp), %rsi
callq 0x93e0
jmp 0x752f
xorps %xmm0, %xmm0
movsd %xmm0, 0x248(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x240(%rsp)
movl $0x0, 0x23c(%rsp)
movl $0x0, 0x238(%rsp)
testb $0x1, 0x394(%rsp)
je 0x7a7c
leaq 0x2e8(%rsp), %rax
movq %rax, 0x230(%rsp)
movq 0x230(%rsp), %rdi
callq 0x5670
movq %rax, 0x228(%rsp)
movq 0x230(%rsp), %rdi
callq 0x56a0
movq %rax, 0x220(%rsp)
leaq 0x228(%rsp), %rdi
leaq 0x220(%rsp), %rsi
callq 0x56d0
testb $0x1, %al
jne 0x75c3
jmp 0x7a77
leaq 0x228(%rsp), %rdi
callq 0x56f0
movq %rax, 0x218(%rsp)
movq 0x218(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x8180
movq %rax, 0xb8(%rsp)
jmp 0x75f7
movq 0xb8(%rsp), %rax
movq %rax, 0x210(%rsp)
leaq 0x338(%rsp), %rdi
callq 0x56a0
movq %rax, 0x208(%rsp)
leaq 0x210(%rsp), %rdi
leaq 0x208(%rsp), %rsi
callq 0x81b0
testb $0x1, %al
jne 0x763a
jmp 0x77d5
movq 0x1098f(%rip), %rdi     # 0x17fd0
leaq 0x99f0(%rip), %rsi      # 0x11038
callq 0x21b0
movq %rax, 0xb0(%rsp)
jmp 0x7657
movq 0xb0(%rsp), %rdi
movl 0x238(%rsp), %esi
movl %esi, %eax
incl %eax
movl %eax, 0x238(%rsp)
callq 0x22e0
movq %rax, 0xa8(%rsp)
jmp 0x7680
movq 0xa8(%rsp), %rdi
leaq 0x99c2(%rip), %rsi      # 0x11051
callq 0x21b0
movq %rax, 0xa0(%rsp)
jmp 0x769e
movq 0xa0(%rsp), %rdi
movq 0x218(%rsp), %rax
movl (%rax), %esi
callq 0x22e0
movq %rax, 0x98(%rsp)
jmp 0x76bf
movq 0x98(%rsp), %rdi
movq 0x108ea(%rip), %rsi     # 0x17fb8
callq 0x21e0
jmp 0x76d5
movl 0x298(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x298(%rsp)
jmp 0x7a65
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
leaq 0x335(%rsp), %rdi
callq 0x8160
jmp 0x7fe4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7748
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
leaq 0x2c8(%rsp), %rdi
callq 0x2120
leaq 0x2c7(%rsp), %rdi
callq 0x2200
jmp 0x7fca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7791
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
leaq 0x2a0(%rsp), %rdi
callq 0x2120
leaq 0x29f(%rsp), %rdi
callq 0x2200
jmp 0x7fca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7fca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7fbd
movq 0x218(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x94(%rsp)
leaq 0x210(%rsp), %rdi
callq 0x5f70
movl 0x94(%rsp), %esi
movq %rax, %rdx
addq $0x8, %rdx
leaq 0x250(%rsp), %rdi
callq 0x9440
jmp 0x7810
movl 0x380(%rsp), %esi
leaq 0x250(%rsp), %rdi
callq 0xb5a0
jmp 0x7826
movq 0x218(%rsp), %rax
addq $0x8, %rax
movq %rax, 0x200(%rsp)
movq 0x200(%rsp), %rdi
callq 0x45b0
movq %rax, 0x1f8(%rsp)
movq 0x200(%rsp), %rdi
callq 0x2cd0
movq %rax, 0x1f0(%rsp)
leaq 0x1f8(%rsp), %rdi
leaq 0x1f0(%rsp), %rsi
callq 0x4ce0
testb $0x1, %al
jne 0x7882
jmp 0x7a63
leaq 0x1f8(%rsp), %rdi
callq 0x4d00
movq %rax, 0x1e8(%rsp)
movq 0x1e8(%rsp), %rax
movl (%rax), %edx
leaq 0x1d0(%rsp), %rdi
leaq 0x250(%rsp), %rsi
callq 0xb810
jmp 0x78b8
movq 0x1e8(%rsp), %rax
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x1c8(%rsp)
leaq 0x1a8(%rsp), %rdi
leaq 0x1d0(%rsp), %rsi
callq 0x81d0
jmp 0x78e5
movq 0x1e8(%rsp), %rax
movl (%rax), %esi
leaq 0x1a8(%rsp), %rdi
callq 0x71e0
movsd %xmm0, 0x88(%rsp)
jmp 0x7907
leaq 0x1a8(%rsp), %rdi
callq 0x82d0
movsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x1c0(%rsp)
movsd 0x1c0(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x7989
jp 0x7989
movl $0x5, 0x1a4(%rsp)
jmp 0x7a21
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7a51
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
leaq 0x1a8(%rsp), %rdi
callq 0x82d0
jmp 0x7a51
movl 0x23c(%rsp), %eax
incl %eax
movl %eax, 0x23c(%rsp)
movsd 0x1c8(%rsp), %xmm1
movsd 0x1c0(%rsp), %xmm0
subsd %xmm0, %xmm1
movaps 0x966a(%rip), %xmm0     # 0x11020
pand %xmm0, %xmm1
movsd 0x248(%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x248(%rsp)
movsd 0x1c8(%rsp), %xmm0
movsd 0x1c0(%rsp), %xmm1
subsd %xmm1, %xmm0
movl $0x2, %edi
callq 0x8330
movsd %xmm0, 0x80(%rsp)
jmp 0x79fb
movsd 0x80(%rsp), %xmm0
addsd 0x240(%rsp), %xmm0
movsd %xmm0, 0x240(%rsp)
movl $0x0, 0x1a4(%rsp)
leaq 0x1d0(%rsp), %rdi
callq 0x82d0
movl 0x1a4(%rsp), %eax
testl %eax, %eax
je 0x7a3d
jmp 0x7a3b
jmp 0x7a3f
jmp 0x7a3f
leaq 0x1f8(%rsp), %rdi
callq 0x4920
jmp 0x7864
leaq 0x1d0(%rsp), %rdi
callq 0x82d0
jmp 0x7fbd
jmp 0x7a65
leaq 0x228(%rsp), %rdi
callq 0x5710
jmp 0x75a5
jmp 0x7db6
leaq 0x2e8(%rsp), %rax
movq %rax, 0x198(%rsp)
movq 0x198(%rsp), %rdi
callq 0x5670
movq %rax, 0x190(%rsp)
movq 0x198(%rsp), %rdi
callq 0x56a0
movq %rax, 0x188(%rsp)
leaq 0x190(%rsp), %rdi
leaq 0x188(%rsp), %rsi
callq 0x56d0
testb $0x1, %al
jne 0x7ad4
jmp 0x7db4
leaq 0x190(%rsp), %rdi
callq 0x56f0
movq %rax, 0x180(%rsp)
movq 0x180(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x8180
movq %rax, 0x78(%rsp)
jmp 0x7b05
movq 0x78(%rsp), %rax
movq %rax, 0x178(%rsp)
leaq 0x338(%rsp), %rdi
callq 0x56a0
movq %rax, 0x170(%rsp)
leaq 0x178(%rsp), %rdi
leaq 0x170(%rsp), %rsi
callq 0x81b0
testb $0x1, %al
jne 0x7b42
jmp 0x7b6d
movq 0x10487(%rip), %rdi     # 0x17fd0
leaq 0x94f2(%rip), %rsi      # 0x11042
callq 0x21b0
jmp 0x7b57
movl 0x298(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x298(%rsp)
jmp 0x7d90
movq 0x180(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x74(%rsp)
leaq 0x178(%rsp), %rdi
callq 0x5f70
movl 0x74(%rsp), %esi
movq %rax, %rdx
addq $0x8, %rdx
leaq 0x250(%rsp), %rdi
callq 0x9440
jmp 0x7ba2
leaq 0x158(%rsp), %rdi
leaq 0x250(%rsp), %rsi
callq 0x9470
jmp 0x7bb9
movq 0x180(%rsp), %rax
addq $0x8, %rax
movq %rax, 0x150(%rsp)
movq 0x150(%rsp), %rdi
callq 0x45b0
movq %rax, 0x148(%rsp)
movq 0x150(%rsp), %rdi
callq 0x2cd0
movq %rax, 0x140(%rsp)
leaq 0x148(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x4ce0
testb $0x1, %al
jne 0x7c15
jmp 0x7d83
leaq 0x148(%rsp), %rdi
callq 0x4d00
movq %rax, 0x138(%rsp)
movq 0x138(%rsp), %rax
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x130(%rsp)
leaq 0x110(%rsp), %rdi
leaq 0x158(%rsp), %rsi
callq 0x81d0
jmp 0x7c57
movq 0x138(%rsp), %rax
movl (%rax), %esi
leaq 0x110(%rsp), %rdi
callq 0x71e0
movsd %xmm0, 0x68(%rsp)
jmp 0x7c76
leaq 0x110(%rsp), %rdi
callq 0x82d0
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x128(%rsp)
movsd 0x128(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x7cea
jp 0x7cea
jmp 0x7d71
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
jmp 0x7da2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x328(%rsp)
movl %eax, 0x324(%rsp)
leaq 0x110(%rsp), %rdi
callq 0x82d0
jmp 0x7da2
movl 0x23c(%rsp), %eax
incl %eax
movl %eax, 0x23c(%rsp)
movsd 0x130(%rsp), %xmm1
movsd 0x128(%rsp), %xmm0
subsd %xmm0, %xmm1
movaps 0x9309(%rip), %xmm0     # 0x11020
pand %xmm0, %xmm1
movsd 0x248(%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x248(%rsp)
movsd 0x130(%rsp), %xmm0
movsd 0x128(%rsp), %xmm1
subsd %xmm1, %xmm0
movl $0x2, %edi
callq 0x8330
movsd %xmm0, 0x60(%rsp)
jmp 0x7d59
movsd 0x60(%rsp), %xmm0
addsd 0x240(%rsp), %xmm0
movsd %xmm0, 0x240(%rsp)
leaq 0x148(%rsp), %rdi
callq 0x4920
jmp 0x7bf7
leaq 0x158(%rsp), %rdi
callq 0x82d0
leaq 0x190(%rsp), %rdi
callq 0x5710
jmp 0x7ab6
leaq 0x158(%rsp), %rdi
callq 0x82d0
jmp 0x7fbd
jmp 0x7db6
movsd 0x248(%rsp), %xmm0
cvtsi2sdl 0x23c(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x108(%rsp)
movsd 0x240(%rsp), %xmm0
cvtsi2sdl 0x23c(%rsp), %xmm1
divsd %xmm1, %xmm0
sqrtsd %xmm0, %xmm0
movsd %xmm0, 0x100(%rsp)
cvtsi2sdl 0x23c(%rsp), %xmm0
cvtsi2sdl 0x298(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0xf8(%rsp)
testb $0x1, 0x395(%rsp)
je 0x7f23
movq 0x101a4(%rip), %rdi     # 0x17fd0
leaq 0x9219(%rip), %rsi      # 0x1104c
callq 0x21b0
movq %rax, 0x58(%rsp)
jmp 0x7e3f
movq 0x58(%rsp), %rdi
movsd 0x108(%rsp), %xmm0
callq 0x2340
movq %rax, 0x50(%rsp)
jmp 0x7e59
movq 0x50(%rsp), %rdi
movq 0x10153(%rip), %rsi     # 0x17fb8
callq 0x21e0
jmp 0x7e6c
movq 0x1015d(%rip), %rdi     # 0x17fd0
leaq 0x91d9(%rip), %rsi      # 0x11053
callq 0x21b0
movq %rax, 0x48(%rsp)
jmp 0x7e86
movq 0x48(%rsp), %rdi
movsd 0x100(%rsp), %xmm0
callq 0x2340
movq %rax, 0x40(%rsp)
jmp 0x7ea0
movq 0x40(%rsp), %rdi
movq 0x1010c(%rip), %rsi     # 0x17fb8
callq 0x21e0
jmp 0x7eb3
movq 0x10116(%rip), %rdi     # 0x17fd0
leaq 0x919a(%rip), %rsi      # 0x1105b
callq 0x21b0
movq %rax, 0x38(%rsp)
jmp 0x7ecd
movq 0x38(%rsp), %rdi
movsd 0xf8(%rsp), %xmm0
movsd 0x914d(%rip), %xmm1     # 0x11030
mulsd %xmm1, %xmm0
callq 0x2340
movq %rax, 0x30(%rsp)
jmp 0x7ef3
movq 0x30(%rsp), %rdi
leaq 0x9166(%rip), %rsi      # 0x11065
callq 0x21b0
movq %rax, 0x28(%rsp)
jmp 0x7f0b
movq 0x28(%rsp), %rdi
movq 0x100a1(%rip), %rsi     # 0x17fb8
callq 0x21e0
jmp 0x7f1e
jmp 0x7fb6
movsd 0x108(%rsp), %xmm0
movq 0x1009d(%rip), %rdi     # 0x17fd0
callq 0x2340
movq %rax, 0x20(%rsp)
jmp 0x7f3f
movq 0x20(%rsp), %rdi
leaq 0x9106(%rip), %rsi      # 0x11051
callq 0x21b0
movq %rax, 0x18(%rsp)
jmp 0x7f57
movq 0x18(%rsp), %rdi
movsd 0x100(%rsp), %xmm0
callq 0x2340
movq %rax, 0x10(%rsp)
jmp 0x7f71
movq 0x10(%rsp), %rdi
leaq 0x90d4(%rip), %rsi      # 0x11051
callq 0x21b0
movq %rax, 0x8(%rsp)
jmp 0x7f89
movq 0x8(%rsp), %rdi
movsd 0xf8(%rsp), %xmm0
callq 0x2340
movq %rax, (%rsp)
jmp 0x7fa2
movq (%rsp), %rdi
leaq 0x90a4(%rip), %rsi      # 0x11051
callq 0x21b0
jmp 0x7fb4
jmp 0x7fb6
xorl %edi, %edi
callq 0x2210
leaq 0x250(%rsp), %rdi
callq 0x8360
leaq 0x2e8(%rsp), %rdi
callq 0x8380
leaq 0x338(%rsp), %rdi
callq 0x8380
movq 0x328(%rsp), %rdi
callq 0x2310
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)