// File: /workspace/github_cpp_makefile_star2_O2/iu-vail[P]iprimal/iPrimal.cpp
// Function: Primal::DualUpdates(_cell&, std::queue<_tree_node*, std::deque<_tree_node*, std::allocator<_tree_node*>>>&)
int
Primal::DualUpdates(cell& _start_cell, queue<tree_node*>& _bfs){

  // search the epsilon (minimal value) for varibles adjustments
  // it must satisfy 3 conditions: 
  // 1. >=0 in oprt_matrix; 2. in exploited rows; 3. in un-exploited cols

  // define and init epsilon as a largest positive value
  double epsilon = std::numeric_limits<double>::infinity();
  bool updated_epsilon = false;

#ifdef USE_HEAP

  /**** lines below are version using min-heaps, relatively faster ****/
  // search for min epsilon
  for(uint row_index=0; row_index<row_size; row_index++){
    if(exploited_rows.find(row_index) != exploited_rows.end()){
      //expose the first unvisited entry
      while(!min_heaps[row_index].empty()){ 
	if(exploited_cols.find(min_heaps[row_index].top().first) != exploited_cols.end())
	  min_heaps[row_index].pop();
        else
	  break;
      }
      if(!min_heaps[row_index].empty()){
        double cell_val = min_heaps[row_index].top().second + deltas[min_heaps[row_index].top().first] - deltas[GetAssignedCol(row_index)];
        if(cell_val < epsilon){
	  epsilon = cell_val;
          updated_epsilon = true;
        }
      }//if !min
    }//if exploited row
  }//for row_index

  // one more round traversal to find all qualified entries
  queue<cell> tmp_q;
  cell qual_c;
  if(updated_epsilon){
    for(uint row_index=0; row_index<row_size; row_index++)
      if(exploited_rows.find(row_index) != exploited_rows.end()){
        while(!min_heaps[row_index].empty()){ 
	  if(exploited_cols.find(min_heaps[row_index].top().first) != exploited_cols.end()){
            min_heaps[row_index].pop();
          }
          else{
            double cell_val = min_heaps[row_index].top().second + deltas[min_heaps[row_index].top().first] - deltas[GetAssignedCol(row_index)];
            if(fabs(cell_val - epsilon)<DOUBLE_EPSILON){
              qual_c.row_idx = row_index;
	      qual_c.col_idx = min_heaps[row_index].top().first;
              tmp_q.push(qual_c);
	      //this entry will be colored as visited later, so remove it here
	      // and this also expose next available entry for judging
	      min_heaps[row_index].pop();
            }
	    else if( cell_val - epsilon > DOUBLE_EPSILON){
              // stop at encountering the first uncolored entry that > epsilon
	      break;
	    }
            else {
	      cerr<<"Very weired thing happens."<<endl;
	      assert(0);
            }
          }//else
        }//while
      }//if exploited rows
  }//if updated epsilon

#else

  /**** lines below are version NOT using min-heaps, relatively slower ****/
  for(uint row_index=0; row_index<row_size; row_index++)
    if(exploited_rows.find(row_index) != exploited_rows.end())
      for(uint col_index=0; col_index<col_size; col_index++)
        if(exploited_cols.find(col_index) == exploited_cols.end()){
	  //double cell_val = oprt_matrix[row_index][col_index] - deltas[col_index];
	  double cell_val = oprt_matrix[row_index][col_index] + deltas[col_index] - deltas[GetAssignedCol(row_index)];
          if(cell_val > 0 && cell_val < epsilon){
            epsilon = cell_val;
            updated_epsilon = true;
          }
        }

  // one more round traversal to find all qualified entries
  queue<cell> tmp_q;
  cell qual_c;
  if(updated_epsilon){
    for(uint row_index=0; row_index<row_size; row_index++)
      if(exploited_rows.find(row_index) != exploited_rows.end())
        for(uint col_index=0; col_index<col_size; col_index++)
          if(exploited_cols.find(col_index) == exploited_cols.end()){
	    double cell_val = oprt_matrix[row_index][col_index] + deltas[col_index] - deltas[GetAssignedCol(row_index)];
            if(fabs(cell_val - epsilon)<DOUBLE_EPSILON){
              qual_c.row_idx = row_index;
	      qual_c.col_idx = col_index;
              tmp_q.push(qual_c);
            }
          }
  }//if

#endif

  // if found nothing, i.e., all available entries are <=0, leaving a void set
  if(!updated_epsilon)
    epsilon = - (oprt_matrix[_start_cell.row_idx][_start_cell.col_idx] 
		+ deltas[_start_cell.col_idx] - deltas[GetAssignedCol(_start_cell.row_idx)]);
  assert(epsilon > 0 && epsilon < std::numeric_limits<double>::infinity());

  _cout("# epsilon: "<<epsilon<<endl);

  // delta update
  for(uint col_index=0; col_index<col_size; col_index++)
    if(exploited_cols.find(col_index) != exploited_cols.end())
      deltas[col_index] += epsilon;  

  _cout("Updated deltas: "<<endl);
  DisplayVec<double>(deltas);

  vector<double> tmp_d(row_size);
  
  for(uint row_index=0; row_index<row_size; row_index++){
    tmp_d[row_index] = oprt_matrix[row_index][_start_cell.col_idx] + deltas[_start_cell.col_idx] - deltas[GetAssignedCol(row_index)];
  }

  _cout("Updated column ["<<_start_cell.col_idx<<"]:"<<endl);
  DisplayVec<double>(tmp_d);

  double min_d = std::numeric_limits<double>::infinity();
  uint new_start_row = row_size;
  for(uint i=0; i<row_size; i++)
    if(tmp_d[i] < min_d){ 
      min_d = tmp_d[i];
      new_start_row = i;
    }
  assert(new_start_row != row_size);
  _cout("Updated root: ("<<new_start_row<<", "<<_start_cell.col_idx<<")"<<endl);

  //terminate this stage if conditions below occur
  if(min_d >= 0){
    _cout("No loop, but the whole column is feasible!"<<endl);
    swap_loop.clear();

    return 0;
  }
  else if(new_start_row !=(uint)_start_cell.row_idx)
    if(exploited_rows.find(new_start_row) != exploited_rows.end()){
      _cout("Loop already exists!"<<endl);
      //update the starting cell
      _start_cell.row_idx = new_start_row;
      //now search the loop or notify the upper funciton to search it
      assert(asgn_ptrs[new_start_row]!=NULL);
      tree_node* tmp_ptr = asgn_ptrs[new_start_row];
      swap_loop.clear();
      while(tmp_ptr->asgn != -1){
        swap_loop.push_back(tmp_ptr->c);
        tmp_ptr=tmp_ptr->parent;
      }
      //finally append the updated root 
      swap_loop.push_back(_start_cell); 

      return 1;
    }
 
  while(!tmp_q.empty()){
    cell cur_c = tmp_q.front();
    tmp_q.pop();
    tree_node* p_cur_tree_node = asgn_ptrs[cur_c.row_idx];
    _cout("Current dead-end entry is: ("<<p_cur_tree_node->c.row_idx<<", "<<p_cur_tree_node->c.col_idx<<")"<<endl);
/*
    for(uint col_index=0; col_index<col_size; col_index++){
      //if(exploited_cols.find(col_index) == exploited_cols.end() && oprt_matrix[epsilon_row_idx][col_index] == oprt_matrix[epsilon_row_idx][epsilon_col_idx] ){
      if(fabs(oprt_matrix[epsilon_row_idx][col_index] + deltas[col_index] - deltas[GetAssignedCol(epsilon_row_idx)]) < DOUBLE_EPSILON
                && exploited_cols.find(col_index) == exploited_cols.end()
                && col_index != (uint)p_cur_tree_node->c.col_idx){
          //current new cell
          cell cur_c;
          cur_c.row_idx = epsilon_row_idx;
          cur_c.col_idx = col_index;
*/
          _cout("  found a new 0: ("
	  	<<cur_c.row_idx<<", "<<cur_c.col_idx<<")"<<endl);

	  //create a new tree_node
          tree_node* new_tree_node = new tree_node;
	  new_tree_node->c = cur_c;
	  new_tree_node->asgn = 0;
	  new_tree_node->parent = p_cur_tree_node;
          // check if it already has siblings
	  if(p_cur_tree_node->child == NULL){
            p_cur_tree_node->child = new_tree_node;
	    sib_ptrs[cur_c.row_idx] = new_tree_node;
          }
          else{
	    assert(sib_ptrs[cur_c.row_idx] != NULL);
	    sib_ptrs[cur_c.row_idx]->next_sibling = new_tree_node;
	    sib_ptrs[cur_c.row_idx] = new_tree_node;
	  }

	  //push the new cell_node in the BFS queue
	  _bfs.push(new_tree_node);
      //}//if
    //}//for
  }//while tmp_q

  return -1;  // did not form loop, countinue searching outside
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %rdx, 0x50(%rsp)
movq %rsi, (%rsp)
movq %rdi, %rbx
leaq 0x50(%rdi), %r12
leaq 0x58(%rdi), %rax
movq %rax, 0x28(%rsp)
leaq 0x80(%rdi), %r13
leaq 0x88(%rdi), %rbp
movsd 0x5076(%rip), %xmm0     # 0x90b0
movapd %xmm0, 0x30(%rsp)
xorl %ecx, %ecx
leaq 0x58(%rsp), %r14
xorl %r15d, %r15d
movl %ecx, 0x58(%rsp)
cmpl (%rbx), %ecx
jae 0x40fa
movq %r12, %rdi
movq %r14, %rsi
callq 0x591c
cmpq 0x28(%rsp), %rax
je 0x40ab
movl 0x58(%rsp), %ecx
movq 0xe0(%rbx), %rax
movq %rcx, %rdx
shlq $0x5, %rdx
movq (%rax,%rdx), %rsi
cmpq 0x8(%rax,%rdx), %rsi
je 0x40f3
movq %r13, %rdi
callq 0x591c
movl 0x58(%rsp), %ecx
movq %rcx, %rdi
shlq $0x5, %rdi
addq 0xe0(%rbx), %rdi
cmpq %rbp, %rax
je 0x40b1
callq 0x51b2
jmp 0x4068
movl 0x58(%rsp), %ecx
jmp 0x40f3
movq (%rdi), %rax
cmpq 0x8(%rdi), %rax
je 0x40f3
movsd 0x8(%rax), %xmm0
movl (%rax), %eax
movq 0x38(%rbx), %rdx
addsd (%rdx,%rax,8), %xmm0
movq 0xf8(%rbx), %rax
movl (%rax,%rcx,4), %eax
subsd (%rdx,%rax,8), %xmm0
movapd 0x30(%rsp), %xmm1
ucomisd %xmm0, %xmm1
seta %al
orb %al, %r15b
minsd %xmm1, %xmm0
movapd %xmm0, 0x30(%rsp)
incl %ecx
jmp 0x404a
leaq 0x58(%rsp), %rdi
callq 0x51cc
testb $0x1, %r15b
je 0x420e
xorl %ecx, %ecx
leaq 0x58(%rsp), %r15
leaq 0x48(%rsp), %r14
movl %ecx, 0x10(%rsp)
cmpl (%rbx), %ecx
jae 0x4251
movq %r12, %rdi
leaq 0x10(%rsp), %rsi
callq 0x591c
cmpq 0x28(%rsp), %rax
je 0x41f3
movl 0x10(%rsp), %ecx
movq 0xe0(%rbx), %rax
movq %rcx, %rdx
shlq $0x5, %rdx
movq (%rax,%rdx), %rsi
cmpq 0x8(%rax,%rdx), %rsi
je 0x4207
movq %r13, %rdi
callq 0x591c
movl 0x10(%rsp), %ecx
movq %rcx, %rdi
shlq $0x5, %rdi
addq 0xe0(%rbx), %rdi
cmpq %rbp, %rax
je 0x4185
callq 0x51b2
jmp 0x413e
movq (%rdi), %rax
movsd 0x8(%rax), %xmm0
movl (%rax), %eax
movq 0x38(%rbx), %rdx
movq 0xf8(%rbx), %rsi
addsd (%rdx,%rax,8), %xmm0
movl (%rsi,%rcx,4), %esi
subsd (%rdx,%rsi,8), %xmm0
subsd 0x30(%rsp), %xmm0
movapd %xmm0, %xmm1
andpd 0x4f17(%rip), %xmm1     # 0x90d0
movsd 0x4ef7(%rip), %xmm2     # 0x90b8
ucomisd %xmm1, %xmm2
jbe 0x41f9
movl %ecx, 0x48(%rsp)
movl %eax, 0x4c(%rsp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x6d12
movl 0x10(%rsp), %edi
shlq $0x5, %rdi
addq 0xe0(%rbx), %rdi
callq 0x51b2
jmp 0x413e
movl 0x10(%rsp), %ecx
jmp 0x4207
ucomisd 0x4eb7(%rip), %xmm0     # 0x90b8
jbe 0x4507
incl %ecx
jmp 0x411a
movq (%rsp), %rdi
movl (%rdi), %eax
movslq %eax, %rcx
movq 0x38(%rbx), %rdx
movq 0xc8(%rbx), %rsi
imulq $0x18, %rcx, %rcx
movslq 0x4(%rdi), %rdi
movq (%rsi,%rcx), %rcx
movsd (%rcx,%rdi,8), %xmm0
addsd (%rdx,%rdi,8), %xmm0
movq 0xf8(%rbx), %rcx
movl (%rcx,%rax,4), %eax
subsd (%rdx,%rax,8), %xmm0
xorpd 0x4dd1(%rip), %xmm0     # 0x9020
jmp 0x4257
movapd 0x30(%rsp), %xmm0
movapd %xmm0, 0x30(%rsp)
movq %xmm0, %rax
movq %rax, %rcx
btrq $0x3f, %rcx
movabsq $-0x10000000000000, %rdx # imm = 0xFFF0000000000000
addq %rcx, %rdx
shrq $0x35, %rdx
cmpl $0x3ff, %edx            # imm = 0x3FF
setb %cl
testq %rax, %rax
setns %dl
andb %cl, %dl
decq %rax
movabsq $0xfffffffffffff, %rcx  # imm = 0xFFFFFFFFFFFFF
cmpq %rcx, %rax
setb %al
orb %dl, %al
je 0x4541
xorl %ecx, %ecx
leaq 0x10(%rsp), %r14
movl %ecx, 0x10(%rsp)
cmpl 0x4(%rbx), %ecx
jae 0x42e3
movq %r13, %rdi
movq %r14, %rsi
callq 0x591c
movl 0x10(%rsp), %ecx
cmpq %rbp, %rax
je 0x42df
movq 0x38(%rbx), %rax
movsd (%rax,%rcx,8), %xmm0
addsd 0x30(%rsp), %xmm0
movsd %xmm0, (%rax,%rcx,8)
incl %ecx
jmp 0x42ae
movl (%rbx), %esi
leaq 0x10(%rsp), %rdi
leaq 0x40(%rsp), %rdx
callq 0x51e8
movl (%rbx), %eax
movq 0xc8(%rbx), %rcx
movq (%rsp), %rdx
movslq 0x4(%rdx), %rdx
movq 0x38(%rbx), %rsi
movq 0xf8(%rbx), %rdi
movq 0x10(%rsp), %r8
xorl %r9d, %r9d
cmpq %r9, %rax
je 0x4344
movq (%rcx), %r10
movsd (%r10,%rdx,8), %xmm0
addsd (%rsi,%rdx,8), %xmm0
movl (%rdi,%r9,4), %r10d
subsd (%rsi,%r10,8), %xmm0
movsd %xmm0, (%r8,%r9,8)
incq %r9
addq $0x18, %rcx
jmp 0x4318
movsd 0x4d64(%rip), %xmm0     # 0x90b0
movq 0x10(%rsp), %rdx
xorl %esi, %esi
movl %eax, %ecx
cmpq %rsi, %rax
je 0x4373
movsd (%rdx,%rsi,8), %xmm1
ucomisd %xmm1, %xmm0
cmoval %esi, %ecx
minsd %xmm0, %xmm1
incq %rsi
movapd %xmm1, %xmm0
jmp 0x4355
movl %ecx, 0xc(%rsp)
cmpl %eax, %ecx
je 0x4560
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jae 0x43ee
movq (%rsp), %rax
cmpl (%rax), %ecx
je 0x4404
leaq 0xc(%rsp), %rsi
movq %r12, %rdi
callq 0x591c
cmpq 0x28(%rsp), %rax
je 0x4404
movl 0xc(%rsp), %eax
movq (%rsp), %rcx
movl %eax, (%rcx)
movq 0x128(%rbx), %rcx
movq (%rcx,%rax,8), %r14
testq %r14, %r14
je 0x457f
addq $0x110, %rbx            # imm = 0x110
movq %rbx, %rdi
callq 0x518e
cmpl $-0x1, 0x8(%r14)
je 0x44b1
movq %rbx, %rdi
movq %r14, %rsi
callq 0x51a6
movq 0x18(%r14), %r14
jmp 0x43d2
addq $0x110, %rbx            # imm = 0x110
movq %rbx, %rdi
callq 0x518e
xorl %ebx, %ebx
jmp 0x44c0
pushq $0x28
popq %r15
leaq 0x40(%rsp), %r12
movq 0x68(%rsp), %rax
cmpq %rax, 0x88(%rsp)
je 0x44ad
movq (%rax), %r14
leaq 0x58(%rsp), %rdi
callq 0x6f98
movslq %r14d, %r13
movq 0x128(%rbx), %rax
movq (%rax,%r13,8), %rbp
movq %r15, %rdi
callq 0x2220
movq %r14, %xmm0
xorpd %xmm1, %xmm1
movupd %xmm1, 0x10(%rax)
andq $0x0, 0x20(%rax)
movq %xmm0, (%rax)
andl $0x0, 0x8(%rax)
movq %rax, 0x40(%rsp)
movq %rbp, 0x18(%rax)
cmpq $0x0, 0x10(%rbp)
je 0x4488
movq 0x140(%rbx), %rdx
movq (%rdx,%r13,8), %rcx
testq %rcx, %rcx
je 0x44e8
leaq (%rdx,%r13,8), %r13
movq %rax, 0x20(%rcx)
jmp 0x4497
movq %rax, 0x10(%rbp)
shlq $0x3, %r13
addq 0x140(%rbx), %r13
movq %rax, (%r13)
movq 0x50(%rsp), %rdi
movq %r12, %rsi
callq 0x66b6
jmp 0x440d
pushq $-0x1
jmp 0x44bf
movq %rbx, %rdi
movq (%rsp), %rsi
callq 0x51a6
pushq $0x1
popq %rbx
leaq 0x10(%rsp), %rdi
callq 0x3082
leaq 0x58(%rsp), %rdi
callq 0x554e
movl %ebx, %eax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4cb0(%rip), %rdi      # 0x919f
leaq 0x4c01(%rip), %rsi      # 0x90f7
leaq 0x4d01(%rip), %rcx      # 0x91fe
movl $0x285, %edx            # imm = 0x285
callq 0x2150
movq 0x9ae2(%rip), %rdi      # 0xdff0
leaq 0x4cce(%rip), %rsi      # 0x91e3
callq 0x2210
movq %rax, %rdi
callq 0x2120
leaq 0x4d94(%rip), %rdi      # 0x92bd
leaq 0x4bc7(%rip), %rsi      # 0x90f7
leaq 0x4cc7(%rip), %rcx      # 0x91fe
movl $0x201, %edx            # imm = 0x201
callq 0x2150
leaq 0x4cec(%rip), %rdi      # 0x9234
leaq 0x4ba8(%rip), %rsi      # 0x90f7
leaq 0x4ca8(%rip), %rcx      # 0x91fe
movl $0x22e, %edx            # imm = 0x22E
callq 0x2150
leaq 0x4d0e(%rip), %rdi      # 0x9275
leaq 0x4b89(%rip), %rsi      # 0x90f7
leaq 0x4c89(%rip), %rcx      # 0x91fe
movl $0x24a, %edx            # imm = 0x24A
callq 0x2150
leaq 0x4d09(%rip), %rdi      # 0x928f
leaq 0x4b6a(%rip), %rsi      # 0x90f7
leaq 0x4c6a(%rip), %rcx      # 0x91fe
movl $0x25a, %edx            # imm = 0x25A
callq 0x2150
jmp 0x45aa
jmp 0x45aa
jmp 0x45bf
jmp 0x45bf
jmp 0x45aa
jmp 0x45bf
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x3082
jmp 0x45c2
jmp 0x45bf
jmp 0x45bf
jmp 0x45bf
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x554e
movq %rbx, %rdi
callq 0x2390