// File: /workspace/github_cpp_makefile_star2_O1/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 0x40(%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 0x801a
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, (%rsp)
movq 0x70(%rsp), %rcx
movq 0x80(%rsp), %rdx
addq $-0x8, %rdx
cmpq %rdx, %rcx
movq %rbx, 0x98(%rsp)
je 0x4f2e
movq %rax, (%rcx)
addq $0x8, 0x70(%rsp)
jmp 0x4f3b
leaq 0x40(%rsp), %rdi
movq %rsp, %rsi
callq 0x8190
leaq 0x58(%r14), %r12
leaq 0x88(%r14), %r15
leaq 0x50(%r14), %rax
movq %rax, 0xa0(%rsp)
leaq 0x80(%r14), %rax
movq %rax, 0xa8(%rsp)
leaq 0x110(%r14), %rax
movq %rax, 0x28(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x20(%rsp)
movq %r12, 0xb0(%rsp)
movq 0x88(%rsp), %rax
movq %rax, %rcx
subq 0x68(%rsp), %rcx
shrq $0x3, %rcx
cmpq $0x1, %rax
adcq $-0x1, %rcx
shlq $0x6, %rcx
movq 0x70(%rsp), %rdx
subq 0x78(%rsp), %rdx
sarq $0x3, %rdx
addq %rcx, %rdx
movq 0x50(%rsp), %rax
movq 0x60(%rsp), %rcx
movq %rcx, %rsi
subq %rax, %rsi
sarq $0x3, %rsi
addq %rdx, %rsi
je 0x5483
testb $0x1, 0x20(%rsp)
jne 0x5483
movl 0x4(%r14), %edx
imull %edx, %edx
cmpl %edx, 0x30(%rsp)
ja 0x54a6
movq (%rax), %rdx
movq %rdx, (%rsp)
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x5007
addq $0x8, %rax
jmp 0x5039
movq 0x58(%rsp), %rdi
movl $0x200, %esi            # imm = 0x200
callq 0x3260
movq 0x68(%rsp), %rax
leaq 0x8(%rax), %rcx
movq %rcx, 0x68(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x58(%rsp)
leaq 0x200(%rax), %rcx
movq %rcx, 0x60(%rsp)
movq %rax, 0x50(%rsp)
movq (%rsp), %rbp
cmpl $0x1, 0x8(%rbp)
jne 0x524d
movl (%rbp), %eax
movl %eax, 0x8(%rsp)
movq 0xa0(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x7c5c
cmpl $0x0, 0x4(%r14)
je 0x50dd
xorl %ebx, %ebx
movq (%rsp), %rax
movslq (%rax), %rdx
movq 0xc8(%r14), %rcx
leaq (%rdx,%rdx,2), %rsi
movq (%rcx,%rsi,8), %rsi
movsd (%rsi,%rbx,8), %xmm0
ucomisd 0x602f(%rip), %xmm0     # 0xb0c0
jb 0x50d1
movq 0xf8(%r14), %rsi
movl (%rsi,%rdx,4), %edx
cmpq %rdx, %rbx
je 0x50d1
movslq (%rax), %rdi
leaq (%rdi,%rdi,2), %rax
movq (%rcx,%rax,8), %rax
movl %ebx, 0x8(%rsp)
movsd (%rax,%rbx,8), %xmm0
movsd %xmm0, 0x10(%rsp)
shlq $0x5, %rdi
addq 0xe0(%r14), %rdi
leaq 0x8(%rsp), %rsi
callq 0x6fd4
incq %rbx
movl 0x4(%r14), %eax
cmpq %rax, %rbx
jb 0x506e
cmpl $0x0, 0x4(%r14)
je 0x5317
xorl %ebp, %ebp
movq (%rsp), %r13
movl (%r13), %r12d
movslq %r12d, %rbx
movq 0x38(%r14), %rax
movq 0xc8(%r14), %rcx
leaq (%rbx,%rbx,2), %rdx
movq (%rcx,%rdx,8), %rcx
movsd (%rcx,%rbp,8), %xmm0
addsd (%rax,%rbp,8), %xmm0
movq 0xf8(%r14), %rcx
movl (%rcx,%r12,4), %ecx
subsd (%rax,%rcx,8), %xmm0
andpd 0x5fa6(%rip), %xmm0     # 0xb0d0
movsd 0x5f86(%rip), %xmm1     # 0xb0b8
ucomisd %xmm0, %xmm1
jbe 0x5230
movq 0x90(%r14), %rcx
movq %r15, %rax
testq %rcx, %rcx
je 0x5168
movq %r15, %rax
movl 0x20(%rcx), %edx
xorl %esi, %esi
cmpq %rdx, %rbp
cmovbeq %rcx, %rax
seta %sil
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x514e
movq %r15, %rcx
cmpq %r15, %rax
je 0x517d
movl 0x20(%rax), %ecx
cmpq %rcx, %rbp
cmovbq %r15, %rax
movq %rax, %rcx
cmpq %r15, %rcx
jne 0x5230
movl 0x4(%r13), %eax
cmpq %rax, %rbp
je 0x5230
movl $0x28, %edi
callq 0x3250
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq $0x0, 0x20(%rax)
movq %rax, 0x8(%rsp)
movl %r12d, (%rax)
movl %ebp, 0x4(%rax)
movl $0x0, 0x8(%rax)
movq %r13, 0x18(%rax)
cmpq $0x0, 0x10(%r13)
je 0x51e9
movq 0x140(%r14), %rdx
movq (%rdx,%rbx,8), %rcx
testq %rcx, %rcx
je 0x54c7
leaq (%rdx,%rbx,8), %rbx
movq %rax, 0x20(%rcx)
jmp 0x51f8
movq %rax, 0x10(%r13)
shlq $0x3, %rbx
addq 0x140(%r14), %rbx
movq %rax, (%rbx)
movq 0x70(%rsp), %rax
movq 0x80(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x5221
movq 0x8(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x70(%rsp)
jmp 0x5230
leaq 0x40(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x8190
incq %rbp
movl 0x4(%r14), %eax
cmpq %rax, %rbp
jb 0x50ea
movq 0xb0(%rsp), %r12
jmp 0x5317
movl (%r14), %eax
movl $0x0, 0x1c(%rsp)
testq %rax, %rax
je 0x5317
movq 0xf8(%r14), %rcx
movq 0x60(%r14), %rdx
movq 0x90(%r14), %rsi
xorl %ebx, %ebx
movl 0x4(%rbp), %r13d
cmpl %r13d, (%rcx,%rbx,4)
jne 0x5307
movq %r12, %rdi
testq %rdx, %rdx
je 0x52ad
movq %rdx, %r8
movq %r12, %rdi
movl 0x20(%r8), %r9d
xorl %r10d, %r10d
cmpq %r9, %rbx
cmovbeq %r8, %rdi
seta %r10b
movq 0x10(%r8,%r10,8), %r8
testq %r8, %r8
jne 0x5291
movq %r12, %r8
cmpq %r12, %rdi
je 0x52c3
movl 0x20(%rdi), %r8d
cmpq %r8, %rbx
cmovbq %r12, %rdi
movq %rdi, %r8
cmpq %r12, %r8
jne 0x5307
movq %r15, %rdi
testq %rsi, %rsi
je 0x52ef
movq %rsi, %r8
movq %r15, %rdi
xorl %r9d, %r9d
cmpl %r13d, 0x20(%r8)
setb %r9b
cmovaeq %r8, %rdi
movq 0x10(%r8,%r9,8), %r8
testq %r8, %r8
jne 0x52d6
movq %r15, %r8
cmpq %r15, %rdi
je 0x5302
cmpl 0x20(%rdi), %r13d
cmovbq %r15, %rdi
movq %rdi, %r8
cmpq %r15, %r8
je 0x5360
incq %rbx
movl %ebx, 0x1c(%rsp)
cmpq %rax, %rbx
jne 0x5275
movq 0x30(%rsp), %rax
incl %eax
movq %rax, 0x30(%rsp)
movq 0x70(%rsp), %rax
cmpq 0x50(%rsp), %rax
jne 0x4f87
testb $0x1, 0x20(%rsp)
jne 0x4f87
movq %r14, %rdi
movq 0x98(%rsp), %rsi
leaq 0x40(%rsp), %rdx
callq 0x5510
testl %eax, %eax
js 0x4f87
jmp 0x5483
movl $0x28, %edi
callq 0x3250
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rax)
movq $0x0, 0x20(%rax)
movq %rax, 0x8(%rsp)
movl %ebx, (%rax)
movl %r13d, 0x4(%rax)
movl $0x1, 0x8(%rax)
movq %rbp, 0x18(%rax)
movq %rax, 0x10(%rbp)
movq 0x128(%r14), %rcx
movq %rax, (%rcx,%rbx,8)
movq 0x98(%rsp), %rax
cmpl %ebx, (%rax)
jne 0x53ec
movq 0x8(%rsp), %rbx
movq 0x28(%rsp), %rdi
callq 0x709c
cmpl $-0x1, 0x8(%rbx)
je 0x5412
movl $0x18, %edi
callq 0x3250
movq (%rbx), %rcx
movq %rcx, 0x10(%rax)
movq %rax, %rdi
movq 0x28(%rsp), %rsi
callq 0x3040
incq 0x120(%r14)
movq 0x18(%rbx), %rbx
jmp 0x53bb
movq 0x70(%rsp), %rax
movq 0x80(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x5452
movq 0x8(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x70(%rsp)
jmp 0x5461
movl $0x18, %edi
callq 0x3250
movq (%rbx), %rcx
movq %rcx, 0x10(%rax)
movq %rax, %rdi
movq 0x28(%rsp), %rsi
callq 0x3040
incq 0x120(%r14)
movb $0x1, %al
movq %rax, 0x20(%rsp)
movq 0xa0(%rsp), %rdi
leaq 0x1c(%rsp), %rsi
callq 0x7760
jmp 0x5461
leaq 0x40(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x8190
movq (%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x3c(%rsp)
movq 0xa8(%rsp), %rdi
leaq 0x3c(%rsp), %rsi
callq 0x7c5c
jmp 0x5317
leaq 0x40(%rsp), %rdi
callq 0x73d2
movq 0x20(%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 0x9adb(%rip), %rsi      # 0xef98
movq %rax, %rdi
xorl %edx, %edx
callq 0x33b0
leaq 0x5cd1(%rip), %rdi      # 0xb19f
leaq 0x5c22(%rip), %rsi      # 0xb0f7
leaq 0x5ce3(%rip), %rcx      # 0xb1bf
movl $0x157, %edx            # imm = 0x157
callq 0x3150
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
jmp 0x54fa
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x73d2
movq %rbx, %rdi
callq 0x33d0
nop