// File: /workspace/github_cpp_makefile_star2_O3/canzarlab[P]Trajan/geno/lineSearch.cpp
// Function: dcsrch(double&, double&, double&, double, double, double, double, double, TaskType&, TMPContainer&)
void dcsrch(double & f,
            double & g,
            double & stp,
            double const ftol,
            double const gtol,
            double const xtol,
            double const stpmin,
            double const stpmax,
            TaskType & task, TMPContainer& TCON) {
  double const zero = 0.0,
               p5   = 0.5,
               p66  = 0.66,
               xtrapl = 1.1,
               xtrapu = 4.0;
  //static bool brackt;
  //static int stage;
  //static double finit, fx, fy, ginit,gtest, gx, gy,
  //              stx,sty,stmin,stmax,width,width1;
  double ftest,fm,fxm,fym, gm,gxm,gym;

      if (task == TaskType::START) {

//       Check the input arguments for errors.

         if (stp < stpmin) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: STP < STPMIN" << std::endl;
         }
         if (stp > stpmax) {
          //task = TaskType::ERROR;
          stp = stpmax;
          std::cerr << "ERROR: STP > STPMAX" << std::endl;
         } 
         if (g >= zero) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: INITIAL G >= ZERO" << std::endl;
         }
         if (ftol < zero) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: FTOL < ZERO" << std::endl;
         }
         if (gtol < zero) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: GTOL < ZERO" << std::endl;
         }
         if (xtol < zero) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: XTOL < ZERO" << std::endl;
         }
         if (stpmin < zero) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: STPMIN < ZERO" << std::endl;
         }
         if (stpmax < stpmin) {
          task = TaskType::ERROR;
          std::cerr << "ERROR: STPMAX < STPMIN" << std::endl;
         }

//        Exit if there are errors on input.

         if (task == TaskType::ERROR)
          return;

//        Initialize local variables.

         TCON.brackt = false;
         TCON.stage = 1;
         TCON.finit = f;
         TCON.ginit = g;
         TCON.gtest = ftol*TCON.fy;
         TCON.width = stpmax - stpmin;
         TCON.width1 = TCON.width/p5;

//        The variables stx, fx, gx contain the values of the step, 
//        function, and derivative at the best step. 
//        The variables sty, fy, gy contain the value of the step, 
//        function, and derivative at sty.
//        The variables stp, f, g contain the values of the step, 
//        function, and derivative at stp.

         TCON.stx = zero;
         TCON.fx = TCON.finit;
         TCON.gx = TCON.ginit;
         TCON.sty = zero;
         TCON.fy = TCON.finit;
         TCON.gy = TCON.ginit;
         TCON.stmin = zero;
         TCON.stmax = stp + xtrapu*stp;
         task = TaskType::FG;

         return;

      }

//     If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the
//     algorithm enters the second stage.

      ftest = TCON.finit + stp*TCON.gtest;
      if (TCON.stage == 1 && f <= ftest && g >= zero) 
        TCON.stage = 2;

//     Test for warnings.

      if (TCON.brackt && (stp <= TCON.stmin || stp >= TCON.stmax)) {
        task = TaskType::WARNING;
//        std::cerr << "ROUNDING ERRORS PREVENT PROGRESS\n";
      }
      if (TCON.brackt && TCON.stmax - TCON.stmin <= xtol*TCON.stmax) {
        task = TaskType::WARNING;
//        std::cerr << "XTOL TEST SATISFIED\n";
      }
      if (stp == stpmax && f <= ftest && g <= TCON.gtest) {
        task = TaskType::WARNING;
//        std::cerr << "STP = STPMAX\n";
      }
      if (stp == stpmin && (f > ftest || g >= TCON.gtest)) {
        task = TaskType::WARNING;
//        std::cerr << "STP = STPMIN\n";
      }
//     Test for convergence.

