// File: /workspace/github_cpp_makefile_star2_O3/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 0x25b70
movl %edx, %ebx
movq %rdi, %r15
leaq 0x34dd2(%rip), %rax     # 0x5a864
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 0x21b82
movq 0x10(%r15), %rdi
movq %r14, %rsi
callq 0x25760
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
callq 0x25760
movsd %xmm0, 0x10(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, 0x8(%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
mulsd (%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
mulsd 0x10(%rsp), %xmm1
addsd %xmm1, %xmm0
jmp 0x25d64
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movapd %xmm0, %xmm1
addsd (%rsp), %xmm1
jmp 0x25d60
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd (%rsp), %xmm1
subsd %xmm0, %xmm1
jmp 0x25d60
leaq 0x34d77(%rip), %rdi     # 0x5a8ee
xorl %eax, %eax
callq 0x29356
xorpd %xmm1, %xmm1
jmp 0x25d60
movq 0x18(%r15), %rdi
movq %r14, %rsi
callq 0x25760
movapd %xmm0, %xmm2
mulsd %xmm0, %xmm2
leaq 0x567f6(%rip), %rax     # 0x7c398
movsd (%rax), %xmm3
movapd 0x334b2(%rip), %xmm1    # 0x59060
xorpd %xmm3, %xmm1
ucomisd %xmm1, %xmm2
jb 0x25c4c
ucomisd %xmm2, %xmm3
jb 0x25c4c
leaq 0x567e3(%rip), %rax     # 0x7c3b0
movsd (%rax), %xmm1
jmp 0x25d60
movq 0x18(%r15), %rdi
callq 0x2418e
movl %eax, %ebp
movq 0x10(%r15), %rdi
movq %r14, %rsi
callq 0x25760
testl %ebp, %ebp
je 0x25cab
movq 0x18(%r15), %rdi
movq %r14, %rsi
movsd %xmm0, 0x10(%rsp)
callq 0x25760
movsd %xmm0, (%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, 0x8(%rsp)
movsd 0x33be0(%rip), %xmm1    # 0x59808
addsd (%rsp), %xmm1
movsd 0x10(%rsp), %xmm0
callq 0x44b0
movapd %xmm0, %xmm1
mulsd (%rsp), %xmm1
mulsd 0x8(%rsp), %xmm1
jmp 0x25d60
movq 0x10(%r15), %rdi
movq %r14, %rsi
movsd %xmm2, 0x10(%rsp)
movsd %xmm0, 0x8(%rsp)
callq 0x25760
movsd %xmm0, 0x18(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd (%rsp), %xmm1
mulsd 0x18(%rsp), %xmm0
mulsd 0x8(%rsp), %xmm1
subsd %xmm0, %xmm1
divsd 0x10(%rsp), %xmm1
jmp 0x25d60
leaq 0x566e6(%rip), %rax     # 0x7c398
movsd (%rax), %xmm2
movapd 0x333a2(%rip), %xmm1    # 0x59060
xorpd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
xorpd %xmm1, %xmm1
jb 0x25cd6
ucomisd %xmm0, %xmm2
jae 0x25d60
movq 0x18(%r15), %rdi
movq %r14, %rsi
movsd %xmm0, 0x10(%rsp)
callq 0x25760
movsd %xmm0, 0x8(%rsp)
movq 0x10(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, (%rsp)
movq 0x18(%r15), %rdi
movq %r14, %rsi
movl %ebx, %edx
callq 0x25a68
movsd %xmm0, 0x18(%rsp)
movsd 0x10(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
callq 0x44b0
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