// File: /workspace/github_cpp_makefile_star2_O2/toxaart[P]hierarchical_block_sparse_lib/source/HierarchicalBlockSparseMatrix.h
// Function: hbsm::HierarchicalBlockSparseMatrix<double>::inv_chol(hbsm::HierarchicalBlockSparseMatrix<double> const&, hbsm::HierarchicalBlockSparseMatrix<double>&)
void HierarchicalBlockSparseMatrix<Treal>::inv_chol(HierarchicalBlockSparseMatrix<Treal> const & A, HierarchicalBlockSparseMatrix<Treal> & Z){


			if(!Z.empty()) throw std::runtime_error("Error in HierarchicalBlockSparseMatrix::inv_chol(): non-empty matrix to write result!");
			if(A.nRows_orig != A.nCols_orig) throw std::runtime_error("Error in HierarchicalBlockSparseMatrix::inv_chol(): call for non-square matrix!");

			Z.set_params(A.get_params());

			Z.resize(A.nRows_orig, A.nCols_orig);

			if(Z.lowest_level()){

				if(Z.get_first_row_position() > Z.get_n_rows()-1 || Z.get_first_col_position() > Z.get_n_cols()-1) return;

				int blocksize = Z.nRows;

				int n = Z.nRows;

				if(Z.on_bottom_boundary()) n = Z.get_n_rows() % Z.blocksize; // fill only necessary elements

				for(int i = 0; i < n; ++i) Z.submatrix[i*blocksize + i] = 1.0;

				Z.submatrix[0] = std::sqrt(1/A.submatrix[0]);
				for (int i = 1; i < n; i++) {
					Treal R;
					for (int j = 0; j < i; j++) {
						R = 0;

						for (int k = 0; k < n; k++)
							R += A.submatrix[k*blocksize+j] * Z.submatrix[i*blocksize+k];

						R *= Z.submatrix[j*blocksize+j];

						for (int k = 0; k < n; k++)
							Z.submatrix[i*blocksize+k] -= Z.submatrix[j*blocksize+k] * R;
					}
					R = 0;
					for (int k = 0; k < n; k++)
						R += A.submatrix[k*blocksize+i] * Z.submatrix[i*blocksize+k];

					R = std::sqrt(1/R);
					for (int k = 0; k < n; k++)
						Z.submatrix[i*blocksize+k] *= R;
				}

			   return;


			}

			// Z_00 = invChol(A_00)
			if(A.children[0] != NULL){
				Z.children[0] = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
				Z.children[0]->parent = &Z;
				inv_chol(*A.children[0], *Z.children[0]);
			}


			if(Z.children[0] == NULL) throw std::runtime_error("Error in HierarchicalBlockSparseMatrix::inv_chol(): smth went wrong since Z_00 is NULL!");

			// R = Z_00^T * A_01
			std::shared_ptr<HierarchicalBlockSparseMatrix<Treal> > R;

			if(A.children[2] != NULL){
				R = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
				multiply(*Z.children[0], true, *A.children[2], false, *R);
			}

			// T = Z_00 * R
			std::shared_ptr<HierarchicalBlockSparseMatrix<Treal> > T;
			if(R != NULL){
				T = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
				multiply(*Z.children[0], false, *R, false, *T);
			}


			// X = -T
			std::shared_ptr<HierarchicalBlockSparseMatrix<Treal> > X;
			if(T != NULL){
				X = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
				X->rescale(*T,-1.0);
			}

			// Y = A_10 * X
			std::shared_ptr<HierarchicalBlockSparseMatrix<Treal> > Y;

			if(A.children[1] != NULL && X != NULL){
				Y = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
				multiply(*A.children[1], false, *X, false, *Y);
			}


			// Q = Y + A_11
			std::shared_ptr<HierarchicalBlockSparseMatrix<Treal> > Q;
			if(A.children[3] != NULL){
				if(Y != NULL){
					Q = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
					add(*Y, *A.children[3], *Q);
				}
				else{
					Q = A.children[3];
				}
			}
			else{
				Q = Y;
			}

			// Z_11 = invChol(Q)
			if(Z.children[3] == NULL){
				if(Q != NULL){
					Z.children[3] = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
					Z.children[3]->parent = &Z;
					inv_chol(*Q, *Z.children[3]);
				}
			}
			else throw std::runtime_error("Error in HierarchicalBlockSparseMatrix::inv_chol(): smth went wrong since Z_11 was not NULL!");

			// Z_01 = X * Z_11
			if(Z.children[2] == NULL){
				if(X != NULL){
					Z.children[2] = std::make_shared<HierarchicalBlockSparseMatrix<Treal> >();
					multiply(*X, false, *Z.children[3], false, *Z.children[2]);
				}
			}
			else std::runtime_error("Error in HierarchicalBlockSparseMatrix::inv_chol(): smth went wrong since Z_01 was not NULL!");

			// Z_10 = 0
			assert(Z.children[1] == NULL);

			return;

		}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %rsi, %rbx
