// File: chiku[P]cmatrix/src/impl/matrix/invert.cpp
// Function: cmatrix::Matrix<double>::invert()
Matrix<Type> Matrix<Type>::invert()
{
    if (!isSquare()) {
        throw Exception::InversionNotPossible(ExceptionBody::NonSquareMatrix(size));
    }

    Matrix<Type> result = (*this);
    long int n = result.rows();
    long int pivot_column = 0, pivot_row = 0;

    Matrix<long int> column_indices(n, 1);
    Matrix<long int> row_indices(n, 1);
    Matrix<long int> pivots(n, 1);

    for (long int i = 0; i < n; i++) {
        pivots(i, 0) = -1;
    }

    for (long int i = 0; i < n; i++) {
        Type big = 0;
        for (long int j = 0; j < n; j++) {
            if (pivots(j, 0) != 0) {
                for (long int k = 0; k < n; k++) {
                    if ((pivots(k, 0) == -1) && (fabs(result(j, k)) >= big)) {
                        big = fabs(result(j, k));
                        pivot_row = j;
                        pivot_column = k;
                    }
                }
            }
        }
        pivots(pivot_column, 0) += 1;

        /* We now have the pivot element, so we interchange rows, if needed, to put the pivot
        element on the diagonal. The columns are not physically interchanged, only relabeled:
        column_indices[i], the column of the ith pivot element, is the ith column that is reduced,
        while row_indices[i] is the row in which that pivot element was originally located.
        If row_indices[i] != column_indices[i] there is an implied column interchange.
        With this form of book keeping, inverse matrix will be scrambled by columns. */
        if (pivot_row != pivot_column) {
            for (long int j = 0; j < n; j++)
                std::swap(result(pivot_row, j), result(pivot_column, j));
        }

        row_indices(i, 0) = pivot_row;       // We are now ready to divide the pivot row by the
        column_indices(i, 0) = pivot_column; // pivot element, located at pivot_row and pivot_column.
        if (result(pivot_column, pivot_column) == 0.0) {
            throw Exception::InversionNotPossible(ExceptionBody::SingularMatrix());
        }
        Type pivot_inverse = 1.0 / result(pivot_column, pivot_column);
        result(pivot_column, pivot_column) = 1.0;

        for (long int j = 0; j < n; j++) {
            result(pivot_column, j) *= pivot_inverse;
        }

        for (long int j = 0; j < n; j++) { // Next, we reduce the rows...
            if (j != pivot_column) {       //  except for the pivot one
                Type dum = result(j, pivot_column);
                result(j, pivot_column) = 0.0;
                for (long int k = 0; k < n; k++)
                    result(j, k) -= result(pivot_column, k) * dum;
            }
        }
    }
    /* This is the end of the main loop over columns of the reduction. It only remains to unscramble
    the solution in view of the column interchanges. We do this by interchanging pairs of
    columns in the reverse order that the permutation was built up. */
    for (long int i = 0; i < 0; i++) {
        if (row_indices(i, 0) != column_indices(i, 0)) {
            for (long int j = 0; j < n; j++) {
                std::swap(result(j, row_indices(i, 0)), result(i, column_indices(i, 0)));
            }
        }
    }

    return result;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2a0, %rsp            # imm = 0x2A0
movq %rdi, -0x188(%rbp)
movq %rdi, %rax
movq %rax, -0x180(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rdi
movq %rdi, -0x178(%rbp)
callq 0x20b20
testb $0x1, %al
jne 0x1fc16
movb $0x1, -0x4d(%rbp)
movl $0x10, %edi
callq 0x61c0
movq %rax, %rcx
movq -0x178(%rbp), %rax
movq %rcx, -0x190(%rbp)
movups (%rax), %xmm0
movaps %xmm0, -0x40(%rbp)
movq -0x40(%rbp), %rsi
movq -0x38(%rbp), %rdx
leaq -0x30(%rbp), %rdi
callq 0x20b40
jmp 0x1fba5
movq -0x190(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x20c60
jmp 0x1fbb7
movq -0x190(%rbp), %rdi
movb $0x0, -0x4d(%rbp)
leaq 0x66c37(%rip), %rsi     # 0x86800
leaq 0x10d0(%rip), %rdx      # 0x20ca0
callq 0x6760
jmp 0x20565
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x1fbfd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x6230
testb $0x1, -0x4d(%rbp)
jne 0x1fc05
jmp 0x1fc11
movq -0x190(%rbp), %rdi
callq 0x62c0
jmp 0x2055c
movq -0x188(%rbp), %rdi
movq -0x178(%rbp), %rsi
movb $0x0, -0x4e(%rbp)
callq 0x12d70
movq -0x188(%rbp), %rdi
callq 0x10160
movq %rax, -0x198(%rbp)
jmp 0x1fc42
movq -0x198(%rbp), %rax
movq %rax, -0x58(%rbp)
movq $0x0, -0x60(%rbp)
movq $0x0, -0x68(%rbp)
movq -0x58(%rbp), %rsi
leaq -0x90(%rbp), %rdi
movl $0x1, %edx
callq 0x20cc0
jmp 0x1fc74
movq -0x58(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
movl $0x1, %edx
callq 0x20cc0
jmp 0x1fc8b
movq -0x58(%rbp), %rsi
leaq -0xe0(%rbp), %rdi
movl $0x1, %edx
callq 0x20cc0
jmp 0x1fca2
movq $0x0, -0xe8(%rbp)
movq -0xe8(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x1fd44
movq -0xe8(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xe0(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1a0(%rbp)
jmp 0x1fcde
movq -0x1a0(%rbp), %rax
movq $-0x1, (%rax)
movq -0xe8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe8(%rbp)
jmp 0x1fcad
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x20550
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x20526
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x2051a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x2050e
movq $0x0, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x2035b
xorps %xmm0, %xmm0
movsd %xmm0, -0xf8(%rbp)
movq $0x0, -0x100(%rbp)
movq -0x100(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x1fed3
movq -0x100(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xe0(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1a8(%rbp)
jmp 0x1fda7
movq -0x1a8(%rbp), %rax
cmpq $0x0, (%rax)
je 0x1feba
movq $0x0, -0x108(%rbp)
movq -0x108(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x1feb8
movq -0x108(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xe0(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1b0(%rbp)
jmp 0x1fdf4
movq -0x1b0(%rbp), %rax
cmpq $-0x1, (%rax)
jne 0x1fe9f
movq -0x188(%rbp), %rdi
movq -0x100(%rbp), %rsi
movq -0x108(%rbp), %rdx
callq 0x10370
movq %rax, -0x1b8(%rbp)
jmp 0x1fe28
movq -0x1b8(%rbp), %rax
movsd (%rax), %xmm0
movaps 0x46926(%rip), %xmm1    # 0x66760
pand %xmm1, %xmm0
ucomisd -0xf8(%rbp), %xmm0
jb 0x1fe9f
movq -0x188(%rbp), %rdi
movq -0x100(%rbp), %rsi
movq -0x108(%rbp), %rdx
callq 0x10370
movq %rax, -0x1c0(%rbp)
jmp 0x1fe6b
movq -0x1c0(%rbp), %rax
movsd (%rax), %xmm0
movaps 0x468e3(%rip), %xmm1    # 0x66760
pand %xmm1, %xmm0
movsd %xmm0, -0xf8(%rbp)
movq -0x100(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x108(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0x1fea1
movq -0x108(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x108(%rbp)
jmp 0x1fdc3
jmp 0x1feba
jmp 0x1febc
movq -0x100(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x100(%rbp)
jmp 0x1fd76
movq -0x60(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xe0(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1c8(%rbp)
jmp 0x1fef0
movq -0x1c8(%rbp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
movq -0x68(%rbp), %rax
cmpq -0x60(%rbp), %rax
je 0x1ff90
movq $0x0, -0x110(%rbp)
movq -0x110(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x1ff8e
movq -0x188(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0x110(%rbp), %rdx
callq 0x10370
movq %rax, -0x1d0(%rbp)
jmp 0x1ff47
movq -0x188(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x110(%rbp), %rdx
callq 0x10370
movq %rax, -0x1d8(%rbp)
jmp 0x1ff67
movq -0x1d8(%rbp), %rsi
movq -0x1d0(%rbp), %rdi
callq 0x20e00
movq -0x110(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x110(%rbp)
jmp 0x1ff1a
jmp 0x1ff90
movq -0x68(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movq -0xf0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xb8(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1e0(%rbp)
jmp 0x1ffbb
movq -0x1e0(%rbp), %rax
movq -0x1e8(%rbp), %rcx
movq %rcx, (%rax)
movq -0x60(%rbp), %rax
movq %rax, -0x1f8(%rbp)
movq -0xf0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0x90(%rbp), %rdi
callq 0x20d10
movq %rax, -0x1f0(%rbp)
jmp 0x1fff7
movq -0x188(%rbp), %rdi
movq -0x1f0(%rbp), %rax
movq -0x1f8(%rbp), %rcx
movq %rcx, (%rax)
movq -0x60(%rbp), %rdx
movq %rdx, %rsi
callq 0x10370
movq %rax, -0x200(%rbp)
jmp 0x20024
movq -0x200(%rbp), %rax
movsd (%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x200e5
jp 0x200e5
movb $0x1, -0x131(%rbp)
movl $0x10, %edi
callq 0x61c0
movq %rax, -0x208(%rbp)
leaq -0x130(%rbp), %rdi
callq 0x20e40
jmp 0x20068
movq -0x208(%rbp), %rdi
leaq -0x130(%rbp), %rsi
callq 0x20c60
jmp 0x2007d
movq -0x208(%rbp), %rdi
movb $0x0, -0x131(%rbp)
leaq 0x6676e(%rip), %rsi     # 0x86800
leaq 0xc07(%rip), %rdx       # 0x20ca0
callq 0x6760
jmp 0x20565
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x200c9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x130(%rbp), %rdi
callq 0x6230
testb $0x1, -0x131(%rbp)
jne 0x200d4
jmp 0x200e0
movq -0x208(%rbp), %rdi
callq 0x62c0
jmp 0x2050e
movq -0x188(%rbp), %rdi
movq -0x60(%rbp), %rdx
movq %rdx, %rsi
callq 0x10370
movq %rax, -0x210(%rbp)
jmp 0x20101
movq -0x188(%rbp), %rdi
movq -0x210(%rbp), %rax
movsd (%rax), %xmm1
movsd 0x44efd(%rip), %xmm0    # 0x65018
divsd %xmm1, %xmm0
movsd %xmm0, -0x140(%rbp)
movq -0x60(%rbp), %rdx
movq %rdx, %rsi
callq 0x10370
movq %rax, -0x218(%rbp)
jmp 0x2013c
movq -0x218(%rbp), %rax
movsd 0x44ecd(%rip), %xmm0    # 0x65018
movsd %xmm0, (%rax)
movq $0x0, -0x148(%rbp)
movq -0x148(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x201c2
movq -0x188(%rbp), %rdi
movsd -0x140(%rbp), %xmm0
movsd %xmm0, -0x228(%rbp)
movq -0x60(%rbp), %rsi
movq -0x148(%rbp), %rdx
callq 0x10370
movq %rax, -0x220(%rbp)
jmp 0x20197
movq -0x220(%rbp), %rax
movsd -0x228(%rbp), %xmm0
mulsd (%rax), %xmm0
movsd %xmm0, (%rax)
movq -0x148(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x148(%rbp)
jmp 0x2015a
movq $0x0, -0x150(%rbp)
movq -0x150(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x20342
movq -0x150(%rbp), %rax
cmpq -0x60(%rbp), %rax
je 0x20329
movq -0x188(%rbp), %rdi
movq -0x150(%rbp), %rsi
movq -0x60(%rbp), %rdx
callq 0x10370
movq %rax, -0x230(%rbp)
jmp 0x2020f
movq -0x188(%rbp), %rdi
movq -0x230(%rbp), %rax
movsd (%rax), %xmm0
movsd %xmm0, -0x158(%rbp)
movq -0x150(%rbp), %rsi
movq -0x60(%rbp), %rdx
callq 0x10370
movq %rax, -0x238(%rbp)
jmp 0x20242
movq -0x238(%rbp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, (%rax)
movq $0x0, -0x160(%rbp)
movq -0x160(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x20327
movq -0x188(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x160(%rbp), %rdx
callq 0x10370
movq %rax, -0x240(%rbp)
jmp 0x2028c
movq -0x188(%rbp), %rdi
movq -0x240(%rbp), %rax
movsd (%rax), %xmm0
movsd %xmm0, -0x258(%rbp)
movsd -0x158(%rbp), %xmm0
movsd %xmm0, -0x250(%rbp)
movq -0x150(%rbp), %rsi
movq -0x160(%rbp), %rdx
callq 0x10370
movq %rax, -0x248(%rbp)
jmp 0x202d2
movq -0x248(%rbp), %rax
movsd -0x250(%rbp), %xmm2
movsd -0x258(%rbp), %xmm0
movsd (%rax), %xmm1
movq %xmm0, %rcx
movabsq $-0x8000000000000000, %rdx # imm = 0x8000000000000000
xorq %rdx, %rcx
movq %rcx, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rax)
movq -0x160(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x160(%rbp)
jmp 0x2025b
jmp 0x20329
jmp 0x2032b
movq -0x150(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x150(%rbp)
jmp 0x201cd
jmp 0x20344
movq -0xf0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xf0(%rbp)
jmp 0x1fd4f
movq $0x0, -0x168(%rbp)
cmpq $0x0, -0x168(%rbp)
jge 0x204de
movq -0x168(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xb8(%rbp), %rdi
callq 0x20d10
movq %rax, -0x260(%rbp)
jmp 0x20394
movq -0x260(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x270(%rbp)
movq -0x168(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0x90(%rbp), %rdi
callq 0x20d10
movq %rax, -0x268(%rbp)
jmp 0x203c5
movq -0x270(%rbp), %rax
movq -0x268(%rbp), %rcx
cmpq (%rcx), %rax
je 0x204c5
movq $0x0, -0x170(%rbp)
movq -0x170(%rbp), %rax
cmpq -0x58(%rbp), %rax
jge 0x204c3
movq -0x170(%rbp), %rax
movq %rax, -0x280(%rbp)
movq -0x168(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq -0xb8(%rbp), %rdi
callq 0x20d10
movq %rax, -0x278(%rbp)
jmp 0x20426
movq -0x280(%rbp), %rsi
movq -0x188(%rbp), %rdi
movq -0x278(%rbp), %rax
movq (%rax), %rdx
callq 0x10370
movq %rax, -0x288(%rbp)
jmp 0x2044c
movq -0x168(%rbp), %rsi
movq %rsi, -0x298(%rbp)
xorl %eax, %eax
movl %eax, %edx
leaq -0x90(%rbp), %rdi
callq 0x20d10
movq %rax, -0x290(%rbp)
jmp 0x20473
movq -0x298(%rbp), %rsi
movq -0x188(%rbp), %rdi
movq -0x290(%rbp), %rax
movq (%rax), %rdx
callq 0x10370
movq %rax, -0x2a0(%rbp)
jmp 0x20499
movq -0x2a0(%rbp), %rsi
movq -0x288(%rbp), %rdi
callq 0x20e00
movq -0x170(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x170(%rbp)
jmp 0x203e7
jmp 0x204c5
jmp 0x204c7
movq -0x168(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x168(%rbp)
jmp 0x20366
movb $0x1, -0x4e(%rbp)
leaq -0xe0(%rbp), %rdi
callq 0x20eb0
leaq -0xb8(%rbp), %rdi
callq 0x20eb0
leaq -0x90(%rbp), %rdi
callq 0x20eb0
testb $0x1, -0x4e(%rbp)
jne 0x20540
jmp 0x20534
leaq -0xe0(%rbp), %rdi
callq 0x20eb0
leaq -0xb8(%rbp), %rdi
callq 0x20eb0
leaq -0x90(%rbp), %rdi
callq 0x20eb0
jmp 0x20550
movq -0x188(%rbp), %rdi
callq 0x105f0
movq -0x180(%rbp), %rax
addq $0x2a0, %rsp            # imm = 0x2A0
popq %rbp
retq
movq -0x188(%rbp), %rdi
callq 0x105f0
movq -0x48(%rbp), %rdi
callq 0x67c0
nopw %cs:(%rax,%rax)
nop