// File: btbujiangjun[P]abcdl/src/algebra/MatrixAlgebra.cpp
// Function: abcdl::algebra::Matrix<int>::inverse() const
Matrix<real> Matrix<T>::inverse() const{
    CHECK(_rows == _cols);
    //copy src mat
    Matrix<real> extend_mat = clone();
    //extend eye matrix
    extend_mat.extend(EyeMatrix<real>(_rows), Axis_type::COL);

    //adjust row
    size_t extend_mat_rows = extend_mat.rows();
    size_t extend_mat_cols = extend_mat.cols();
    for(size_t i = 0; i != extend_mat_rows; i++){
        if(extend_mat.get_data(i, i) == 0){
            size_t j;
            for(j = 0; j != extend_mat_rows; j++){
                if(extend_mat.get_data(j, i) != 0){
                    extend_mat.swap_row(i, j);
                    break;
                }
            }
            CHECK(j <= extend_mat_rows);//every element is zero in col i, cannot be inverse.
        }
    }

    //calc extend matrix
    for(size_t i = 0; i != extend_mat_rows; i++){
        //all element div the first element,to make diagonal elemnt is 1
        real diagonal_element = extend_mat.get_data(i, i);
        for(size_t j = 0; j < extend_mat_cols; j++){
            extend_mat.set_data(extend_mat.get_data(i, j)/diagonal_element, i, j);
        }

        //to make the element of other rows in col i is 0
        for(size_t m = 0; m != extend_mat_rows; m++){
            if(m == i){//skip itself
                continue;
            }
            real element = extend_mat.get_data(m, i);
            for(size_t n = 0; n != extend_mat_cols; n++){
                extend_mat.set_data(extend_mat.get_data(m, n) - extend_mat.get_data(i, n) * element, m, n);
            }
        }
    }

    //calc inverse matrix
    Matrix<real> result_mat(_rows, _cols);
    for(size_t i = 0; i != extend_mat_rows; i++){
        memcpy(&result_mat.data()[i * _cols], &extend_mat.data()[i * extend_mat_cols + _cols], sizeof(real) * _cols);
    }
    return result_mat;
}

// Assembly:
subq $0x4a8, %rsp            # imm = 0x4A8
movq %rdi, 0x80(%rsp)
movq %rdi, %rax
movq %rax, 0x88(%rsp)
movq %rdi, 0x4a0(%rsp)
movq %rsi, 0x498(%rsp)
movq 0x498(%rsp), %rcx
movq %rcx, 0x90(%rsp)
movq (%rcx), %rax
cmpq 0x8(%rcx), %rax
sete %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x5c70c
jmp 0x5c777
leaq 0x35625(%rip), %rsi     # 0x91d38
leaq 0x310(%rsp), %rdi
movq %rdi, 0x78(%rsp)
movl $0x122, %edx            # imm = 0x122
movl $0x3, %ecx
callq 0x89860
movq 0x78(%rsp), %rdi
leaq 0x3564d(%rip), %rsi     # 0x91d88
callq 0x5ce20
jmp 0x5c742
leaq 0x310(%rsp), %rdi
callq 0x89c20
jmp 0x5c777
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
leaq 0x310(%rsp), %rdi
callq 0x89c20
jmp 0x5ce11
movq 0x90(%rsp), %rsi
leaq 0x2b0(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x331e0
movq 0x70(%rsp), %rsi
leaq 0x2d8(%rsp), %rdi
callq 0x42350
jmp 0x5c7a5
leaq 0x2b0(%rsp), %rdi
callq 0x31a40
movq 0x90(%rsp), %rax
movq (%rax), %rsi
leaq 0x288(%rsp), %rdi
callq 0x3b500
jmp 0x5c7cc
leaq 0x2d8(%rsp), %rdi
leaq 0x288(%rsp), %rsi
movl $0x1, %edx
callq 0x354b0
jmp 0x5c7e8
leaq 0x288(%rsp), %rdi
callq 0x5ce50
leaq 0x2d8(%rsp), %rdi
callq 0x1a390
movq %rax, 0x68(%rsp)
jmp 0x5c809
movq 0x68(%rsp), %rax
movq %rax, 0x280(%rsp)
leaq 0x2d8(%rsp), %rdi
callq 0x1a3a0
movq %rax, 0x60(%rsp)
jmp 0x5c82a
movq 0x60(%rsp), %rax
movq %rax, 0x278(%rsp)
movq $0x0, 0x270(%rsp)
movq 0x270(%rsp), %rax
cmpq 0x280(%rsp), %rax
je 0x5ca38
movq 0x270(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
movq %rdx, %rsi
callq 0x33f30
movq %rax, 0x58(%rsp)
jmp 0x5c878
movq 0x58(%rsp), %rax
movss (%rax), %xmm0
xorps %xmm1, %xmm1
ucomiss %xmm1, %xmm0
jne 0x5ca1d
jp 0x5ca1d
movq $0x0, 0x268(%rsp)
movq 0x268(%rsp), %rax
cmpq 0x280(%rsp), %rax
je 0x5c995
movq 0x268(%rsp), %rsi
movq 0x270(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x33f30
movq %rax, 0x50(%rsp)
jmp 0x5c8d9
movq 0x50(%rsp), %rax
movss (%rax), %xmm0
xorps %xmm1, %xmm1
ucomiss %xmm1, %xmm0
jne 0x5c8f1
jp 0x5c8f1
jmp 0x5c97a
movq 0x270(%rsp), %rsi
movq 0x268(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x34ad0
jmp 0x5c910
jmp 0x5c995
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
leaq 0x2b0(%rsp), %rdi
callq 0x31a40
jmp 0x5ce11
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
jmp 0x5ce04
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
leaq 0x288(%rsp), %rdi
callq 0x5ce50
jmp 0x5ce04
jmp 0x5c97c
movq 0x268(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x268(%rsp)
jmp 0x5c89f
movq 0x268(%rsp), %rax
cmpq 0x280(%rsp), %rax
setbe %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x5c9b0
jmp 0x5ca1b
leaq 0x35381(%rip), %rsi     # 0x91d38
leaq 0xe0(%rsp), %rdi
movl $0x134, %edx            # imm = 0x134
movl $0x3, %ecx
callq 0x89860
jmp 0x5c9d0
leaq 0x353ce(%rip), %rsi     # 0x91da5
leaq 0xe0(%rsp), %rdi
callq 0x2c010
jmp 0x5c9e6
leaq 0xe0(%rsp), %rdi
callq 0x89c20
jmp 0x5ca1b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0x89c20
jmp 0x5ce04
jmp 0x5ca1d
jmp 0x5ca1f
movq 0x270(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x270(%rsp)
jmp 0x5c843
movq $0x0, 0xd8(%rsp)
movq 0xd8(%rsp), %rax
cmpq 0x280(%rsp), %rax
je 0x5ccbb
movq 0xd8(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
movq %rdx, %rsi
callq 0x33f30
movq %rax, 0x48(%rsp)
jmp 0x5ca79
movq 0x48(%rsp), %rax
movss (%rax), %xmm0
movss %xmm0, 0xd4(%rsp)
movq $0x0, 0xc8(%rsp)
movq 0xc8(%rsp), %rax
cmpq 0x278(%rsp), %rax
jae 0x5cb32
movq 0xd8(%rsp), %rsi
movq 0xc8(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x33f30
movq %rax, 0x40(%rsp)
jmp 0x5cad1
movq 0x40(%rsp), %rax
movss (%rax), %xmm0
movss 0xd4(%rsp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, 0xc4(%rsp)
movq 0xd8(%rsp), %rdx
movq 0xc8(%rsp), %rcx
leaq 0x2d8(%rsp), %rdi
leaq 0xc4(%rsp), %rsi
callq 0x34110
jmp 0x5cb17
jmp 0x5cb19
movq 0xc8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xc8(%rsp)
jmp 0x5ca97
movq $0x0, 0xb8(%rsp)
movq 0xb8(%rsp), %rax
cmpq 0x280(%rsp), %rax
je 0x5cca0
movq 0xb8(%rsp), %rax
cmpq 0xd8(%rsp), %rax
jne 0x5cb6b
jmp 0x5cc87
movq 0xb8(%rsp), %rsi
movq 0xd8(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x33f30
movq %rax, 0x38(%rsp)
jmp 0x5cb8f
movq 0x38(%rsp), %rax
movss (%rax), %xmm0
movss %xmm0, 0xb4(%rsp)
movq $0x0, 0xa8(%rsp)
movq 0xa8(%rsp), %rax
cmpq 0x278(%rsp), %rax
je 0x5cc85
movq 0xb8(%rsp), %rsi
movq 0xa8(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x33f30
movq %rax, 0x30(%rsp)
jmp 0x5cbe7
movq 0x30(%rsp), %rax
movss (%rax), %xmm0
movss %xmm0, 0x24(%rsp)
movq 0xd8(%rsp), %rsi
movq 0xa8(%rsp), %rdx
leaq 0x2d8(%rsp), %rdi
callq 0x33f30
movq %rax, 0x28(%rsp)
jmp 0x5cc1a
movss 0x24(%rsp), %xmm0
movq 0x28(%rsp), %rax
movss (%rax), %xmm1
movss 0xb4(%rsp), %xmm2
mulss %xmm2, %xmm1
subss %xmm1, %xmm0
movss %xmm0, 0xa4(%rsp)
movq 0xb8(%rsp), %rdx
movq 0xa8(%rsp), %rcx
leaq 0x2d8(%rsp), %rdi
leaq 0xa4(%rsp), %rsi
callq 0x34110
jmp 0x5cc6a
jmp 0x5cc6c
movq 0xa8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xa8(%rsp)
jmp 0x5cbad
jmp 0x5cc87
movq 0xb8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xb8(%rsp)
jmp 0x5cb3e
jmp 0x5cca2
movq 0xd8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xd8(%rsp)
jmp 0x5ca44
movq 0x80(%rsp), %rdi
movq 0x90(%rsp), %rax
movb $0x0, 0xa3(%rsp)
movq (%rax), %rsi
movq 0x8(%rax), %rdx
callq 0x33a80
jmp 0x5cce1
movq $0x0, 0x98(%rsp)
movq 0x98(%rsp), %rax
cmpq 0x280(%rsp), %rax
je 0x5cdc8
movq 0x80(%rsp), %rdi
callq 0x19380
movq %rax, 0x18(%rsp)
jmp 0x5cd17
movq 0x18(%rsp), %rax
movq 0x90(%rsp), %rdx
movq 0x98(%rsp), %rcx
movq 0x8(%rdx), %rdx
imulq %rdx, %rcx
leaq (%rax,%rcx,4), %rax
movq %rax, 0x8(%rsp)
leaq 0x2d8(%rsp), %rdi
callq 0x19380
movq %rax, 0x10(%rsp)
jmp 0x5cd51
movq 0x8(%rsp), %rdi
movq 0x90(%rsp), %rax
movq 0x10(%rsp), %rsi
movq 0x98(%rsp), %rcx
imulq 0x278(%rsp), %rcx
addq 0x8(%rax), %rcx
shlq $0x2, %rcx
addq %rcx, %rsi
movq 0x8(%rax), %rdx
shlq $0x2, %rdx
callq 0x9370
movq 0x98(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x98(%rsp)
jmp 0x5cced
movq 0x80(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x308(%rsp)
movl %eax, 0x304(%rsp)
callq 0x33e80
jmp 0x5ce04
movb $0x1, 0xa3(%rsp)
testb $0x1, 0xa3(%rsp)
jne 0x5cde7
movq 0x80(%rsp), %rdi
callq 0x33e80
leaq 0x2d8(%rsp), %rdi
callq 0x33e80
movq 0x88(%rsp), %rax
addq $0x4a8, %rsp            # imm = 0x4A8
retq
leaq 0x2d8(%rsp), %rdi
callq 0x33e80
movq 0x308(%rsp), %rdi
callq 0x9700
nop