// File: /workspace/github_cpp_makefile_star2_O2/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
movapd %xmm1, %xmm12
movq %rdx, %r15
movq %rsi, %r13
movq %rdi, %r12
movl (%rcx), %edx
testl %edx, %edx
je 0x2c51d
movsd (%r15), %xmm5
movsd 0x28(%r14), %xmm11
movapd %xmm5, %xmm10
mulsd %xmm11, %xmm10
movsd 0x8(%r14), %xmm9
addsd %xmm10, %xmm9
movl 0x4(%r14), %eax
movsd (%r13), %xmm1
cmpl $0x1, %eax
jne 0x2c4c4
ucomisd (%r12), %xmm9
jb 0x2c4c4
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x2c4c4
pushq $0x2
popq %rax
movl $0x2, 0x4(%r14)
cmpb $0x1, (%r14)
jne 0x2c759
movsd 0x50(%r14), %xmm0
movsd 0x58(%r14), %xmm6
ucomisd %xmm6, %xmm5
setb %sil
movapd %xmm5, %xmm7
cmpnlepd %xmm0, %xmm7
movapd %xmm6, %xmm8
mulsd %xmm2, %xmm8
subsd %xmm0, %xmm6
cmpnlepd %xmm8, %xmm6
andpd %xmm7, %xmm6
movd %xmm6, %edi
pushq $0x3
popq %rcx
testb %sil, %dil
cmovnel %edx, %ecx
jne 0x2c75b
movl %ecx, (%rbx)
jmp 0x2c75b
movsd %xmm0, 0x18(%rsp)
movsd %xmm12, 0x20(%rsp)
movsd %xmm2, 0x10(%rsp)
movsd (%r15), %xmm0
movsd %xmm3, (%rsp)
ucomisd %xmm0, %xmm3
movsd %xmm4, 0x8(%rsp)
jbe 0x2c572
movl $0x1, (%rbx)
movq 0x6aa9d(%rip), %rdi     # 0x96ff0
leaq 0x4029e(%rip), %rsi     # 0x6c7f8
callq 0x9330
movq %rax, %rdi
callq 0x9170
movsd 0x8(%rsp), %xmm4
movsd (%r15), %xmm0
ucomisd %xmm4, %xmm0
jbe 0x2c598
movsd %xmm4, (%r15)
movq 0x6aa6c(%rip), %rdi     # 0x96ff0
leaq 0x40281(%rip), %rsi     # 0x6c80c
callq 0x9330
movq %rax, %rdi
callq 0x9170
movsd (%r13), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jb 0x2c5cd
movl $0x1, (%rbx)
movq 0x6aa3b(%rip), %rdi     # 0x96ff0
leaq 0x40264(%rip), %rsi     # 0x6c820
callq 0x9330
movq %rax, %rdi
callq 0x9170
xorpd %xmm1, %xmm1
ucomisd 0x18(%rsp), %xmm1
jbe 0x2c5f6
movl $0x1, (%rbx)
movq 0x6aa0e(%rip), %rdi     # 0x96ff0
leaq 0x40250(%rip), %rsi     # 0x6c839
callq 0x9330
movq %rax, %rdi
callq 0x9170
xorpd %xmm0, %xmm0
ucomisd 0x20(%rsp), %xmm0
jbe 0x2c627
movl $0x1, (%rbx)
movq 0x6a9e1(%rip), %rdi     # 0x96ff0
leaq 0x40236(%rip), %rsi     # 0x6c84c
callq 0x9330
movq %rax, %rdi
callq 0x9170
xorpd %xmm0, %xmm0
ucomisd 0x10(%rsp), %xmm0
jbe 0x2c650
movl $0x1, (%rbx)
movq 0x6a9b4(%rip), %rdi     # 0x96ff0
leaq 0x4021c(%rip), %rsi     # 0x6c85f
callq 0x9330
movq %rax, %rdi
callq 0x9170
xorpd %xmm0, %xmm0
movsd (%rsp), %xmm3
ucomisd %xmm3, %xmm0
jbe 0x2c685
movl $0x1, (%rbx)
movq 0x6a984(%rip), %rdi     # 0x96ff0
leaq 0x401ff(%rip), %rsi     # 0x6c872
callq 0x9330
movq %rax, %rdi
callq 0x9170
movsd (%rsp), %xmm3
movsd 0x8(%rsp), %xmm2
ucomisd %xmm2, %xmm3
jbe 0x2c6bd
movl $0x1, (%rbx)
movq 0x6a952(%rip), %rdi     # 0x96ff0
leaq 0x401e2(%rip), %rsi     # 0x6c887
callq 0x9330
movq %rax, %rdi
callq 0x9170
movsd (%rsp), %xmm3
movsd 0x8(%rsp), %xmm2
cmpl $0x1, (%rbx)
je 0x2ca77
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)
andq $0x0, 0x50(%r14)
movsd (%r15), %xmm0
movsd 0x400ac(%rip), %xmm1    # 0x6c7f0
mulsd %xmm0, %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x58(%r14)
pushq $0x2
jmp 0x2c9e1
movl %edx, %ecx
ucomisd %xmm4, %xmm5
movsd (%r12), %xmm0
jne 0x2c780
jp 0x2c780
ucomisd %xmm0, %xmm9
jb 0x2c780
ucomisd %xmm1, %xmm11
jb 0x2c780
pushq $0x3
popq %rcx
movl $0x3, (%rbx)
ucomisd %xmm3, %xmm5
jne 0x2c79f
jp 0x2c79f
ucomisd %xmm9, %xmm0
ja 0x2c796
ucomisd %xmm11, %xmm1
jb 0x2c79f
movl $0x3, (%rbx)
pushq $0x3
popq %rcx
movapd 0x24c29(%rip), %xmm5    # 0x513d0
andpd %xmm9, %xmm5
addsd 0x2706c(%rip), %xmm5    # 0x53820
mulsd 0x40024(%rip), %xmm5    # 0x6c7e0
addsd %xmm9, %xmm5
ucomisd %xmm0, %xmm5
jb 0x2c7f0
movapd 0x24c01(%rip), %xmm5    # 0x513d0
movsd 0x20(%r14), %xmm6
xorpd 0x24be3(%rip), %xmm6    # 0x513c0
andpd %xmm1, %xmm5
mulsd %xmm12, %xmm6
ucomisd %xmm5, %xmm6
jae 0x2c9df
addl $-0x3, %ecx
cmpl $0x2, %ecx
jb 0x2ca77
movsd %xmm2, 0x10(%rsp)
movsd %xmm3, (%rsp)
movsd %xmm4, 0x8(%rsp)
cmpl $0x1, %eax
jne 0x2c90d
movsd 0x10(%r14), %xmm5
ucomisd %xmm0, %xmm5
jb 0x2c90d
ucomisd %xmm9, %xmm0
jbe 0x2c90d
subsd %xmm10, %xmm0
leaq 0x40(%r14), %rdi
movsd 0x40(%r14), %xmm3
mulsd %xmm11, %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 %xmm11, %xmm4
subsd %xmm4, %xmm3
leaq 0x40(%rsp), %r13
movsd %xmm3, (%r13)
subsd %xmm11, %xmm1
movsd 0x30(%r14), %xmm3
subsd %xmm11, %xmm3
leaq 0x38(%rsp), %rbp
movsd %xmm3, (%rbp)
movsd 0x38(%r14), %xmm3
subsd %xmm11, %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 0x2bcdc
popq %rax
popq %rcx
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 0x2c93c
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 0x2bcdc
popq %rax
popq %rcx
movb (%r14), %al
cmpb $0x1, %al
movsd 0x8(%rsp), %xmm5
movsd (%rsp), %xmm6
movsd 0x10(%rsp), %xmm7
jne 0x2c9e7
movsd 0x40(%r14), %xmm1
movsd 0x48(%r14), %xmm0
movapd %xmm0, %xmm3
subsd %xmm1, %xmm3
movapd 0x24a5c(%rip), %xmm2    # 0x513d0
andpd %xmm3, %xmm2
movsd 0x68(%r14), %xmm4
mulsd 0x3fe52(%rip), %xmm4    # 0x6c7d8
ucomisd %xmm4, %xmm2
jb 0x2c9b9
mulsd 0x24a6c(%rip), %xmm3    # 0x51400
addsd %xmm1, %xmm3
movsd %xmm3, (%r15)
movsd 0x40(%r14), %xmm1
movsd 0x48(%r14), %xmm0
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
andpd 0x24a17(%rip), %xmm2    # 0x513d0
movsd 0x60(%r14), %xmm3
movsd %xmm3, 0x68(%r14)
movsd %xmm2, 0x60(%r14)
movapd %xmm0, %xmm2
minsd %xmm1, %xmm2
movsd %xmm2, 0x50(%r14)
maxsd %xmm1, %xmm0
jmp 0x2ca25
pushq $0x4
popq %rcx
jmp 0x2ca75
movsd (%r15), %xmm0
movsd 0x40(%r14), %xmm1
movapd %xmm0, %xmm2
subsd %xmm1, %xmm2
mulsd 0x3fde6(%rip), %xmm2    # 0x6c7e8
addsd %xmm0, %xmm2
movsd %xmm2, 0x50(%r14)
movsd (%r15), %xmm2
movapd %xmm2, %xmm0
subsd %xmm1, %xmm0
mulsd 0x3fdcf(%rip), %xmm0    # 0x6c7f0
addsd %xmm2, %xmm0
movsd %xmm0, 0x58(%r14)
maxsd (%r15), %xmm6
minsd %xmm6, %xmm5
movsd %xmm5, (%r15)
pushq $0x2
popq %rcx
testb %al, %al
je 0x2ca75
movsd 0x50(%r14), %xmm0
ucomisd %xmm5, %xmm0
jae 0x2ca6a
movsd 0x58(%r14), %xmm1
ucomisd %xmm1, %xmm5
jae 0x2ca6a
movapd %xmm1, %xmm2
subsd %xmm0, %xmm2
mulsd %xmm1, %xmm7
ucomisd %xmm2, %xmm7
jb 0x2ca75
movsd 0x40(%r14), %xmm0
movsd %xmm0, (%r15)
movl %ecx, (%rbx)
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop