// File: pollo[P]graph-partitioning/partitioners.cpp
// Function: fennel(Graph const&, int, Partition*)
void fennel(const Graph& graph,
            int partitions_number,
            Partition* partition)
{
  const double gamma = 3/2.0;
  const double alfa = graph.get_edges_number() * pow(partitions_number, gamma-1.0) /
    pow(graph.get_nodes_number(), gamma);

  //printf("gamma=%f alfa=%f\n",gamma,alfa);

  const bool with_threshold = true;
  const double v = 1.1;

  /*
    if (with_threshold)
    printf("With threshold set to %f\n",v);
  else
  printf("Without threshold\n");*/

  vector<int> nodes;
  vector<double> partition_score(partitions_number);

  //get random sorted nodes
  graph.get_nodes_randomly(&nodes);

  //initialize partitions
  partition->set_size(nodes.size(), partitions_number);

  int count = 0;

  for (vector<int>::iterator node = nodes.begin();
       node != nodes.end();
       ++node) {

    //initialize partitions score
    for (int i=0; i<partitions_number; i++)
      partition_score[i] = 0;

    int nn = 0;
    //add to partitions score number of neighbors in partition
    for (vector<int>::const_iterator neighbor =
           graph.get_neighbors(*node).begin();
         neighbor != graph.get_neighbors(*node).end();
         ++neighbor)
    {
      int neighbor_partition = partition->get_node_partition(*neighbor);
      if (neighbor_partition >= 0) {
        partition_score[neighbor_partition]++;
        //nn++;
      }
    }

    count ++;
    if (nn>0)
      printf("iteration %d neigh %d\n",count,nn);

    //subtract to partitions score cost function
    for (int i=0; i<partitions_number; i++)
    {
      int partition_size = partition->get_partition_size(i);
      double c = alfa * (pow(partition_size+1, gamma) -
                          pow(partition_size, gamma));
      //double c = alfa * gamma * pow(partition_size,gamma-1);
    if (nn>0)
    {
      printf("partition %d size %d\n",i,partition_size);
      printf("partition %d score %f\n",i,partition_score[i]);
    }
    partition_score[i] -= c;
    if (nn>0)
      printf("partition %d score %f\n",i,partition_score[i]);
    }
    //printf("\n\n");

    //filter out partition above treshold
    vector<pair<double,int> > filtered_partition_score;
    for (int i=0; i<partitions_number; i++)
    {
      //printf("Partition %d, score %f\n",i,partition_score[i]);
      if (partition->get_partition_size(i) <=
          v * graph.get_nodes_number() / ((double)partitions_number) ||
          !with_threshold)
      {
        filtered_partition_score.push_back(pair<double, int>(partition_score[i],
                                                             i));
      }
    }

    //select best partition
    int selected_partition = filtered_partition_score[0].second;
    double score = filtered_partition_score[0].first;
    for (size_t i=1; i<filtered_partition_score.size(); i++)
    {
      if (filtered_partition_score[i].first > score )
      {
        selected_partition = filtered_partition_score[i].second;
        score = filtered_partition_score[i].first;
      }
    }

    if (nn>0)
    printf("Selected partition %d\n",selected_partition);

    //assign node to partition
    partition->set_node_partition(*node, selected_partition);
  }
}

