// File: /workspace/github_cpp_makefile_star2_O1/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 0xa6f9(%rip), %al       # 0xf1e8
testb %al, %al
je 0x4fa5
movb 0xa70b(%rip), %al       # 0xf208
testb %al, %al
je 0x4fc3
movb 0xa71d(%rip), %al       # 0xf228
testb %al, %al
je 0x4fe1
movsd %xmm0, -0x30(%rbp)
testb %r14b, %r14b
je 0x4b7b
movq %r15, %rdi
movl $0x1, %esi
callq 0x42b6
movq 0xa69f(%rip), %rax      # 0xf1d0
cmpq %rax, 0xa6a0(%rip)      # 0xf1d8
je 0x4b41
movq %rax, 0xa697(%rip)      # 0xf1d8
movq 0xa6a8(%rip), %rax      # 0xf1f0
cmpq %rax, 0xa6a9(%rip)      # 0xf1f8
je 0x4b58
movq %rax, 0xa6a0(%rip)      # 0xf1f8
movq 0xa6b1(%rip), %rax      # 0xf210
cmpq %rax, 0xa6b2(%rip)      # 0xf218
je 0x4b6f
movq %rax, 0xa6a9(%rip)      # 0xf218
movl $0x0, 0xa6b7(%rip)      # 0xf230
jmp 0x4b96
movsd (%r15), %xmm0
movzbl %r12b, %edx
movl %r13d, %esi
callq 0x4916
mulsd -0x30(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
movl 0x8(%r15), %r12d
cmpl $0x8, %r12d
je 0x4c6c
cmpl $0x9, %r12d
je 0x4c03
cmpl $0xa, %r12d
jne 0x4cd2
movq 0x10(%r15), %rax
movq 0x28(%r15), %r13
movsd (%r13), %xmm0
ucomisd (%rax), %xmm0
jb 0x4bda
movq 0x18(%r15), %rax
movsd (%rax), %xmm1
ucomisd %xmm0, %xmm1
jae 0x4e4c
leaq 0x56f1(%rip), %rdi      # 0xa2d2
callq 0x2050
movapd %xmm0, %xmm1
leaq -0x160(%rbp), %r15
xorpd %xmm0, %xmm0
movq %r15, %rdi
movq %r13, %rsi
movl %r12d, %edx
jmp 0x4ea1
movq 0x10(%r15), %rsi
movq 0x18(%r15), %rax
movsd (%rsi), %xmm0
movsd (%rax), %xmm1
ucomisd %xmm1, %xmm0
jae 0x4d3b
leaq -0xb8(%rbp), %r12
xorpd %xmm0, %xmm0
movq %r12, %rdi
movl $0x9, %edx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x4ac6
movq (%r12), %rdi
testq %rdi, %rdi
je 0x4c4b
callq 0x2170
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movsd -0x30(%rbp), %xmm0
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0xa0(%rbp), %r15
jmp 0x4d85
movq 0x10(%r15), %rsi
movq 0x18(%r15), %rax
movsd (%rsi), %xmm0
movsd (%rax), %xmm1
ucomisd %xmm1, %xmm0
jae 0x4d92
movsd -0x30(%rbp), %xmm0
leaq -0x118(%rbp), %r12
movq %r12, %rdi
movl $0x8, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x4ac6
movq (%r12), %rdi
testq %rdi, %rdi
je 0x4cb2
callq 0x2170
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x100(%rbp), %r15
xorpd %xmm0, %xmm0
jmp 0x4dd9
movq 0x10(%r15), %r13
testq %r13, %r13
je 0x4de1
movq 0x18(%r15), %rax
movsd -0x30(%rbp), %xmm0
testq %rax, %rax
je 0x4e7a
movsd (%rax), %xmm1
leaq -0x58(%rbp), %rdi
movq %r13, %rsi
movl %r12d, %edx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x4ac6
leaq -0x58(%rbp), %rax
movq (%rax), %rdi
testq %rdi, %rdi
je 0x4d1d
callq 0x2170
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movsd -0x30(%rbp), %xmm0
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x88(%rbp), %r15
jmp 0x4d85
movsd -0x30(%rbp), %xmm0
leaq -0xe8(%rbp), %r12
movq %r12, %rdi
movl $0x9, %edx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x4ac6
movq (%r12), %rdi
testq %rdi, %rdi
je 0x4d6a
callq 0x2170
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 0x4ea9
leaq -0x148(%rbp), %r12
xorpd %xmm0, %xmm0
movq %r12, %rdi
movl $0x8, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x4ac6
movq (%r12), %rdi
testq %rdi, %rdi
je 0x4dbd
callq 0x2170
movq 0x18(%r15), %rsi
movl 0x8(%r15), %edx
movsd -0x30(%rbp), %xmm0
movq 0x10(%r15), %rax
movsd (%rax), %xmm1
leaq -0x130(%rbp), %r15
movq %r15, %rdi
jmp 0x4ea1
testl %r12d, %r12d
jne 0x4ebb
movq 0xa407(%rip), %rax      # 0xf1f8
movq 0xa3f8(%rip), %rcx      # 0xf1f0
subq %rcx, %rax
je 0x4e20
sarq $0x2, %rax
movl 0x20(%r15), %edx
cmpq $0x1, %rax
adcq $0x0, %rax
xorl %esi, %esi
cmpl (%rcx,%rsi,4), %edx
je 0x4ef6
incq %rsi
cmpq %rsi, %rax
jne 0x4e0f
movq 0xa3f1(%rip), %rsi      # 0xf218
cmpq 0xa3f2(%rip), %rsi      # 0xf220
je 0x4f19
movl 0xa3f6(%rip), %eax      # 0xf230
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0xa3d1(%rip)      # 0xf218
jmp 0x4f2c
movsd -0x30(%rbp), %xmm0
movsd %xmm0, -0x38(%rbp)
leaq 0x5475(%rip), %rdi      # 0xa2d2
callq 0x2050
movapd %xmm0, %xmm1
leaq -0x178(%rbp), %r15
movq %r15, %rdi
movq %r13, %rsi
movl $0xa, %edx
jmp 0x4e9c
leaq 0x5451(%rip), %rdi      # 0xa2d2
movsd %xmm0, -0x38(%rbp)
callq 0x2050
movapd %xmm0, %xmm1
leaq -0x70(%rbp), %r15
movq %r15, %rdi
movq %r13, %rsi
movl %r12d, %edx
movsd -0x38(%rbp), %xmm0
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x4ac6
movq (%r15), %rdi
testq %rdi, %rdi
je 0x4ebb
callq 0x2170
testb %r14b, %r14b
je 0x4ed1
leaq 0xa309(%rip), %rsi      # 0xf1d0
movq %rbx, %rdi
callq 0x5014
jmp 0x4ee1
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
movq $0x0, 0x10(%rbx)
movq %rbx, %rax
addq $0x158, %rsp            # imm = 0x158
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd -0x30(%rbp), %xmm0
movq 0xa30e(%rip), %rax      # 0xf210
movslq (%rax,%rsi,4), %rax
movq 0xa2c3(%rip), %rcx      # 0xf1d0
addsd (%rcx,%rax,8), %xmm0
movsd %xmm0, (%rcx,%rax,8)
jmp 0x4ebb
leaq 0xa2f0(%rip), %rdi      # 0xf210
leaq 0xa309(%rip), %rdx      # 0xf230
callq 0x46fe
addq $0x20, %r15
movq 0xa2c1(%rip), %rsi      # 0xf1f8
cmpq 0xa2c2(%rip), %rsi      # 0xf200
je 0x4f52
movl (%r15), %eax
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0xa2a8(%rip)      # 0xf1f8
jmp 0x4f61
leaq 0xa297(%rip), %rdi      # 0xf1f0
movq %r15, %rdx
callq 0x46fe
incl 0xa2c9(%rip)            # 0xf230
movq 0xa26a(%rip), %rsi      # 0xf1d8
cmpq 0xa26b(%rip), %rsi      # 0xf1e0
je 0x4f90
movsd -0x30(%rbp), %xmm0
movsd %xmm0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0xa24d(%rip)      # 0xf1d8
jmp 0x4ebb
leaq 0xa239(%rip), %rdi      # 0xf1d0
leaq -0x30(%rbp), %rdx
callq 0x5094
jmp 0x4ebb
movsd %xmm1, -0x38(%rbp)
movsd %xmm0, -0x40(%rbp)
callq 0x2372
movsd -0x40(%rbp), %xmm0
movsd -0x38(%rbp), %xmm1
jmp 0x4af7
movsd %xmm1, -0x38(%rbp)
movsd %xmm0, -0x40(%rbp)
callq 0x23c1
movsd -0x40(%rbp), %xmm0
movsd -0x38(%rbp), %xmm1
jmp 0x4b05
movsd %xmm1, -0x38(%rbp)
movsd %xmm0, -0x40(%rbp)
callq 0x2410
movsd -0x40(%rbp), %xmm0
movsd -0x38(%rbp), %xmm1
jmp 0x4b13
nop