// File: cjlin1[P]liblinear/newton.cpp
// Function: NEWTON::pcg(double*, double*, double*, double*)
int NEWTON::pcg(double *g, double *M, double *s, double *r)
{
	int i, inc = 1;
	int n = fun_obj->get_nr_variable();
	double one = 1;
	double *d = new double[n];
	double *Hd = new double[n];
	double zTr, znewTrnew, alpha, beta, cgtol, dHd;
	double *z = new double[n];
	double Q = 0, newQ, Qdiff;

	for (i=0; i<n; i++)
	{
		s[i] = 0;
		r[i] = -g[i];
		z[i] = r[i] / M[i];
		d[i] = z[i];
	}

	zTr = ddot_(&n, z, &inc, r, &inc);
	double gMinv_norm = sqrt(zTr);
	cgtol = min(eps_cg, sqrt(gMinv_norm));
	int cg_iter = 0;
	int max_cg_iter = max(n, 5);

	while (cg_iter < max_cg_iter)
	{
		cg_iter++;

		fun_obj->Hv(d, Hd);
		dHd = ddot_(&n, d, &inc, Hd, &inc);
		// avoid 0/0 in getting alpha
		if (dHd <= 1.0e-16)
			break;
		
		alpha = zTr/dHd;
		daxpy_(&n, &alpha, d, &inc, s, &inc);
		alpha = -alpha;
		daxpy_(&n, &alpha, Hd, &inc, r, &inc);

		// Using quadratic approximation as CG stopping criterion
		newQ = -0.5*(ddot_(&n, s, &inc, r, &inc) - ddot_(&n, s, &inc, g, &inc));
		Qdiff = newQ - Q;
		if (newQ <= 0 && Qdiff <= 0)
		{
			if (cg_iter * Qdiff >= cgtol * newQ)
				break;
		}
		else
		{
			info("WARNING: quadratic approximation > 0 or increasing in CG\n");
			break;
		}
		Q = newQ;

		for (i=0; i<n; i++)
			z[i] = r[i] / M[i];
		znewTrnew = ddot_(&n, z, &inc, r, &inc);
		beta = znewTrnew/zTr;
		dscal_(&n, &beta, d, &inc);
		daxpy_(&n, &one, z, &inc, d, &inc);
		zTr = znewTrnew;
	}

	if (cg_iter == max_cg_iter)
		info("WARNING: reaching maximal number of CG steps\n");

	delete[] d;
	delete[] Hd;
	delete[] z;

	return cg_iter;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xb8(%rbp)
movl $0x1, -0x30(%rbp)
movq 0x18(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movl %eax, -0x34(%rbp)
movsd 0xe2e2(%rip), %xmm0     # 0x12028
movsd %xmm0, -0x40(%rbp)
movslq -0x34(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x2030
movq %rax, -0x48(%rbp)
movslq -0x34(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x2030
movq %rax, -0x50(%rbp)
movslq -0x34(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x2030
movq %rax, -0x88(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x90(%rbp)
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x34(%rbp), %eax
jge 0x3e7d
movq -0x20(%rbp), %rax
movslq -0x2c(%rbp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movq -0x10(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movq -0x28(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movq -0x28(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x18(%rbp), %rax
movslq -0x2c(%rbp), %rcx
divsd (%rax,%rcx,8), %xmm0
movq -0x88(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movq -0x88(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x48(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x3ddb
movq -0x88(%rbp), %rsi
movq -0x28(%rbp), %rcx
leaq -0x34(%rbp), %rdi
leaq -0x30(%rbp), %r8
movq %r8, %rdx
callq 0x11bb0
movsd %xmm0, -0x58(%rbp)
movsd -0x58(%rbp), %xmm0
callq 0x20d0
movq -0xb8(%rbp), %rax
movsd %xmm0, -0xa8(%rbp)
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0xc0(%rbp)
movsd -0xa8(%rbp), %xmm0
callq 0x20d0
movaps %xmm0, %xmm1
movsd -0xc0(%rbp), %xmm0
callq 0x4200
movsd %xmm0, -0x78(%rbp)
movl $0x0, -0xac(%rbp)
movl -0x34(%rbp), %edi
movl $0x5, %esi
callq 0x4240
movl %eax, -0xb0(%rbp)
movl -0xac(%rbp), %eax
cmpl -0xb0(%rbp), %eax
jge 0x4169
movq -0xb8(%rbp), %rax
movl -0xac(%rbp), %ecx
addl $0x1, %ecx
movl %ecx, -0xac(%rbp)
movq 0x18(%rax), %rdi
movq -0x48(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq (%rdi), %rax
callq *0x10(%rax)
movq -0x48(%rbp), %rsi
movq -0x50(%rbp), %rcx
leaq -0x34(%rbp), %rdi
leaq -0x30(%rbp), %r8
movq %r8, %rdx
callq 0x11bb0
movsd %xmm0, -0x80(%rbp)
movsd 0xed2f(%rip), %xmm0     # 0x12c90
ucomisd -0x80(%rbp), %xmm0
jb 0x3f6d
jmp 0x4169
movsd -0x58(%rbp), %xmm0
divsd -0x80(%rbp), %xmm0
movsd %xmm0, -0x68(%rbp)
movq -0x48(%rbp), %rdx
movq -0x20(%rbp), %r8
leaq -0x34(%rbp), %rdi
leaq -0x68(%rbp), %rsi
leaq -0x30(%rbp), %r9
movq %r9, %rcx
callq 0x11930
movsd -0x68(%rbp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, -0x68(%rbp)
movq -0x50(%rbp), %rdx
movq -0x28(%rbp), %r8
leaq -0x34(%rbp), %rdi
leaq -0x68(%rbp), %rsi
leaq -0x30(%rbp), %r9
movq %r9, %rcx
callq 0x11930
movq -0x20(%rbp), %rsi
movq -0x28(%rbp), %rcx
leaq -0x34(%rbp), %rdi
leaq -0x30(%rbp), %r8
movq %r8, %rdx
callq 0x11bb0
movsd %xmm0, -0xc8(%rbp)
movq -0x20(%rbp), %rsi
movq -0x10(%rbp), %rcx
leaq -0x34(%rbp), %rdi
leaq -0x30(%rbp), %r8
movq %r8, %rdx
callq 0x11bb0
movsd -0xc8(%rbp), %xmm1
subsd %xmm0, %xmm1
movsd 0xec77(%rip), %xmm0     # 0x12c98
mulsd %xmm1, %xmm0
movsd %xmm0, -0x98(%rbp)
movsd -0x98(%rbp), %xmm0
subsd -0x90(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
xorps %xmm0, %xmm0
ucomisd -0x98(%rbp), %xmm0
jb 0x4089
xorps %xmm0, %xmm0
ucomisd -0xa0(%rbp), %xmm0
jb 0x4089
cvtsi2sdl -0xac(%rbp), %xmm0
mulsd -0xa0(%rbp), %xmm0
movsd -0x78(%rbp), %xmm1
mulsd -0x98(%rbp), %xmm1
ucomisd %xmm1, %xmm0
jb 0x4087
jmp 0x4169
jmp 0x40a3
movq -0xb8(%rbp), %rdi
leaq 0xece7(%rip), %rsi      # 0x12d7e
movb $0x0, %al
callq 0x3660
jmp 0x4169
movsd -0x98(%rbp), %xmm0
movsd %xmm0, -0x90(%rbp)
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x34(%rbp), %eax
jge 0x40f7
movq -0x28(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x18(%rbp), %rax
movslq -0x2c(%rbp), %rcx
divsd (%rax,%rcx,8), %xmm0
movq -0x88(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x40ba
movq -0x88(%rbp), %rsi
movq -0x28(%rbp), %rcx
leaq -0x34(%rbp), %rdi
leaq -0x30(%rbp), %r8
movq %r8, %rdx
callq 0x11bb0
movsd %xmm0, -0x60(%rbp)
movsd -0x60(%rbp), %xmm0
divsd -0x58(%rbp), %xmm0
movsd %xmm0, -0x70(%rbp)
movq -0x48(%rbp), %rdx
leaq -0x34(%rbp), %rdi
leaq -0x70(%rbp), %rsi
leaq -0x30(%rbp), %rcx
callq 0x11e00
movq -0x88(%rbp), %rdx
movq -0x48(%rbp), %r8
leaq -0x34(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x30(%rbp), %r9
movq %r9, %rcx
callq 0x11930
movsd -0x60(%rbp), %xmm0
movsd %xmm0, -0x58(%rbp)
jmp 0x3f02
movl -0xac(%rbp), %eax
cmpl -0xb0(%rbp), %eax
jne 0x418c
movq -0xb8(%rbp), %rdi
leaq 0xec33(%rip), %rsi      # 0x12db8
movb $0x0, %al
callq 0x3660
movq -0x48(%rbp), %rax
movq %rax, -0xd0(%rbp)
cmpq $0x0, %rax
je 0x41a9
movq -0xd0(%rbp), %rdi
callq 0x21b0
movq -0x50(%rbp), %rax
movq %rax, -0xd8(%rbp)
cmpq $0x0, %rax
je 0x41c6
movq -0xd8(%rbp), %rdi
callq 0x21b0
movq -0x88(%rbp), %rax
movq %rax, -0xe0(%rbp)
cmpq $0x0, %rax
je 0x41e6
movq -0xe0(%rbp), %rdi
callq 0x21b0
movl -0xac(%rbp), %eax
addq $0xe0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)