/*
      printf("f = %15.15g \n", f);
      printf("ftest = %15.15g\n", ftest);
      std::cout << "f " << f << std::endl;
      std::cout << "ftest " << ftest << std::endl;
      std::cout << "fabs(g) " << std::fabs(g) << std::endl;
      std::cout << "gtol*ginit " << gtol * (-ginit) << std::endl;
*/
//      if (f <= ftest && std::fabs(g) <= gtol * (-TCON.ginit))
      double eps = 1E-6;
      if (f <= ftest + eps*(std::fabs(ftest) + 1) && std::fabs(g) <= gtol * (-TCON.ginit)) 
        task = TaskType::CONVERGENCE;

//     Test for termination.

      if (task == TaskType::WARNING || task == TaskType::CONVERGENCE)
        return;

//     A modified function is used to predict the step during the
//     first TCON.stage if a lower function value has been obtained but 
//     the decrease is not sufficient.

      if (TCON.stage == 1 && f <= TCON.fx && f > ftest) {
//        Define the modified function and derivative values.
         fm = f - stp*TCON.gtest;
         fxm = TCON.fx - TCON.stx*TCON.gtest;
         fym = TCON.fy - TCON.sty*TCON.gtest;
         gm = g - TCON.gtest;
         gxm = TCON.gx - TCON.gtest;
         gym = TCON.gy - TCON.gtest;
//        Call dcstep to update stx, sty, and to compute the new step.
//	 std::cout << "called dcstep 1" << std::endl;
         dcstep(TCON.stx,fxm,gxm,TCON.sty,fym,gym,stp,fm,gm,TCON.brackt,TCON.stmin,TCON.stmax);
//        Reset the function and derivative values for f.
         TCON.fx = fxm + TCON.stx*TCON.gtest;
         TCON.fy = fym + TCON.sty*TCON.gtest;
         TCON.gx = gxm + TCON.gtest;
         TCON.gy = gym + TCON.gtest;
      } else {

//       Call dcstep to update stx, sty, and to compute the new step.
//	std::cout << "called dcstep 2" << std::endl;
        dcstep(TCON.stx,TCON.fx,TCON.gx,TCON.sty,TCON.fy,TCON.gy,stp,f,g,TCON.brackt,TCON.stmin,TCON.stmax);
	//	std::cout << "stx = " << stx << std::endl;
	//	std::cout << "fx  = " << fx << std::endl;
	//	std::cout << "gx  = " << gx << std::endl;
	//	std::cout << "sty = " << sty << std::endl;
	//	std::cout << "fy  = " << fy << std::endl;
	//	std::cout << "gy  = " << gy << std::endl;
	//	std::cout << "stp = " << stp << std::endl;
	//	std::cout << "f   = " << f << std::endl;
	//	std::cout << "g   = " << g << std::endl;
	//	std::cout << "stmin = " << stmin << std::endl;
	//	std::cout << "stmax = " << stmax << std::endl;
      }
//     Decide if a bisection step is needed.

      if (TCON.brackt) {
	//	std::cout << "brackt true" << std::endl;
         if (std::fabs(TCON.sty-TCON.stx) >= p66*TCON.width1) stp = TCON.stx + p5*(TCON.sty - TCON.stx);
         TCON.width1 = TCON.width;
         TCON.width = std::fabs(TCON.sty-TCON.stx);
      }

//     Set the minimum and maximum steps allowed for stp.

      if (TCON.brackt) {
         TCON.stmin = std::min(TCON.stx,TCON.sty);
         TCON.stmax = std::max(TCON.stx,TCON.sty);
      } else {
         TCON.stmin = stp + xtrapl*(stp - TCON.stx);
         TCON.stmax = stp + xtrapu*(stp - TCON.stx);
      }
// 
//     Force the step to be within the bounds stpmax and stpmin.
// 
      stp = std::max(stp,stpmin);
      stp = std::min(stp,stpmax);

//     If further progress is not possible, let stp be the best
//     point obtained during the search.

      if ((TCON.brackt && (stp <= TCON.stmin || stp >= TCON.stmax))
          || (TCON.brackt && TCON.stmax-TCON.stmin <= xtol*TCON.stmax)) {
	//	std::cout << "no further progress" << std::endl;
	stp = TCON.stx;
      }

//     Obtain another function and derivative.

      task = TaskType::FG;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %r8, %r14
