// File: arinaschwartz[P]KNN-MNIST/knn.cpp
// Function: KNN(MNISTDataset&, MNISTDataset&, unsigned int, unsigned int, bool)
uint32 KNN(MNISTDataset &trainSet, MNISTDataset &testSet, uint32 k, uint32 max, bool verbose)
{    
    uint32 training_length = trainSet.getNumImages();
    const MNISTImage* test_image;
    const MNISTImage* train_image;
    uint8 classifications[max];
    uint32 numCorrect = 0;

    
    for(uint32 i = 0; i < max; i++){
        test_image = testSet.getImage(i);
        priority_queue<distLabel, vector<distLabel>, greater<distLabel> > imgQueue;
        for(uint32 j = 0; j < training_length; j++){
            train_image = trainSet.getImage(j);
            double current_distance = (*test_image).distance(train_image);
            uint8 current_label = (*train_image).getLabel();
            distLabel current_image;
            current_image.first = current_distance;
            current_image.second = current_label;
            imgQueue.push(current_image);
        }
        //Counts label frequency, stores in array by index
        uint32 labelFreq[10];
        for(uint32 iter = 0; iter < k; iter++){
            distLabel neighbor = imgQueue.top();
            labelFreq[neighbor.second] += 1;
            imgQueue.pop();
        }
        uint8 prevailing_label = 0;
        uint8 highest_frequency = 0;
        //Picks the most frequent label
        for(uint8 check_label = 0; check_label < 10; check_label++){
            if(labelFreq[check_label] > highest_frequency){
                prevailing_label = check_label;
            }
            labelFreq[check_label] = 0;
        }
            
        classifications[i] = prevailing_label;
    }

    for(uint32 i = 0; i < max; i++){
        
        if(classifications[i] == (*testSet.getImage(i)).getLabel()){
            numCorrect++;
        }
    }

    return numCorrect;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x130, %rsp            # imm = 0x130
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movl %ecx, -0x18(%rbp)
andb $0x1, %al
movb %al, -0x19(%rbp)
movq -0x8(%rbp), %rdi
callq 0x3eb0
movl %eax, -0x20(%rbp)
movl -0x18(%rbp), %eax
movq %rsp, %rcx
movq %rcx, -0x38(%rbp)
movq %rax, %rdx
addq $0xf, %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0x100(%rbp)
movq %rcx, %rsp
movq %rax, -0x40(%rbp)
movl $0x0, -0x44(%rbp)
movl $0x0, -0x48(%rbp)
movl -0x48(%rbp), %eax
cmpl -0x18(%rbp), %eax
jae 0x4a49
movq -0x10(%rbp), %rdi
movl -0x48(%rbp), %esi
callq 0x3ed0
movq %rax, -0x28(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x4ad0
movl $0x0, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jae 0x494a
movq -0x8(%rbp), %rdi
movl -0x6c(%rbp), %esi
callq 0x3ed0
movq %rax, -0x108(%rbp)
jmp 0x4891
movq -0x108(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movsd %xmm0, -0x110(%rbp)
jmp 0x48b7
movsd -0x110(%rbp), %xmm0
movsd %xmm0, -0x88(%rbp)
movq -0x30(%rbp), %rdi
callq 0x3fe0
movl %eax, -0x114(%rbp)
jmp 0x48d8
movl -0x114(%rbp), %eax
movb %al, -0x89(%rbp)
leaq -0xa0(%rbp), %rdi
callq 0x4b00
jmp 0x48f2
movsd -0x88(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
movb -0x89(%rbp), %al
movb %al, -0x98(%rbp)
leaq -0x68(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x4b20
jmp 0x4920
jmp 0x4922
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x4870
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x4be0
jmp 0x4ac3
movl $0x0, -0xd4(%rbp)
movl -0xd4(%rbp), %eax
cmpl -0x14(%rbp), %eax
jae 0x49b7
leaq -0x68(%rbp), %rdi
callq 0x4b70
movq %rax, -0x120(%rbp)
jmp 0x4971
movq -0x120(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0xf0(%rbp)
movzbl -0xe8(%rbp), %eax
movl -0xd0(%rbp,%rax,4), %ecx
incl %ecx
movl %ecx, -0xd0(%rbp,%rax,4)
leaq -0x68(%rbp), %rdi
callq 0x4b90
jmp 0x49a4
jmp 0x49a6
movl -0xd4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xd4(%rbp)
jmp 0x4954
movb $0x0, -0xf1(%rbp)
movb $0x0, -0xf2(%rbp)
movb $0x0, -0xf3(%rbp)
movzbl -0xf3(%rbp), %eax
cmpl $0xa, %eax
jge 0x4a1f
movzbl -0xf3(%rbp), %eax
movl -0xd0(%rbp,%rax,4), %eax
movzbl -0xf2(%rbp), %ecx
cmpl %ecx, %eax
jbe 0x49fd
movb -0xf3(%rbp), %al
movb %al, -0xf1(%rbp)
movzbl -0xf3(%rbp), %eax
movl $0x0, -0xd0(%rbp,%rax,4)
movb -0xf3(%rbp), %al
addb $0x1, %al
movb %al, -0xf3(%rbp)
jmp 0x49cc
movq -0x100(%rbp), %rax
movb -0xf1(%rbp), %dl
movl -0x48(%rbp), %ecx
movb %dl, (%rax,%rcx)
leaq -0x68(%rbp), %rdi
callq 0x4be0
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x4844
movl $0x0, -0xf8(%rbp)
movl -0xf8(%rbp), %eax
cmpl -0x18(%rbp), %eax
jae 0x4ab4
movq -0x100(%rbp), %rax
movl -0xf8(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl %eax, -0x124(%rbp)
movq -0x10(%rbp), %rdi
movl -0xf8(%rbp), %esi
callq 0x3ed0
movq %rax, %rdi
callq 0x3fe0
movl %eax, %ecx
movl -0x124(%rbp), %eax
cmpl %ecx, %eax
jne 0x4aa1
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x4aa3
movl -0xf8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xf8(%rbp)
jmp 0x4a53
movl -0x44(%rbp), %eax
movq -0x38(%rbp), %rcx
movq %rcx, %rsp
movq %rbp, %rsp
popq %rbp
retq
movq -0x78(%rbp), %rdi
callq 0x3310
nopl (%rax)