// File: /workspace/github_cpp_makefile_star2_O2/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 $0xa8, %rsp
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x58(%rsp), %rdi
callq 0x5172
pushq $0x28
popq %rdi
callq 0x2220
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
andq $0x0, 0x20(%rax)
movq %rbx, 0x40(%rsp)
movq (%rbx), %rcx
movq %rcx, (%rax)
orl $-0x1, 0x8(%rax)
leaq 0x8(%rsp), %rsi
movq %rax, (%rsi)
leaq 0x58(%rsp), %rdi
callq 0x66b6
leaq 0x50(%r14), %r13
leaq 0x58(%r14), %rbx
leaq 0x80(%r14), %r12
leaq 0x88(%r14), %r15
leaq 0x110(%r14), %rax
movq %rax, 0x48(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x10(%rsp)
movq %r15, 0x28(%rsp)
movq %r12, 0x50(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x6752
testq %rax, %rax
je 0x3f6d
testb $0x1, 0x10(%rsp)
jne 0x3f6d
movl 0x4(%r14), %eax
imull %eax, %eax
cmpl %eax, 0x30(%rsp)
ja 0x3f90
movq 0x68(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x8(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x68ea
movq 0x8(%rsp), %rax
cmpl $0x1, 0x8(%rax)
jne 0x3ccc
movl (%rax), %eax
movl %eax, 0x18(%rsp)
movq %r13, %rdi
leaq 0x18(%rsp), %rsi
callq 0x5fc2
xorl %ebp, %ebp
movl 0x4(%r14), %eax
cmpq %rax, %rbp
jae 0x3d33
movq 0x8(%rsp), %rax
movslq (%rax), %rdi
movq 0xc8(%r14), %rax
imulq $0x18, %rdi, %rcx
movq (%rax,%rcx), %rax
movsd (%rax,%rbp,8), %xmm0
ucomisd 0x5429(%rip), %xmm0     # 0x90c0
jb 0x3cc7
movq 0xf8(%r14), %rax
movl (%rax,%rdi,4), %eax
cmpq %rax, %rbp
je 0x3cc7
movl %ebp, 0x18(%rsp)
movsd %xmm0, 0x20(%rsp)
shlq $0x5, %rdi
addq 0xe0(%r14), %rdi
leaq 0x18(%rsp), %rsi
callq 0x5158
incq %rbp
jmp 0x3c66
xorl %ebp, %ebp
movl %ebp, 0x4(%rsp)
cmpl (%r14), %ebp
jae 0x3f20
movl %ebp, %eax
movq 0xf8(%r14), %rcx
movl (%rcx,%rax,4), %eax
movq 0x8(%rsp), %rcx
cmpl 0x4(%rcx), %eax
jne 0x3d2f
movq %r13, %rdi
leaq 0x4(%rsp), %rsi
callq 0x591c
cmpq %rbx, %rax
je 0x3d09
movl 0x4(%rsp), %ebp
jmp 0x3d2f
movq 0x8(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x18(%rsp)
movq %r12, %rdi
leaq 0x18(%rsp), %rsi
callq 0x591c
movl 0x4(%rsp), %ebp
cmpq %r15, %rax
je 0x3e55
incl %ebp
jmp 0x3cce
xorl %ebp, %ebp
movl %ebp, 0x4(%rsp)
cmpl %eax, %ebp
jae 0x3f20
movq 0x8(%rsp), %rax
movl (%rax), %eax
movslq %eax, %rcx
movq 0x38(%r14), %rdx
movq 0xc8(%r14), %rsi
imulq $0x18, %rcx, %rcx
movl %ebp, %edi
movq (%rsi,%rcx), %rcx
movsd (%rcx,%rdi,8), %xmm0
addsd (%rdx,%rdi,8), %xmm0
movq 0xf8(%r14), %rcx
movl (%rcx,%rax,4), %eax
subsd (%rdx,%rax,8), %xmm0
andpd 0x534f(%rip), %xmm0     # 0x90d0
movsd 0x532f(%rip), %xmm1     # 0x90b8
ucomisd %xmm0, %xmm1
jbe 0x3e4a
movq %r12, %rdi
leaq 0x4(%rsp), %rsi
callq 0x591c
movl 0x4(%rsp), %ebp
cmpq %r15, %rax
jne 0x3e4a
movq 0x8(%rsp), %r15
cmpl 0x4(%r15), %ebp
je 0x3e45
movq %rbx, %r12
movq %r13, %rbx
movl (%r15), %r13d
pushq $0x28
popq %rdi
callq 0x2220
movslq %r13d, %rcx
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
andq $0x0, 0x20(%rax)
movl %ecx, (%rax)
movl %ebp, 0x4(%rax)
andl $0x0, 0x8(%rax)
movq %rax, 0x18(%rsp)
movq %r15, 0x18(%rax)
cmpq $0x0, 0x10(%r15)
je 0x3e15
movq 0x140(%r14), %rsi
movq (%rsi,%rcx,8), %rdx
testq %rdx, %rdx
je 0x3fac
leaq (%rsi,%rcx,8), %rcx
movq %rax, 0x20(%rdx)
jmp 0x3e24
movq %rax, 0x10(%r15)
shlq $0x3, %rcx
addq 0x140(%r14), %rcx
movq %rax, (%rcx)
leaq 0x58(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x66b6
movl 0x4(%rsp), %ebp
movq %rbx, %r13
movq %r12, %rbx
movq 0x50(%rsp), %r12
movq 0x28(%rsp), %r15
incl %ebp
movl 0x4(%r14), %eax
jmp 0x3d35
movq 0x8(%rsp), %r15
movl 0x4(%r15), %eax
movl %eax, 0x38(%rsp)
pushq $0x28
popq %rdi
callq 0x2220
andq $0x0, 0x20(%rax)
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq %rax, 0x18(%rsp)
movl %ebp, (%rax)
movl 0x38(%rsp), %ecx
movl %ecx, 0x4(%rax)
movl $0x1, 0x8(%rax)
movq %r15, 0x18(%rax)
movq %rax, 0x10(%r15)
movq 0x128(%r14), %rcx
movq %rax, (%rcx,%rbp,8)
movq 0x40(%rsp), %rax
cmpl (%rax), %ebp
jne 0x3ed2
movq 0x18(%rsp), %rbp
movq 0x48(%rsp), %r15
movq %r15, %rdi
callq 0x518e
cmpl $-0x1, 0x8(%rbp)
je 0x3ee3
movq %r15, %rdi
movq %rbp, %rsi
callq 0x51a6
movq 0x18(%rbp), %rbp
jmp 0x3ebb
leaq 0x58(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x66b6
jmp 0x3f02
movq %r15, %rdi
movq %rbp, %rsi
callq 0x51a6
movb $0x1, %al
movq %rax, 0x10(%rsp)
movq %r13, %rdi
leaq 0x4(%rsp), %rsi
callq 0x596e
movq 0x8(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x3c(%rsp)
movq %r12, %rdi
leaq 0x3c(%rsp), %rsi
callq 0x5fc2
movq 0x28(%rsp), %r15
movq 0x30(%rsp), %rax
incl %eax
movq %rax, 0x30(%rsp)
movq 0x88(%rsp), %rax
cmpq 0x68(%rsp), %rax
jne 0x3c00
testb $0x1, 0x10(%rsp)
jne 0x3c00
movq %r14, %rdi
movq 0x40(%rsp), %rsi
leaq 0x58(%rsp), %rdx
callq 0x3ffa
testl %eax, %eax
js 0x3c00
movq $0x0, 0x10(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x54f6
movq 0x10(%rsp), %rax
andb $0x1, %al
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x4
popq %rdi
callq 0x2130
orl $-0x1, (%rax)
movq 0xa006(%rip), %rsi      # 0xdfa8
movq %rax, %rdi
xorl %edx, %edx
callq 0x2370
leaq 0x51ec(%rip), %rdi      # 0x919f
leaq 0x513d(%rip), %rsi      # 0x90f7
leaq 0x51fe(%rip), %rcx      # 0x91bf
movl $0x157, %edx            # imm = 0x157
callq 0x2150
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
jmp 0x3fe5
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x54f6
movq %rbx, %rdi
callq 0x2390