// Assembly:
subq $0x1b8, %rsp            # imm = 0x1B8
movq %rdi, 0x1b0(%rsp)
movl %esi, 0x1ac(%rsp)
movq %rdx, 0x1a0(%rsp)
movabsq $0x3ff8000000000000, %rax # imm = 0x3FF8000000000000
movq %rax, 0x198(%rsp)
movq 0x1b0(%rsp), %rdi
callq 0xa310
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x90(%rsp)
movl 0x1ac(%rsp), %edi
movsd 0x29df(%rip), %xmm0     # 0xc398
callq 0xa320
movaps %xmm0, %xmm1
movsd 0x90(%rsp), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, 0x98(%rsp)
movq 0x1b0(%rsp), %rdi
callq 0xa350
movl %eax, %edi
movsd 0x29b2(%rip), %xmm0     # 0xc3a0
callq 0xa320
movaps %xmm0, %xmm1
movsd 0x98(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x190(%rsp)
movb $0x1, 0x18f(%rsp)
movabsq $0x3ff199999999999a, %rax # imm = 0x3FF199999999999A
movq %rax, 0x180(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x2a30
movslq 0x1ac(%rsp), %rax
movq %rax, 0xa0(%rsp)
leaq 0x14f(%rsp), %rdi
movq %rdi, 0xa8(%rsp)
callq 0xa170
movq 0xa0(%rsp), %rsi
movq 0xa8(%rsp), %rdx
leaq 0x150(%rsp), %rdi
callq 0xa180
jmp 0x9a77
leaq 0x14f(%rsp), %rdi
callq 0xa200
movq 0x1b0(%rsp), %rdi
leaq 0x168(%rsp), %rsi
callq 0x32d0
jmp 0x9a9b
movq 0x1a0(%rsp), %rax
movq %rax, 0x88(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x4560
movq 0x88(%rsp), %rdi
movl %eax, %esi
movl 0x1ac(%rsp), %edx
callq 0x80d0
jmp 0x9ad0
movl $0x0, 0x138(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x3e80
movq %rax, 0x130(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x3eb0
movq %rax, 0x128(%rsp)
leaq 0x130(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x6420
testb $0x1, %al
jne 0x9b23
jmp 0xa11e
movl $0x0, 0x124(%rsp)
movl 0x124(%rsp), %eax
cmpl 0x1ac(%rsp), %eax
jge 0x9bac
movslq 0x124(%rsp), %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
xorps %xmm0, %xmm0
movsd %xmm0, (%rax)
movl 0x124(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x124(%rsp)
jmp 0x9b2e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
leaq 0x14f(%rsp), %rdi
callq 0xa200
jmp 0xa14d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
jmp 0xa140
movl $0x0, 0x120(%rsp)
movq 0x1b0(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x130(%rsp), %rdi
callq 0x5840
movq 0x78(%rsp), %rdi
movl (%rax), %esi
callq 0x3280
movq %rax, 0x80(%rsp)
jmp 0x9be7
movq 0x80(%rsp), %rdi
callq 0x3f50
movq %rax, 0x118(%rsp)
movq 0x1b0(%rsp), %rax
movq %rax, 0x68(%rsp)
leaq 0x130(%rsp), %rdi
callq 0x5840
movq 0x68(%rsp), %rdi
movl (%rax), %esi
callq 0x3280
movq %rax, 0x70(%rsp)
jmp 0x9c29
movq 0x70(%rsp), %rdi
callq 0x3fc0
movq %rax, 0x110(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0x3f80
testb $0x1, %al
jne 0x9c56
jmp 0x9cd0
movq 0x1a0(%rsp), %rax
movq %rax, 0x58(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x3ff0
movq 0x58(%rsp), %rdi
movl (%rax), %esi
callq 0x81a0
movl %eax, 0x64(%rsp)
jmp 0x9c82
movl 0x64(%rsp), %eax
movl %eax, 0x10c(%rsp)
cmpl $0x0, 0x10c(%rsp)
jl 0x9cbc
movslq 0x10c(%rsp), %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
movsd 0x26dc(%rip), %xmm0     # 0xc390
addsd (%rax), %xmm0
movsd %xmm0, (%rax)
jmp 0x9cbe
leaq 0x118(%rsp), %rdi
callq 0x4540
jmp 0x9bfc
movl 0x138(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x138(%rsp)
cmpl $0x0, 0x120(%rsp)
jle 0x9d0b
movl 0x138(%rsp), %esi
movl 0x120(%rsp), %edx
leaq 0x26b0(%rip), %rdi      # 0xc3b0
xorl %eax, %eax
callq 0x2030
jmp 0x9d09
jmp 0x9d0b
movl $0x0, 0x108(%rsp)
movl 0x108(%rsp), %eax
cmpl 0x1ac(%rsp), %eax
jge 0x9ea5
movq 0x1a0(%rsp), %rdi
movl 0x108(%rsp), %esi
callq 0x81d0
movl %eax, 0x54(%rsp)
jmp 0x9d44
movl 0x54(%rsp), %eax
movl %eax, 0x104(%rsp)
movsd 0x190(%rsp), %xmm0
movsd %xmm0, 0x40(%rsp)
movl 0x104(%rsp), %edi
incl %edi
movsd 0x2631(%rip), %xmm0     # 0xc3a0
callq 0xa320
movsd %xmm0, 0x48(%rsp)
jmp 0x9d7c
movl 0x104(%rsp), %edi
movsd 0x2615(%rip), %xmm0     # 0xc3a0
callq 0xa320
movsd %xmm0, 0x38(%rsp)
jmp 0x9d98
movsd 0x40(%rsp), %xmm0
movsd 0x38(%rsp), %xmm2
movsd 0x48(%rsp), %xmm1
subsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, 0xf8(%rsp)
cmpl $0x0, 0x120(%rsp)
jle 0x9e18
movl 0x108(%rsp), %esi
movl 0x104(%rsp), %edx
leaq 0x25ed(%rip), %rdi      # 0xc3c7
xorl %eax, %eax
callq 0x2030
jmp 0x9de3
movl 0x108(%rsp), %eax
movl %eax, 0x34(%rsp)
movslq %eax, %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
movl 0x34(%rsp), %esi
movsd (%rax), %xmm0
leaq 0x25d0(%rip), %rdi      # 0xc3dd
movb $0x1, %al
callq 0x2030
jmp 0x9e16
jmp 0x9e18
movsd 0xf8(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
movslq 0x108(%rsp), %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
movsd 0x28(%rsp), %xmm1
movsd (%rax), %xmm0
subsd %xmm1, %xmm0
movsd %xmm0, (%rax)
cmpl $0x0, 0x120(%rsp)
jle 0x9e8d
movl 0x108(%rsp), %eax
movl %eax, 0x24(%rsp)
movslq %eax, %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
movl 0x24(%rsp), %esi
movsd (%rax), %xmm0
leaq 0x255b(%rip), %rdi      # 0xc3dd
movb $0x1, %al
callq 0x2030
jmp 0x9e8b
jmp 0x9e8d
jmp 0x9e8f
movl 0x108(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x108(%rsp)
jmp 0x9d16
leaq 0xe0(%rsp), %rdi
callq 0xa360
movl $0x0, 0xdc(%rsp)
movl 0xdc(%rsp), %eax
cmpl 0x1ac(%rsp), %eax
jge 0x9fbf
movq 0x1a0(%rsp), %rdi
movl 0xdc(%rsp), %esi
callq 0x81d0
movl %eax, 0x20(%rsp)
jmp 0x9eeb
movl 0x20(%rsp), %eax
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0x1b0(%rsp), %rdi
callq 0xa350
movl %eax, 0x1c(%rsp)
jmp 0x9f0c
movsd 0x10(%rsp), %xmm1
movl 0x1c(%rsp), %eax
cvtsi2sd %eax, %xmm2
movsd 0x2486(%rip), %xmm0     # 0xc3a8
mulsd %xmm2, %xmm0
cvtsi2sdl 0x1ac(%rsp), %xmm2
divsd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
jb 0x9fa7
movslq 0xdc(%rsp), %rsi
leaq 0x150(%rsp), %rdi
callq 0xa210
movq %rax, %rsi
leaq 0xc8(%rsp), %rdi
leaq 0xdc(%rsp), %rdx
callq 0xa3a0
jmp 0x9f68
leaq 0xe0(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0xa370
jmp 0x9f7f
jmp 0x9fa7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0xa410
jmp 0xa140
jmp 0x9fa9
movl 0xdc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xdc(%rsp)
jmp 0x9ebd
leaq 0xe0(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xa3d0
movl 0x8(%rax), %eax
movl %eax, 0xc4(%rsp)
leaq 0xe0(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xa3d0
movsd (%rax), %xmm0
movsd %xmm0, 0xb8(%rsp)
movq $0x1, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
movq %rax, 0x8(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0xa3f0
movq %rax, %rcx
movq 0x8(%rsp), %rax
cmpq %rcx, %rax
jae 0xa0af
movq 0xb0(%rsp), %rsi
leaq 0xe0(%rsp), %rdi
callq 0xa3d0
movsd (%rax), %xmm0
ucomisd 0xb8(%rsp), %xmm0
jbe 0xa094
movq 0xb0(%rsp), %rsi
leaq 0xe0(%rsp), %rdi
callq 0xa3d0
movl 0x8(%rax), %eax
movl %eax, 0xc4(%rsp)
movq 0xb0(%rsp), %rsi
leaq 0xe0(%rsp), %rdi
callq 0xa3d0
movsd (%rax), %xmm0
movsd %xmm0, 0xb8(%rsp)
jmp 0xa096
movq 0xb0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xb0(%rsp)
jmp 0xa004
cmpl $0x0, 0x120(%rsp)
jle 0xa0d2
movl 0xc4(%rsp), %esi
leaq 0x232d(%rip), %rdi      # 0xc3f4
xorl %eax, %eax
callq 0x2030
jmp 0xa0d0
jmp 0xa0d2
movq 0x1a0(%rsp), %rax
movq %rax, (%rsp)
leaq 0x130(%rsp), %rdi
callq 0x5840
movq (%rsp), %rdi
movl (%rax), %esi
movl 0xc4(%rsp), %edx
callq 0x8140
jmp 0xa0ff
leaq 0xe0(%rsp), %rdi
callq 0xa410
leaq 0x130(%rsp), %rdi
callq 0x5810
jmp 0x9af0
leaq 0x150(%rsp), %rdi
callq 0xa230
leaq 0x168(%rsp), %rdi
callq 0x2ad0
addq $0x1b8, %rsp            # imm = 0x1B8
retq
leaq 0x150(%rsp), %rdi
callq 0xa230
leaq 0x168(%rsp), %rdi
callq 0x2ad0
movq 0x140(%rsp), %rdi
callq 0x2270
nopw (%rax,%rax)