movq %rcx, %rbx
movsd %xmm2, 0x10(%rsp)
movapd %xmm1, %xmm11
movq %rdx, %r15
movq %rsi, %r13
movq %rdi, %r12
movl (%rcx), %edx
testl %edx, %edx
movsd %xmm3, (%rsp)
je 0x2d68f
movsd (%r15), %xmm5
movsd 0x28(%r14), %xmm2
movapd %xmm5, %xmm10
mulsd %xmm2, %xmm10
movsd 0x8(%r14), %xmm9
addsd %xmm10, %xmm9
movl 0x4(%r14), %eax
movsd (%r13), %xmm1
cmpl $0x1, %eax
jne 0x2d631
ucomisd (%r12), %xmm9
jb 0x2d631
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x2d631
movl $0x2, 0x4(%r14)
movl $0x2, %eax
cmpb $0x1, (%r14)
jne 0x2da01
movsd 0x50(%r14), %xmm0
movsd 0x58(%r14), %xmm6
ucomisd %xmm6, %xmm5
setb %sil
movapd %xmm5, %xmm7
cmpnlepd %xmm0, %xmm7
movapd %xmm6, %xmm8
mulsd 0x10(%rsp), %xmm8
subsd %xmm0, %xmm6
cmpnlepd %xmm8, %xmm6
andpd %xmm7, %xmm6
movd %xmm6, %edi
movl $0x3, %ecx
testb %sil, %dil
cmovnel %edx, %ecx
jne 0x2d685
movl %ecx, (%rbx)
movsd (%rsp), %xmm3
jmp 0x2da03
movsd %xmm11, 0x20(%rsp)
movsd %xmm0, 0x18(%rsp)
movsd (%r15), %xmm0
ucomisd %xmm0, %xmm3
movsd %xmm4, 0x8(%rsp)
jbe 0x2d701
movl $0x1, (%rbx)
movq 0x58936(%rip), %rbp     # 0x85ff0
leaq 0x405cf(%rip), %rsi     # 0x6dc90
movl $0x13, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
movsd 0x8(%rsp), %xmm4
movsd (%r15), %xmm0
ucomisd %xmm4, %xmm0
jbe 0x2d74f
movsd %xmm4, (%r15)
movq 0x588dd(%rip), %rbp     # 0x85ff0
leaq 0x4058a(%rip), %rsi     # 0x6dca4
movl $0x13, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
movsd (%r13), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jb 0x2d7ac
movl $0x1, (%rbx)
movq 0x58884(%rip), %rbp     # 0x85ff0
leaq 0x40545(%rip), %rsi     # 0x6dcb8
movl $0x18, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
xorpd %xmm1, %xmm1
ucomisd 0x18(%rsp), %xmm1
jbe 0x2d7fd
movl $0x1, (%rbx)
movq 0x5882f(%rip), %rbp     # 0x85ff0
leaq 0x40509(%rip), %rsi     # 0x6dcd1
movl $0x12, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
xorpd %xmm0, %xmm0
ucomisd 0x20(%rsp), %xmm0
jbe 0x2d856
movl $0x1, (%rbx)
movq 0x587da(%rip), %rbp     # 0x85ff0
leaq 0x404c7(%rip), %rsi     # 0x6dce4
movl $0x12, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
xorpd %xmm0, %xmm0
ucomisd 0x10(%rsp), %xmm0
jbe 0x2d8a7
movl $0x1, (%rbx)
movq 0x58785(%rip), %rbp     # 0x85ff0
leaq 0x40485(%rip), %rsi     # 0x6dcf7
movl $0x12, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
xorpd %xmm0, %xmm0
movsd (%rsp), %xmm3
ucomisd %xmm3, %xmm0
jbe 0x2d904
movl $0x1, (%rbx)
movq 0x5872d(%rip), %rbp     # 0x85ff0
leaq 0x40440(%rip), %rsi     # 0x6dd0a
movl $0x14, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
movsd (%rsp), %xmm3
movsd 0x8(%rsp), %xmm2
ucomisd %xmm2, %xmm3
jbe 0x2d964
movl $0x1, (%rbx)
movq 0x586d3(%rip), %rbp     # 0x85ff0
leaq 0x403fb(%rip), %rsi     # 0x6dd1f
movl $0x16, %edx
movq %rbp, %rdi
callq 0x93b0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x9330
movsbl %al, %esi
movq %rbp, %rdi
callq 0x9040
movq %rax, %rdi
callq 0x9230
movsd (%rsp), %xmm3
movsd 0x8(%rsp), %xmm2
cmpl $0x1, (%rbx)
je 0x2dd23
movb $0x0, (%r14)
movl $0x1, 0x4(%r14)
movsd (%r12), %xmm0
movsd %xmm0, 0x8(%r14)
movsd (%r13), %xmm1
movsd %xmm1, 0x20(%r14)
movsd 0x18(%rsp), %xmm4
mulsd 0x18(%r14), %xmm4
movsd %xmm4, 0x28(%r14)
subsd %xmm3, %xmm2
movsd %xmm2, 0x60(%r14)
addsd %xmm2, %xmm2
movsd %xmm2, 0x68(%r14)
movsd %xmm0, 0x10(%r14)
movsd %xmm1, 0x30(%r14)
xorpd %xmm2, %xmm2
movupd %xmm2, 0x40(%r14)
movsd %xmm0, 0x18(%r14)
movsd %xmm1, 0x38(%r14)
movq $0x0, 0x50(%r14)
movsd (%r15), %xmm0
movsd 0x4029a(%rip), %xmm1    # 0x6dc88
mulsd %xmm0, %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x58(%r14)
jmp 0x2dd1c
movl %edx, %ecx
ucomisd %xmm4, %xmm5
movsd (%r12), %xmm0
jne 0x2da29
jp 0x2da29
ucomisd %xmm0, %xmm9
jb 0x2da29
ucomisd %xmm1, %xmm2
jb 0x2da29
movl $0x3, (%rbx)
movl $0x3, %ecx
ucomisd %xmm3, %xmm5
jne 0x2da49
jp 0x2da49
ucomisd %xmm9, %xmm0
ja 0x2da3e
ucomisd %xmm2, %xmm1
jb 0x2da49
movl $0x3, (%rbx)
movl $0x3, %ecx
movapd 0x2e97f(%rip), %xmm5    # 0x5c3d0
andpd %xmm9, %xmm5
addsd 0x2e99a(%rip), %xmm5    # 0x5c3f8
mulsd 0x40212(%rip), %xmm5    # 0x6dc78
addsd %xmm9, %xmm5
ucomisd %xmm0, %xmm5
jb 0x2da9f
movapd 0x2e957(%rip), %xmm5    # 0x5c3d0
andpd %xmm1, %xmm5
movsd 0x20(%r14), %xmm6
xorpd 0x2e935(%rip), %xmm6    # 0x5c3c0
mulsd %xmm11, %xmm6
movl $0x4, %edx
ucomisd %xmm5, %xmm6
jae 0x2dd21
addl $-0x3, %ecx
cmpl $0x2, %ecx
jb 0x2dd23
movsd %xmm4, 0x8(%rsp)
cmpl $0x1, %eax
jne 0x2dbae
movsd 0x10(%r14), %xmm5
ucomisd %xmm0, %xmm5
jb 0x2dbae
ucomisd %xmm9, %xmm0
jbe 0x2dbae
subsd %xmm10, %xmm0
leaq 0x40(%r14), %rdi
movsd 0x40(%r14), %xmm3
mulsd %xmm2, %xmm3
subsd %xmm3, %xmm5
leaq 0x28(%rsp), %rax
movsd %xmm5, (%rax)
movq %rax, %rsi
movsd 0x18(%r14), %xmm3
leaq 0x48(%r14), %rcx
movsd 0x48(%r14), %xmm4
mulsd %xmm2, %xmm4
subsd %xmm4, %xmm3
leaq 0x40(%rsp), %r13
movsd %xmm3, (%r13)
subsd %xmm2, %xmm1
movsd 0x30(%r14), %xmm3
subsd %xmm2, %xmm3
leaq 0x38(%rsp), %rbp
movsd %xmm3, (%rbp)
movsd 0x38(%r14), %xmm3
subsd %xmm2, %xmm3
leaq 0x30(%rsp), %r12
movsd %xmm3, (%r12)
movsd 0x50(%r14), %xmm2
movsd 0x58(%r14), %xmm3
movq %rbp, %rdx
movq %r13, %r8
movq %r12, %r9
pushq %r14
pushq %r15
callq 0x2ce3c
addq $0x10, %rsp
movupd 0x28(%r14), %xmm0
movupd 0x40(%r14), %xmm1
unpcklpd %xmm0, %xmm0            # xmm0 = xmm0[0,0]
leaq 0x28(%rsp), %rax
movsd (%rax), %xmm2
movhpd (%r13), %xmm2           # xmm2 = xmm2[0],mem[0]
mulpd %xmm0, %xmm1
addpd %xmm2, %xmm1
movupd %xmm1, 0x10(%r14)
movsd (%rbp), %xmm1
movhpd (%r12), %xmm1           # xmm1 = xmm1[0],mem[0]
addpd %xmm0, %xmm1
movupd %xmm1, 0x30(%r14)
jmp 0x2dbdf
leaq 0x40(%r14), %rdi
leaq 0x10(%r14), %rsi
leaq 0x30(%r14), %rdx
leaq 0x48(%r14), %rcx
leaq 0x18(%r14), %r8
leaq 0x38(%r14), %r9
movsd 0x50(%r14), %xmm2
movsd 0x58(%r14), %xmm3
pushq %r14
pushq %r15
callq 0x2ce3c
addq $0x10, %rsp
cmpb $0x1, (%r14)
movsd 0x8(%rsp), %xmm5
movsd (%rsp), %xmm6
jne 0x2dcca
movsd 0x40(%r14), %xmm0
movsd 0x48(%r14), %xmm1
movapd %xmm1, %xmm3
subsd %xmm0, %xmm3
movapd 0x2e7c0(%rip), %xmm2    # 0x5c3d0
andpd %xmm3, %xmm2
movsd 0x68(%r14), %xmm4
mulsd 0x4004e(%rip), %xmm4    # 0x6dc70
ucomisd %xmm4, %xmm2
jb 0x2dc55
mulsd 0x2e7e8(%rip), %xmm3    # 0x5c418
addsd %xmm0, %xmm3
movsd %xmm3, (%r15)
movsd 0x40(%r14), %xmm0
movsd 0x48(%r14), %xmm1
movapd %xmm1, %xmm2
subsd %xmm0, %xmm2
andpd 0x2e77b(%rip), %xmm2    # 0x5c3d0
movsd 0x60(%r14), %xmm3
movsd %xmm3, 0x68(%r14)
movsd %xmm2, 0x60(%r14)
movapd %xmm1, %xmm2
minsd %xmm0, %xmm2
movsd %xmm2, 0x50(%r14)
maxsd %xmm0, %xmm1
movsd %xmm1, 0x58(%r14)
maxsd (%r15), %xmm6
minsd %xmm6, %xmm5
movsd %xmm5, (%r15)
movsd 0x50(%r14), %xmm0
ucomisd %xmm5, %xmm0
jae 0x2dcc2
movsd 0x58(%r14), %xmm1
ucomisd %xmm1, %xmm5
jae 0x2dcc2
movapd %xmm1, %xmm2
subsd %xmm0, %xmm2
movsd 0x10(%rsp), %xmm0
mulsd %xmm1, %xmm0
movl $0x2, %edx
ucomisd %xmm2, %xmm0
jb 0x2dd21
movsd 0x40(%r14), %xmm5
jmp 0x2dd17
movsd (%r15), %xmm0
movsd 0x40(%r14), %xmm1
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
mulsd 0x3ff9b(%rip), %xmm2    # 0x6dc80
addsd %xmm0, %xmm2
movsd %xmm2, 0x50(%r14)
movsd (%r15), %xmm0
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
mulsd 0x3ff84(%rip), %xmm2    # 0x6dc88
addsd %xmm0, %xmm2
movsd %xmm2, 0x58(%r14)
maxsd (%r15), %xmm6
minsd %xmm6, %xmm5
movsd %xmm5, (%r15)
movl $0x2, %edx
movl %edx, (%rbx)
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop