// File: /workspace/github_cpp_makefile_star2_O2/Eshaancoding[P]AutoDiff/src/Variable/grad.cpp
// Function: Variable::grad(op, double, bool, double, bool)
vector<double> Variable::grad (op last_operation, double ERROR_NODE, bool top_node, double other_value, bool left) {
    static vector<double> GRAD_OUTPUT = {};
    static vector<int> ID_ARRAY = {};
    static vector<int> input_index = {};
    static int INDEX = 0;
    double error = ERROR_NODE;

    if (top_node) {
        this->eval(); // get values
        GRAD_OUTPUT.clear();
        ID_ARRAY.clear();
        input_index.clear();
        INDEX = 0;
        // we already computed error_node (1), pass to sub nodes
    } 
    else {
        // compute error_node
        error *= this->dir_eval(this->value, last_operation, other_value, left);
    }
    // pass error node to sub nodes and execute
    if (this->operation == op::clip) {
        if (this->arg->value >= this->child[0]->value && 
            this->arg->value <= this->child[1]->value) {
            // in range of clip
            this->arg->grad(this->operation, error, false);    
        } else {
            this->arg->grad(this->operation, 0, false);
        }
    }
    else if (this->operation == op::min) {
        // determine what child
        if (this->child[0]->value >= this->child[1]->value) {
            this->child[0]->grad(this->operation, 0, false, this->child[1]->value, false);
            this->child[1]->grad(this->operation, error, false, this->child[0]->value, true); 
        } else {
            this->child[0]->grad(this->operation, error, false, this->child[1]->value, false); 
            this->child[1]->grad(this->operation, 0, false, this->child[0]->value, true); 
        }
    } 
    else if (this->operation == op::max) {
        if (this->child[0]->value >= this->child[1]->value) {
            this->child[0]->grad(this->operation, error, false, this->child[1]->value, true); 
            this->child[1]->grad(this->operation, 0, false, this->child[0]->value, false); 
        } else {
            this->child[0]->grad(this->operation, 0, false, this->child[1]->value, true); 
            this->child[1]->grad(this->operation, error, false, this->child[0]->value, false); 
        }
    }
    else if (this->child[0] != NULL) {
        if (this->child[1] != NULL) {
            // operation is a two parameter function (e.i plus, multiply, subtract, etc...) 
            this->child[0]->grad(this->operation, error, false, this->child[1]->value, true);
            this->child[1]->grad(this->operation, error, false, this->child[0]->value, false);
        } else {
            // operation is a one parameter function (e.i sin, cos, atan)
            this->child[0]->grad(this->operation, error, false);
        }
    } else if (this->operation == op::input) {
        // append to grad_output
        bool find = false;
        for (int i = 0; i < ID_ARRAY.size(); i++) {
            if (this->id == ID_ARRAY[i]) {
                find = true;
                GRAD_OUTPUT[input_index[i]] += error;
                break;
            }
        }
        if (!find) {
            input_index.push_back(INDEX); 
            ID_ARRAY.push_back(this->id);                
            INDEX++;
            GRAD_OUTPUT.push_back(error);
        }
    }
    if (top_node) {
        return GRAD_OUTPUT;
    } else {
        return {};
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x158, %rsp            # imm = 0x158
movl %r8d, %r12d
movl %ecx, %r14d
movl %edx, %r13d
movq %rsi, %r15
movq %rdi, %rbx
movb 0xad8b(%rip), %al       # 0xf1d8
testb %al, %al
movsd %xmm0, -0x30(%rbp)
je 0x485c
movb 0xad98(%rip), %al       # 0xf1f8
testb %al, %al
je 0x48c8
movb 0xadaa(%rip), %al       # 0xf218
testb %al, %al
je 0x4934
movsd %xmm0, -0x40(%rbp)
testb %r14b, %r14b
je 0x44de
pushq $0x1
popq %rsi
movq %r15, %rdi
callq 0x3ce4
movq 0xad2e(%rip), %rax      # 0xf1c0
cmpq %rax, 0xad2f(%rip)      # 0xf1c8
je 0x44a2
movq %rax, 0xad26(%rip)      # 0xf1c8
movq 0xad37(%rip), %rax      # 0xf1e0
cmpq %rax, 0xad38(%rip)      # 0xf1e8
je 0x44b9
movq %rax, 0xad2f(%rip)      # 0xf1e8
movq 0xad40(%rip), %rax      # 0xf200
cmpq %rax, 0xad41(%rip)      # 0xf208
movsd -0x30(%rbp), %xmm2
je 0x44d5
movq %rax, 0xad33(%rip)      # 0xf208
andl $0x0, 0xad44(%rip)      # 0xf220
jmp 0x44fd
movsd (%r15), %xmm0
movzbl %r12b, %edx
movl %r13d, %esi
callq 0x427e
movsd -0x30(%rbp), %xmm2
mulsd %xmm0, %xmm2
movsd %xmm2, -0x40(%rbp)
movl 0x8(%r15), %r12d
cmpl $0x8, %r12d
je 0x45cd
cmpl $0x9, %r12d
je 0x456e
cmpl $0xa, %r12d
jne 0x4631
movq 0x10(%r15), %rax
movq 0x28(%r15), %r12
movsd (%r12), %xmm0
ucomisd (%rax), %xmm0
jb 0x4541
movq 0x18(%r15), %rax
movsd (%rax), %xmm1
ucomisd %xmm0, %xmm1
jae 0x478a
leaq 0x5d6a(%rip), %rdi      # 0xa2b2
callq 0x2040
movapd %xmm0, %xmm1
leaq -0x160(%rbp), %r15
pushq $0xa
popq %rdx
pushq $0x1
popq %r8
xorpd %xmm0, %xmm0
movq %r15, %rdi
movq %r12, %rsi
jmp 0x47db
movq 0x10(%r15), %rsi
movq 0x18(%r15), %rax
movsd (%rsi), %xmm0
movsd (%rax), %xmm1
ucomisd %xmm1, %xmm0
jae 0x4697
leaq -0xb8(%rbp), %r12
pushq $0x9
popq %rdx
pushq $0x1
popq %r8
xorpd %xmm0, %xmm0
movq %r12, %rdi
xorl %ecx, %ecx
movsd %xmm2, -0x30(%rbp)
callq 0x4424
movq %r12, %rdi
callq 0x4a4a
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0xa0(%rbp), %r15
jmp 0x468d
movq 0x10(%r15), %rsi
movq 0x18(%r15), %rax
movsd (%rsi), %xmm0
movsd (%rax), %xmm1
ucomisd %xmm1, %xmm0
jae 0x46e3
leaq -0x118(%rbp), %r12
pushq $0x8
popq %rdx
movq %r12, %rdi
movapd %xmm2, %xmm0
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x4424
movq %r12, %rdi
callq 0x4a4a
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x100(%rbp), %r15
pushq $0x1
popq %r8
xorpd %xmm0, %xmm0
movq %r15, %rdi
jmp 0x47db
movq 0x10(%r15), %r13
testq %r13, %r13
je 0x472e
movq 0x18(%r15), %rax
testq %rax, %rax
movsd %xmm2, -0x30(%rbp)
je 0x47b5
movsd (%rax), %xmm1
leaq -0x58(%rbp), %rdi
pushq $0x1
popq %r8
movq %r13, %rsi
movl %r12d, %edx
movapd %xmm2, %xmm0
xorl %ecx, %ecx
callq 0x4424
leaq -0x58(%rbp), %rdi
callq 0x4a4a
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x88(%rbp), %r15
movq %r15, %rdi
movsd -0x30(%rbp), %xmm0
jmp 0x46d9
leaq -0xe8(%rbp), %r12
pushq $0x9
popq %rdx
pushq $0x1
popq %r8
movq %r12, %rdi
movapd %xmm2, %xmm0
xorl %ecx, %ecx
callq 0x4424
movq %r12, %rdi
callq 0x4a4a
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0xd0(%rbp), %r15
xorpd %xmm0, %xmm0
movq %r15, %rdi
xorl %ecx, %ecx
xorl %r8d, %r8d
jmp 0x47dd
leaq -0x148(%rbp), %r12
pushq $0x8
popq %rdx
xorpd %xmm0, %xmm0
movq %r12, %rdi
xorl %ecx, %ecx
xorl %r8d, %r8d
movsd %xmm2, -0x30(%rbp)
callq 0x4424
movq %r12, %rdi
callq 0x4a4a
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x130(%rbp), %r15
pushq $0x1
popq %r8
movq %r15, %rdi
jmp 0x47d6
testl %r12d, %r12d
jne 0x47ea
movq 0xaaaa(%rip), %rax      # 0xf1e8
movq 0xaa9b(%rip), %rcx      # 0xf1e0
subq %rcx, %rax
sarq $0x2, %rax
movl 0x20(%r15), %edx
addq $0x20, %r15
xorl %esi, %esi
cmpq %rsi, %rax
je 0x4822
leaq 0x1(%rsi), %rdi
cmpl (%rcx,%rsi,4), %edx
movq %rdi, %rsi
jne 0x4756
movq 0xaa8e(%rip), %rax      # 0xf200
movslq -0x4(%rax,%rdi,4), %rax
movq 0xaa42(%rip), %rcx      # 0xf1c0
addsd (%rcx,%rax,8), %xmm2
movsd %xmm2, (%rcx,%rax,8)
jmp 0x47ea
leaq 0x5b21(%rip), %rdi      # 0xa2b2
movsd %xmm2, -0x30(%rbp)
callq 0x2040
movapd %xmm0, %xmm1
leaq -0x178(%rbp), %r15
pushq $0xa
popq %rdx
pushq $0x1
popq %r8
movq %r15, %rdi
movq %r12, %rsi
jmp 0x47d6
leaq 0x5af6(%rip), %rdi      # 0xa2b2
callq 0x2040
movapd %xmm0, %xmm1
leaq -0x70(%rbp), %r15
pushq $0x1
popq %r8
movq %r15, %rdi
movq %r13, %rsi
movl %r12d, %edx
movsd -0x30(%rbp), %xmm0
xorl %ecx, %ecx
callq 0x4424
movq %r15, %rdi
callq 0x4a4a
testb %r14b, %r14b
je 0x4800
leaq 0xa9ca(%rip), %rsi      # 0xf1c0
movq %rbx, %rdi
callq 0x49e2
jmp 0x480d
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
andq $0x0, 0x10(%rbx)
movq %rbx, %rax
addq $0x158, %rsp            # imm = 0x158
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xa9d7(%rip), %rdi      # 0xf200
leaq 0xa9f0(%rip), %rsi      # 0xf220
callq 0x4048
leaq 0xa9a4(%rip), %rdi      # 0xf1e0
movq %r15, %rsi
callq 0x4048
incl 0xa9d6(%rip)            # 0xf220
leaq 0xa96f(%rip), %rdi      # 0xf1c0
leaq -0x40(%rbp), %rsi
callq 0x49b8
jmp 0x47ea
leaq 0xa975(%rip), %rdi      # 0xf1d8
movsd %xmm1, -0x38(%rbp)
callq 0x2240
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
testl %eax, %eax
je 0x445a
xorpd %xmm0, %xmm0
movupd %xmm0, 0xa935(%rip)     # 0xf1c0
andq $0x0, 0xa93d(%rip)      # 0xf1d0
leaq 0xa926(%rip), %rsi      # 0xf1c0
leaq 0x10d(%rip), %rdi       # 0x49ae
leaq 0xa8a8(%rip), %rdx      # 0xf150
callq 0x2130
leaq 0xa924(%rip), %rdi      # 0xf1d8
callq 0x2100
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
jmp 0x445a
leaq 0xa929(%rip), %rdi      # 0xf1f8
movsd %xmm1, -0x38(%rbp)
callq 0x2240
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
testl %eax, %eax
je 0x4468
xorpd %xmm0, %xmm0
movupd %xmm0, 0xa8e9(%rip)     # 0xf1e0
andq $0x0, 0xa8f1(%rip)      # 0xf1f0
leaq 0xa8da(%rip), %rsi      # 0xf1e0
leaq -0x8cf(%rip), %rdi      # 0x403e
leaq 0xa83c(%rip), %rdx      # 0xf150
callq 0x2130
leaq 0xa8d8(%rip), %rdi      # 0xf1f8
callq 0x2100
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
jmp 0x4468
leaq 0xa8dd(%rip), %rdi      # 0xf218
movsd %xmm1, -0x38(%rbp)
callq 0x2240
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
testl %eax, %eax
je 0x4476
xorpd %xmm0, %xmm0
movupd %xmm0, 0xa89d(%rip)     # 0xf200
andq $0x0, 0xa8a5(%rip)      # 0xf210
leaq 0xa88e(%rip), %rsi      # 0xf200
leaq -0x93b(%rip), %rdi      # 0x403e
leaq 0xa7d0(%rip), %rdx      # 0xf150
callq 0x2130
leaq 0xa88c(%rip), %rdi      # 0xf218
callq 0x2100
movsd -0x38(%rbp), %xmm1
movsd -0x30(%rbp), %xmm0
jmp 0x4476