movq %rdi, %r14
movq %rsi, %rdi
callq 0x14e3a
testb %al, %al
je 0xd002
movl 0x8(%r14), %eax
cmpl 0xc(%r14), %eax
jne 0xd01e
movl 0x10(%r14), %eax
leaq 0x50(%rsp), %rsi
movl %eax, (%rsi)
movq %rbx, %rdi
callq 0x7cc0
movl 0x8(%r14), %esi
movl 0xc(%r14), %edx
movq %rbx, %rdi
xorl %ecx, %ecx
callq 0x7d24
movq %rbx, %rdi
callq 0x14f94
testb %al, %al
je 0xcb69
movq %r14, 0x78(%rsp)
movq %rbx, %rdi
callq 0x15308
movl %eax, %ebp
movq %rbx, %r14
movq %rbx, %rdi
callq 0x15274
cmpl %eax, %ebp
jge 0xce81
movq %r14, %rdi
callq 0x1557a
movl %eax, %ebp
movq %r14, %rdi
callq 0x152d0
cmpl %eax, %ebp
jge 0xce81
movq %r14, %r12
movl (%r14), %ebx
movq %r14, %rdi
callq 0x15236
movl %ebx, %ebp
testb %al, %al
je 0xcb32
movq %r12, %rdi
callq 0x15274
cltd
idivl 0x10(%r12)
movl %edx, %ebp
movslq %ebx, %r15
leal 0x1(%r15), %eax
movq 0x70(%r12), %rcx
xorl %edx, %edx
testl %ebp, %ebp
movl $0x0, %esi
cmovgl %ebp, %esi
movabsq $0x3ff0000000000000, %rdi # imm = 0x3FF0000000000000
subq $0x1, %rsi
jb 0xce93
movslq %edx, %rdx
movq %rdi, (%rcx,%rdx,8)
addl %eax, %edx
jmp 0xcb54
cmpq $0x0, 0x28(%r14)
je 0xcba4
leaq 0x50(%rsp), %r15
movq %r15, %rdi
callq 0x152ec
leaq 0x28(%rbx), %rdi
movq %r15, %rsi
callq 0x14fba
leaq 0x58(%rsp), %rdi
callq 0x14fe8
movq 0x28(%rbx), %rsi
movq %rbx, 0x68(%rsi)
movq 0x28(%r14), %rdi
callq 0xca68
cmpq $0x0, 0x28(%rbx)
je 0xd03a
xorpd %xmm0, %xmm0
movapd %xmm0, 0x50(%rsp)
cmpq $0x0, 0x48(%r14)
je 0xccb8
leaq 0x40(%rsp), %rdi
callq 0x152ec
leaq 0x50(%rsp), %r15
leaq 0x40(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x48(%rsp), %rdi
callq 0x14fe8
movq 0x28(%rbx), %rdi
movq 0x48(%r14), %rdx
movq (%r15), %r8
andq $0x0, (%rsp)
pushq $0x1
popq %rsi
xorl %ecx, %ecx
xorl %r9d, %r9d
callq 0x8572
cmpq $0x0, 0x50(%rsp)
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
je 0xccbe
leaq 0x10(%rsp), %rdi
callq 0x152ec
leaq 0x40(%rsp), %r15
leaq 0x10(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x18(%rsp), %rdi
callq 0x14fe8
movq 0x28(%rbx), %rdi
movq 0x50(%rsp), %rdx
movq (%r15), %r8
andq $0x0, (%rsp)
xorl %esi, %esi
xorl %ecx, %ecx
xorl %r9d, %r9d
callq 0x8572
cmpq $0x0, 0x40(%rsp)
xorpd %xmm0, %xmm0
movapd %xmm0, 0x10(%rsp)
je 0xccc4
leaq 0x30(%rsp), %rdi
callq 0x152ec
leaq 0x10(%rsp), %r15
leaq 0x30(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x38(%rsp), %rdi
callq 0x14fe8
movq (%r15), %rdi
movq 0x40(%rsp), %rsi
movsd 0xf488(%rip), %xmm0     # 0x1c130
callq 0xc8ec
cmpq $0x0, 0x10(%rsp)
setne %al
jmp 0xccc6
movapd %xmm0, 0x40(%rsp)
movapd %xmm0, 0x10(%rsp)
xorl %eax, %eax
xorpd %xmm0, %xmm0
movapd %xmm0, 0x30(%rsp)
cmpq $0x0, 0x38(%r14)
je 0xcd1e
testb %al, %al
je 0xcd1e
leaq 0x20(%rsp), %rdi
callq 0x152ec
leaq 0x30(%rsp), %r15
leaq 0x20(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x28(%rsp), %rdi
callq 0x14fe8
movq 0x38(%r14), %rdi
movq 0x10(%rsp), %rdx
movq (%r15), %r8
andq $0x0, (%rsp)
xorl %esi, %esi
xorl %ecx, %ecx
xorl %r9d, %r9d
callq 0x8572
xorpd %xmm0, %xmm0
movapd %xmm0, 0x20(%rsp)
cmpq $0x0, 0x58(%r14)
je 0xcd75
addq $0x58, %r14
cmpq $0x0, 0x30(%rsp)
je 0xcd7a
leaq 0x60(%rsp), %rdi
callq 0x152ec
leaq 0x20(%rsp), %r15
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x68(%rsp), %rdi
callq 0x14fe8
movq 0x30(%rsp), %rdi
movq (%r14), %rsi
movq (%r15), %rdx
xorl %ecx, %ecx
callq 0x8294
jmp 0xcd87
leaq 0x30(%rsp), %r14
leaq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x162fc
cmpq $0x0, 0x58(%rbx)
jne 0xd06a
leaq 0x58(%rbx), %r14
cmpq $0x0, 0x20(%rsp)
je 0xcdd1
leaq 0x60(%rsp), %rdi
callq 0x152ec
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x14fba
leaq 0x68(%rsp), %rdi
callq 0x14fe8
movq 0x58(%rbx), %rsi
movq %rbx, 0x68(%rsi)
movq 0x20(%rsp), %rdi
callq 0xca68
cmpq $0x0, 0x48(%rbx)
je 0xcdfb
leaq 0x10722(%rip), %rsi     # 0x1d501
leaq 0x88(%rsp), %rdi
callq 0x2080
leaq 0x88(%rsp), %rdi
callq 0x22d8
jmp 0xce44
cmpq $0x0, 0x10(%rsp)
je 0xce44
leaq 0x60(%rsp), %rdi
callq 0x152ec
leaq 0x48(%rbx), %r15
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x14fba
leaq 0x68(%rsp), %rdi
callq 0x14fe8
movq 0x10(%rsp), %rdi
movq (%r14), %rdx
movq (%r15), %r8
andq $0x0, (%rsp)
xorl %esi, %esi
xorl %ecx, %ecx
xorl %r9d, %r9d
callq 0x8572
cmpq $0x0, 0x38(%rbx)
jne 0xd09a
leaq 0x28(%rsp), %rdi
callq 0x14fe8
leaq 0x38(%rsp), %rdi
callq 0x14fe8
leaq 0x18(%rsp), %rdi
callq 0x14fe8
leaq 0x48(%rsp), %rdi
callq 0x14fe8
leaq 0x58(%rsp), %rdi
callq 0x14fe8
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x78(%rsp), %rax
movq 0x70(%rax), %rax
movsd 0xf17c(%rip), %xmm0     # 0x1c020
divsd (%rax), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jb 0xceb8
sqrtsd %xmm0, %xmm0
jmp 0xcebd
callq 0x2160
movq 0x70(%r12), %rax
movsd %xmm0, (%rax)
movslq %ebp, %r11
movl %ebp, %r13d
leaq (,%r15,8), %rbp
pushq $0x1
popq %r12
pushq $0x8
popq %rsi
movq %rbp, %rbx
movq %r11, 0x80(%rsp)
cmpq %r11, %r12
jge 0xce81
movq %rsi, 0x70(%rsp)
leaq (%rax,%rbx), %rcx
movq %rax, %rdx
xorl %esi, %esi
xorl %edi, %edi
movq 0x78(%rsp), %r8
movq 0x70(%r8), %r8
movq 0x70(%r14), %r9
addq %rbx, %r9
cmpq %r12, %rdi
je 0xcf79
addq %rsi, %r8
xorpd %xmm0, %xmm0
xorl %r10d, %r10d
cmpq %r10, %r13
je 0xcf36
movsd (%r8), %xmm1
mulsd (%r9,%r10,8), %xmm1
addsd %xmm1, %xmm0
incq %r10
addq %rbp, %r8
jmp 0xcf1a
movq %rdi, %r8
imulq %r15, %r8
addq %rdi, %r8
mulsd (%rax,%r8,8), %xmm0
xorl %r8d, %r8d
cmpq %r8, %r13
je 0xcf6d
movsd (%rcx,%r8,8), %xmm1
movsd (%rdx,%r8,8), %xmm2
mulsd %xmm0, %xmm2
subsd %xmm2, %xmm1
movsd %xmm1, (%rcx,%r8,8)
incq %r8
jmp 0xcf49
incq %rdi
addq $0x8, %rsi
addq %rbp, %rdx
jmp 0xcefb
movq 0x70(%rsp), %rsi
addq %rsi, %r8
xorpd %xmm1, %xmm1
xorl %eax, %eax
cmpq %rax, %r13
je 0xcfa3
movsd (%r8), %xmm0
mulsd (%r9,%rax,8), %xmm0
addsd %xmm0, %xmm1
incq %rax
addq %rbp, %r8
jmp 0xcf87
movsd 0xf075(%rip), %xmm0     # 0x1c020
divsd %xmm1, %xmm0
ucomisd 0xf311(%rip), %xmm0     # 0x1c2c8
jb 0xcfbf
sqrtsd %xmm0, %xmm0
jmp 0xcfd1
callq 0x2160
movq 0x70(%rsp), %rsi
movq 0x80(%rsp), %r11
movq 0x70(%r14), %rax
leaq (%rax,%rbx), %rcx
xorl %edx, %edx
cmpq %rdx, %r13
je 0xcff3
movsd (%rcx,%rdx,8), %xmm1
mulsd %xmm0, %xmm1
movsd %xmm1, (%rcx,%rdx,8)
incq %rdx
jmp 0xcfdb
incq %r12
addq %rbp, %rbx
addq $0x8, %rsi
jmp 0xcee6
pushq $0x10
popq %rdi
callq 0x20d0
movq %rax, %r14
leaq 0x10392(%rip), %rsi     # 0x1d3a6
movq %rax, %rdi
callq 0x2080
jmp 0xd054
pushq $0x10
popq %rdi
callq 0x20d0
movq %rax, %r14
leaq 0x103cc(%rip), %rsi     # 0x1d3fc
movq %rax, %rdi
callq 0x2080
jmp 0xd054
pushq $0x10
popq %rdi
callq 0x20d0
movq %rax, %r14
leaq 0x10400(%rip), %rsi     # 0x1d44c
movq %rax, %rdi
callq 0x2080
movq 0x18f95(%rip), %rsi     # 0x25ff0
movq 0x18f5e(%rip), %rdx     # 0x25fc0
movq %r14, %rdi
callq 0x2270
pushq $0x10
popq %rdi
callq 0x20d0
movq %rax, %r14
leaq 0x10428(%rip), %rsi     # 0x1d4a4
movq %rax, %rdi
callq 0x2080
movq 0x18f65(%rip), %rsi     # 0x25ff0
movq 0x18f2e(%rip), %rdx     # 0x25fc0
movq %r14, %rdi
callq 0x2270
leaq 0x104bd(%rip), %rdi     # 0x1d55e
leaq 0xf6a7(%rip), %rsi      # 0x1c74f
leaq 0x104c5(%rip), %rcx     # 0x1d574
movl $0xca5, %edx            # imm = 0xCA5
callq 0x2100
jmp 0xd0f9
jmp 0xd0bd
movq %rax, %rbx
jmp 0xd110
jmp 0xd0f9
jmp 0xd0c6
movq %rax, %rbx
jmp 0xd11a
movq %rax, %rbx
movq %r14, %rdi
callq 0x2130
jmp 0xd0fc
jmp 0xd0da
movq %rax, %rbx
jmp 0xd106
jmp 0xd0ec
jmp 0xd0f9
jmp 0xd0e5
movq %rax, %rbx
jmp 0xd124
jmp 0xd0ec
movq %rax, %rbx
movq %r14, %rdi
callq 0x2130
jmp 0xd12e
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x14fe8
leaq 0x38(%rsp), %rdi
callq 0x14fe8
leaq 0x18(%rsp), %rdi
callq 0x14fe8
leaq 0x48(%rsp), %rdi
callq 0x14fe8
leaq 0x58(%rsp), %rdi
callq 0x14fe8
movq %rbx, %rdi
callq 0x2290