// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/RNMath/RNAlgebraic.cpp
// Function: gaps::RNAlgebraic::PartialDerivative(double const*, int) const
RNScalar RNAlgebraic::
PartialDerivative(const RNScalar *x, int variable) const
{
  // Return partial derivative
  switch(operation) {
  case RN_ZERO_OPERATION: 
    return 0;
    
  case RN_POLYNOMIAL_OPERATION:
    return polynomial->PartialDerivative(x, variable);

  case RN_ADD_OPERATION: 
    return operands[0]->PartialDerivative(x, variable) + operands[1]->PartialDerivative(x, variable);

  case RN_SUBTRACT_OPERATION: 
    return operands[0]->PartialDerivative(x, variable) - operands[1]->PartialDerivative(x, variable);

  case RN_MULTIPLY_OPERATION: {
    // Product rule
    RNScalar v0 = operands[0]->Evaluate(x);
    RNScalar v1 = operands[1]->Evaluate(x);
    RNScalar d0 = operands[0]->PartialDerivative(x, variable);
    RNScalar d1 = operands[1]->PartialDerivative(x, variable);
    return d0*v1 + v0*d1; }

  case RN_DIVIDE_OPERATION: {
    // Quotion rule
    RNScalar v1 = operands[1]->Evaluate(x);
    RNScalar v1_squared = v1 * v1;
    if (RNIsZero(v1_squared, RN_SMALL_EPSILON)) return RN_INFINITY;
    RNScalar v0 = operands[0]->Evaluate(x);
    RNScalar d0 = operands[0]->PartialDerivative(x, variable);
    RNScalar d1 = operands[1]->PartialDerivative(x, variable);
    return (d0*v1 - v0*d1) / v1_squared; }
  
  case RN_POW_OPERATION: 
    // Power rule
    if (operands[1]->IsConstant()) {
      RNScalar v0 = operands[0]->Evaluate(x);
      RNScalar v1 = operands[1]->Evaluate(x);
      RNScalar d0 = operands[0]->PartialDerivative(x, variable);
      return v1 * pow(v0, v1-1.0) * d0;
    }
    else {
      RNScalar v0 = operands[0]->Evaluate(x);
      if (RNIsZero(v0, RN_SMALL_EPSILON)) return 0;
      RNScalar v1 = operands[1]->Evaluate(x);
      RNScalar d0 = operands[0]->PartialDerivative(x, variable);
      RNScalar d1 = operands[1]->PartialDerivative(x, variable);
      return pow(v0, v1) * (d0*v1/v0 + d1*log(v0)); 
    }
  }    

  // Should never get here
  RNAbort("Invalid algebraic operation: %d", operation);
  return 0.0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x28, %rsp
movq %rsi, %r14
movl 0x8(%rdi), %esi
xorpd %xmm1, %xmm1
cmpq $0x6, %rsi
ja 0x2321e
movl %edx, %ebx
movq %rdi, %r15
leaq 0x2f8d0(%rip), %rax     # 0x52a10
movslq (%rax,%rsi,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq 0x20(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
addq $0x28, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
jmp 0x1f6d0
movq 0x10(%r15), %rdi
movq %r14, %rsi
callq 0x22e0e
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
callq 0x22e0e
movsd %xmm0, 0x10(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, 0x8(%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
mulsd (%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
mulsd 0x10(%rsp), %xmm1
addsd %xmm1, %xmm0
jmp 0x23412
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movapd %xmm0, %xmm1
addsd (%rsp), %xmm1
jmp 0x2340e
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd (%rsp), %xmm1
subsd %xmm0, %xmm1
jmp 0x2340e
leaq 0x2f875(%rip), %rdi     # 0x52a9a
xorl %eax, %eax
callq 0x264a8
xorpd %xmm1, %xmm1
jmp 0x2340e
movq 0x18(%r15), %rdi
movq %r14, %rsi
callq 0x22e0e
movapd %xmm0, %xmm2
mulsd %xmm0, %xmm2
leaq 0x54150(%rip), %rax     # 0x773a0
movsd (%rax), %xmm3
movapd 0x2de04(%rip), %xmm1    # 0x51060
xorpd %xmm3, %xmm1
ucomisd %xmm1, %xmm2
jb 0x232fa
ucomisd %xmm2, %xmm3
jb 0x232fa
leaq 0x5413d(%rip), %rax     # 0x773b8
movsd (%rax), %xmm1
jmp 0x2340e
movq 0x18(%r15), %rdi
callq 0x21b1e
movl %eax, %ebp
movq 0x10(%r15), %rdi
movq %r14, %rsi
callq 0x22e0e
testl %ebp, %ebp
je 0x23359
movq 0x18(%r15), %rdi
movq %r14, %rsi
movsd %xmm0, 0x10(%rsp)
callq 0x22e0e
movsd %xmm0, (%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, 0x8(%rsp)
movsd 0x2e72a(%rip), %xmm1    # 0x51a00
addsd (%rsp), %xmm1
movsd 0x10(%rsp), %xmm0
callq 0x44c0
movapd %xmm0, %xmm1
mulsd (%rsp), %xmm1
mulsd 0x8(%rsp), %xmm1
jmp 0x2340e
movq 0x10(%r15), %rdi
movq %r14, %rsi
movsd %xmm2, 0x10(%rsp)
movsd %xmm0, 0x8(%rsp)
callq 0x22e0e
movsd %xmm0, 0x18(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd (%rsp), %xmm1
mulsd 0x18(%rsp), %xmm0
mulsd 0x8(%rsp), %xmm1
subsd %xmm0, %xmm1
divsd 0x10(%rsp), %xmm1
jmp 0x2340e
leaq 0x54040(%rip), %rax     # 0x773a0
movsd (%rax), %xmm2
movapd 0x2dcf4(%rip), %xmm1    # 0x51060
xorpd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
xorpd %xmm1, %xmm1
jb 0x23384
ucomisd %xmm0, %xmm2
jae 0x2340e
movq 0x18(%r15), %rdi
movq %r14, %rsi
movsd %xmm0, 0x10(%rsp)
callq 0x22e0e
movsd %xmm0, 0x8(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x23116
movsd %xmm0, 0x18(%rsp)
movsd 0x10(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x44c0
movsd %xmm0, 0x20(%rsp)
movsd (%rsp), %xmm1
mulsd 0x8(%rsp), %xmm1
movsd 0x10(%rsp), %xmm0
divsd %xmm0, %xmm1
movsd %xmm1, (%rsp)
callq 0x41d0
movapd %xmm0, %xmm1
mulsd 0x18(%rsp), %xmm1
addsd (%rsp), %xmm1
mulsd 0x20(%rsp), %xmm1
movapd %xmm1, %xmm0
addq $0x28, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
nop