// File: /workspace/github_cpp_makefile_star2_O3/iu-vail[P]iprimal/iPrimal.cpp
// Function: Primal::SearchSwapLoop(_cell&)
bool
Primal::SearchSwapLoop(cell& _start) {

  //travs.resize(100, 0);

  queue<tree_node*> bfs;  	//used for searching shortest loop
  tree_node* tree_root = new tree_node;  
  tree_root->c = _start;
  tree_root->asgn = -1;

  //vector<double> deltas(col_size, 0);

  //init the current tree_node
  tree_node* p_cur_tree_node = tree_root;
  bfs.push(p_cur_tree_node);
  
  bool found_status = false;
  int dual_update_stat = -1;	//3 cases, can be -1, 0, 1

  uint loop_cnt = 0;
  //continue to search until find a loop or meet a dead end
  while(bfs.size() && !found_status){

    if(loop_cnt++ > col_size*col_size){
      //cout<<" row_size: "<<row_size<<" col_size: "<<col_size<<" loop cnt: "<<loop_cnt<<endl;
      throw EXCEPTION_BROKEN;
    }

    //get the front cell_node and pop it off queue
    p_cur_tree_node = bfs.front();
    bfs.pop();

    // if we are now at an assigned entry, we need to search other feasible
    // entries in the same row
    if(p_cur_tree_node->asgn == 1){
      // record this row as exploited
      exploited_rows.insert(p_cur_tree_node->c.row_idx);

      // create the min_heap on the fly when needed
      for(uint j=0; j<col_size; j++){
        if(oprt_matrix[p_cur_tree_node->c.row_idx][j]>=0 
		&& j!=assignment[p_cur_tree_node->c.row_idx]){
          pair<uint, double> p(j, oprt_matrix[p_cur_tree_node->c.row_idx][j]);
          min_heaps[p_cur_tree_node->c.row_idx].push(p);
        }
      }

      for(uint col_index=0; col_index<col_size; col_index++) {
        // can find multiple satisfying new cell_nodes in a for loop
        // if == 0
        if(fabs(oprt_matrix[p_cur_tree_node->c.row_idx][col_index] + deltas[col_index] - deltas[GetAssignedCol(p_cur_tree_node->c.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 = p_cur_tree_node->c.row_idx;
          cur_c.col_idx = col_index;
          // below is pretty useful for tracking or debugging the process
          _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;
	    //memorize such unique node into sib_ptrs, for quick localization 
	    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 i
    }
    // otherwise we must be at an un-assigned entry,
    // and we need search the col and push the one assigned entry out
    else{
      //in iprimal-v2, below is moved to bottom, in the same col, only one asgned cell need be pushed in Q 
      // record this col as exploited 
      //exploited_cols.insert(p_cur_tree_node->c.col_idx);

      for(uint row_index=0; row_index<row_size; row_index++){
        // can find only one satisfying new cell_node in a for loop
        if(assignment[row_index] == (uint)p_cur_tree_node->c.col_idx
		&& exploited_rows.find(row_index) == exploited_rows.end() 
      		//added in iprimal-v2, in the same col, only one asgned cell need be pushed in Q 
		&& exploited_cols.find((uint)p_cur_tree_node->c.col_idx) == exploited_cols.end() 
		){
          //current new cell
          cell cur_c;
          cur_c.row_idx = row_index;
          cur_c.col_idx = p_cur_tree_node->c.col_idx;
          // below is pretty useful for tracking or debugging the process
          _cout("  .found a new *: ("
	  	<<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 = 1;
	  new_tree_node->parent = p_cur_tree_node;
          p_cur_tree_node->child = new_tree_node;

	  //memorize such unique node into asgn_ptrs, for quick localization 
          asgn_ptrs[row_index] = new_tree_node;

    	  //do a check if the traversal forms a loop
          if(row_index == (uint)_start.row_idx){
	    // get swap loop
	    tree_node* tmp_ptr = new_tree_node;
            swap_loop.clear();
	    while(tmp_ptr->asgn != -1){
              swap_loop.push_back(tmp_ptr->c);
	      tmp_ptr=tmp_ptr->parent;
	    }
            swap_loop.push_back(tmp_ptr->c); // the root

	    // record row as exploited then exit loop, actually unnecessary
            exploited_rows.insert(row_index);

	    found_status = true;
          }
          else{
	    //push the new cell_node in the BFS queue
	    bfs.push(new_tree_node);
          }

          // record this col as exploited
          exploited_cols.insert(p_cur_tree_node->c.col_idx);
          break;	//break this for loop
        }//if
      }//for i
    }//else
    
    // embed the dual update here, to combine iterations into one stage
    if(bfs.empty() && !found_status){
      _cout("BFS queue is empty, need dual update."<<endl);
      dual_update_stat = DualUpdates(_start, bfs);
      // swap loop already found inside the dual updates
      if(dual_update_stat >=0) 
	break;
    }
  }//while

#ifdef DEBUG
  _cout("Exploited rows: ");
  DisplaySet(exploited_rows);

  _cout("          cols: ");
  DisplaySet(exploited_cols);

  DisplayTree(tree_root);

  // the loop should be an even number
  assert( swap_loop.size()%2 == 0 );

  //if(swap_loop.size() && dual_update_stat != 0){
  if(swap_loop.size()){
     _cout("Found shortest loop: ");
     for(list<cell>::reverse_iterator itr=swap_loop.rbegin(); 
		itr!=swap_loop.rend(); itr++){
       _cout("("<<itr->row_idx<<", "<<itr->col_idx<<")->");
     }
     _cout("head"<<endl<<endl);
  }
#endif

  //destroy the tree here
  //travs[_start.col_idx] += DeleteTree(tree_root);
  return found_status;

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %rsi, %rbx
movq %rdi, %r14
xorpd %xmm0, %xmm0
leaq 0x50(%rsp), %rdi
movapd %xmm0, 0x40(%rdi)
movapd %xmm0, 0x30(%rdi)
movapd %xmm0, 0x20(%rdi)
movapd %xmm0, 0x10(%rdi)
movapd %xmm0, (%rdi)
xorl %esi, %esi
callq 0x828e
movl $0x28, %edi
callq 0x3250
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq $0x0, 0x20(%rax)
movq (%rbx), %rcx
movq %rcx, (%rax)
movl $0xffffffff, 0x8(%rax)  # imm = 0xFFFFFFFF
movq %rax, 0x8(%rsp)
movq 0x80(%rsp), %rcx
movq 0x90(%rsp), %rdx
addq $-0x8, %rdx
cmpq %rdx, %rcx
je 0x4f4b
movq %rax, (%rcx)
addq $0x8, 0x80(%rsp)
jmp 0x4f5a
leaq 0x50(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x8404
leaq 0x58(%r14), %rax
movq %rax, 0xa8(%rsp)
leaq 0x88(%r14), %rax
movq %rax, 0x30(%rsp)
leaq 0x50(%r14), %rax
movq %rax, 0xa0(%rsp)
leaq 0x80(%r14), %rax
movq %rax, 0xb0(%rsp)
leaq 0x110(%r14), %rax
movq %rax, 0x38(%rsp)
movq $0x0, 0x40(%rsp)
movq $0x0, 0x10(%rsp)
movq %rbx, (%rsp)
movq 0x98(%rsp), %rax
movq %rax, %rcx
subq 0x78(%rsp), %rcx
shrq $0x3, %rcx
cmpq $0x1, %rax
adcq $-0x1, %rcx
shlq $0x6, %rcx
movq 0x80(%rsp), %rdx
subq 0x88(%rsp), %rdx
sarq $0x3, %rdx
addq %rcx, %rdx
movq 0x60(%rsp), %rax
movq 0x70(%rsp), %rcx
movq %rcx, %rsi
subq %rax, %rsi
sarq $0x3, %rsi
addq %rdx, %rsi
je 0x549d
testb $0x1, 0x10(%rsp)
jne 0x549d
movl 0x4(%r14), %edx
imull %edx, %edx
cmpl %edx, 0x40(%rsp)
ja 0x54c0
movq (%rax), %r12
movq %r12, 0x8(%rsp)
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x5036
addq $0x8, %rax
jmp 0x506d
movq 0x68(%rsp), %rdi
movl $0x200, %esi            # imm = 0x200
callq 0x3260
movq 0x78(%rsp), %rax
leaq 0x8(%rax), %rcx
movq %rcx, 0x78(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x68(%rsp)
leaq 0x200(%rax), %rcx
movq %rcx, 0x70(%rsp)
movq 0x8(%rsp), %r12
movq %rax, 0x60(%rsp)
cmpl $0x1, 0x8(%r12)
jne 0x5271
movl (%r12), %eax
movl %eax, 0x18(%rsp)
movq 0xa0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x7ed8
movl 0x4(%r14), %r13d
testl %r13d, %r13d
je 0x544e
xorl %ebx, %ebx
movq 0x8(%rsp), %rax
movslq (%rax), %rdi
movq 0xc8(%r14), %rax
leaq (%rdi,%rdi,2), %rcx
movq (%rax,%rcx,8), %rax
movsd (%rax,%rbx,8), %xmm0
ucomisd 0x5ff5(%rip), %xmm0     # 0xb0c0
jb 0x50ff
movq 0xf8(%r14), %rax
movl (%rax,%rdi,4), %eax
cmpq %rax, %rbx
je 0x50ff
movl %ebx, 0x18(%rsp)
movsd %xmm0, 0x20(%rsp)
shlq $0x5, %rdi
addq 0xe0(%r14), %rdi
leaq 0x18(%rsp), %rsi
callq 0x6ff2
movl 0x4(%r14), %r13d
incq %rbx
movl %r13d, %eax
cmpq %rax, %rbx
jb 0x50a7
testl %r13d, %r13d
je 0x544e
xorl %r12d, %r12d
movq 0x8(%rsp), %rbp
movl (%rbp), %r15d
movslq %r15d, %rbx
movq 0x38(%r14), %rax
movq 0xc8(%r14), %rcx
leaq (%rbx,%rbx,2), %rdx
movq (%rcx,%rdx,8), %rcx
movsd (%rcx,%r12,8), %xmm0
addsd (%rax,%r12,8), %xmm0
movq 0xf8(%r14), %rcx
movl (%rcx,%r15,4), %ecx
subsd (%rax,%rcx,8), %xmm0
andpd 0x5f77(%rip), %xmm0     # 0xb0d0
movsd 0x5f57(%rip), %xmm1     # 0xb0b8
ucomisd %xmm0, %xmm1
jbe 0x525d
movq 0x90(%r14), %rax
testq %rax, %rax
je 0x51a9
movq 0x30(%rsp), %rcx
movl 0x20(%rax), %edx
xorl %esi, %esi
cmpq %rdx, %r12
cmovbeq %rax, %rcx
seta %sil
movq 0x10(%rax,%rsi,8), %rax
testq %rax, %rax
jne 0x517c
cmpq 0x30(%rsp), %rcx
je 0x51a9
movl 0x20(%rcx), %eax
cmpq %rax, %r12
jae 0x525d
movl 0x4(%rbp), %eax
cmpq %rax, %r12
je 0x525d
movl $0x28, %edi
callq 0x3250
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq $0x0, 0x20(%rax)
movq %rax, 0x18(%rsp)
movl %r15d, (%rax)
movl %r12d, 0x4(%rax)
movl $0x0, 0x8(%rax)
movq %rbp, 0x18(%rax)
cmpq $0x0, 0x10(%rbp)
je 0x520c
movq 0x140(%r14), %rdx
movq (%rdx,%rbx,8), %rcx
testq %rcx, %rcx
je 0x54e1
leaq (%rdx,%rbx,8), %rbx
movq %rax, 0x20(%rcx)
jmp 0x521b
movq %rax, 0x10(%rbp)
shlq $0x3, %rbx
addq 0x140(%r14), %rbx
movq %rax, (%rbx)
movq 0x80(%rsp), %rax
movq 0x90(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x524a
movq 0x18(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x80(%rsp)
jmp 0x525d
leaq 0x50(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x8404
movl 0x4(%r14), %r13d
incq %r12
movl %r13d, %eax
cmpq %rax, %r12
jb 0x5116
jmp 0x544e
movl (%r14), %eax
movl $0x0, 0x2c(%rsp)
testq %rax, %rax
je 0x5452
movq 0xf8(%r14), %rcx
movq 0x60(%r14), %rdx
movq 0x90(%r14), %rsi
movl 0x4(%r12), %ebx
xorl %r13d, %r13d
cmpl %ebx, (%rcx,%r13,4)
jne 0x5315
testq %rdx, %rdx
je 0x52e3
movq %rdx, %r8
movq 0xa8(%rsp), %rdi
movl 0x20(%r8), %r9d
xorl %r10d, %r10d
cmpq %r9, %r13
cmovbeq %r8, %rdi
seta %r10b
movq 0x10(%r8,%r10,8), %r8
testq %r8, %r8
jne 0x52b5
cmpq 0xa8(%rsp), %rdi
je 0x52e3
movl 0x20(%rdi), %edi
cmpq %rdi, %r13
jae 0x5315
testq %rsi, %rsi
je 0x532b
movq %rsi, %r8
movq 0x30(%rsp), %rdi
xorl %r9d, %r9d
cmpl %ebx, 0x20(%r8)
setb %r9b
cmovaeq %r8, %rdi
movq 0x10(%r8,%r9,8), %r8
testq %r8, %r8
jne 0x52f0
cmpq 0x30(%rsp), %rdi
je 0x532b
cmpl 0x20(%rdi), %ebx
jb 0x532b
incq %r13
movl %r13d, 0x2c(%rsp)
cmpq %rax, %r13
jne 0x529f
jmp 0x544e
movl $0x28, %edi
callq 0x3250
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq $0x0, 0x20(%rax)
movq %rax, 0x18(%rsp)
movl %r13d, (%rax)
movl %ebx, 0x4(%rax)
movl $0x1, 0x8(%rax)
movq %r12, 0x18(%rax)
movq %rax, 0x10(%r12)
movq 0x128(%r14), %rcx
movq %rax, (%rcx,%r13,8)
movq (%rsp), %rax
cmpl %r13d, (%rax)
jne 0x53b5
movq 0x18(%rsp), %rbx
movq 0x38(%rsp), %rdi
callq 0x70ae
cmpl $-0x1, 0x8(%rbx)
je 0x53e1
movl $0x18, %edi
callq 0x3250
movq (%rbx), %rcx
movq %rcx, 0x10(%rax)
movq %rax, %rdi
movq 0x38(%rsp), %rsi
callq 0x3040
incq 0x120(%r14)
movq 0x18(%rbx), %rbx
jmp 0x5384
movq 0x80(%rsp), %rax
movq 0x90(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x5421
movq 0x18(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x80(%rsp)
jmp 0x5430
movl $0x18, %edi
callq 0x3250
movq (%rbx), %rcx
movq %rcx, 0x10(%rax)
movq %rax, %rdi
movq 0x38(%rsp), %rsi
callq 0x3040
incq 0x120(%r14)
movb $0x1, %al
movq %rax, 0x10(%rsp)
movq 0xa0(%rsp), %rdi
leaq 0x2c(%rsp), %rsi
callq 0x79e4
jmp 0x5430
leaq 0x50(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x8404
movq 0x8(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x4c(%rsp)
movq 0xb0(%rsp), %rdi
leaq 0x4c(%rsp), %rsi
callq 0x7ed8
movq (%rsp), %rbx
movq 0x40(%rsp), %rax
incl %eax
movq %rax, 0x40(%rsp)
movq 0x80(%rsp), %rax
cmpq 0x60(%rsp), %rax
jne 0x4faf
testb $0x1, 0x10(%rsp)
jne 0x4faf
movq %r14, %rdi
movq %rbx, %rsi
leaq 0x50(%rsp), %rdx
callq 0x552a
testl %eax, %eax
js 0x4faf
movq $0x0, 0x10(%rsp)
leaq 0x50(%rsp), %rdi
callq 0x73f2
movq 0x10(%rsp), %rax
andb $0x1, %al
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x4, %edi
callq 0x3120
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movq 0x9ac1(%rip), %rsi      # 0xef98
movq %rax, %rdi
xorl %edx, %edx
callq 0x33b0
leaq 0x5cd7(%rip), %rdi      # 0xb1bf
leaq 0x5c28(%rip), %rsi      # 0xb117
leaq 0x5ce9(%rip), %rcx      # 0xb1df
movl $0x157, %edx            # imm = 0x157
callq 0x3150
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
jmp 0x5514
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
callq 0x73f2
movq %rbx, %rdi
callq 0x33d0
nop