def power(self, o, fp, gp): f, g = o.ufl_operands if not is_true_ufl_scalar(f): error("Expecting scalar expression f in f**g.") if not is_true_ufl_scalar(g): error("Expecting scalar expression g in f**g.") # Derivation of the general case: o = f(x)**g(x) # do/df = g * f**(g-1) = g / f * o # do/dg = ln(f) * f**g = ln(f) * o # do/df * df + do/dg * dg = o * (g / f * df + ln(f) * dg) if isinstance(gp, Zero): # This probably produces better results for the common # case of f**constant op = fp * g * f**(g - 1) else: # Note: This produces expressions like (1/w)*w**5 instead of w**4 # op = o * (fp * g / f + gp * ln(f)) # This reuses o op = f**(g - 1) * ( g * fp + f * ln(f) * gp ) # This gives better accuracy in dolfin integration test # Example: d/dx[x**(x**3)]: # f = x # g = x**3 # df = 1 # dg = 3*x**2 # op1 = o * (fp * g / f + gp * ln(f)) # = x**(x**3) * (x**3/x + 3*x**2*ln(x)) # op2 = f**(g-1) * (g*fp + f*ln(f)*gp) # = x**(x**3-1) * (x**3 + x*3*x**2*ln(x)) return op
def power(self, o, fp, gp): f, g = o.ufl_operands if not is_true_ufl_scalar(f): error("Expecting scalar expression f in f**g.") if not is_true_ufl_scalar(g): error("Expecting scalar expression g in f**g.") # Derivation of the general case: o = f(x)**g(x) # do/df = g * f**(g-1) = g / f * o # do/dg = ln(f) * f**g = ln(f) * o # do/df * df + do/dg * dg = o * (g / f * df + ln(f) * dg) if isinstance(gp, Zero): # This probably produces better results for the common # case of f**constant op = fp * g * f**(g-1) else: # Note: This produces expressions like (1/w)*w**5 instead of w**4 # op = o * (fp * g / f + gp * ln(f)) # This reuses o op = f**(g-1) * (g*fp + f*ln(f)*gp) # This gives better accuracy in dolfin integration test # Example: d/dx[x**(x**3)]: # f = x # g = x**3 # df = 1 # dg = 3*x**2 # op1 = o * (fp * g / f + gp * ln(f)) # = x**(x**3) * (x**3/x + 3*x**2*ln(x)) # op2 = f**(g-1) * (g*fp + f*ln(f)*gp) # = x**(x**3-1) * (x**3 + x*3*x**2*ln(x)) return op
def power(self, f): """f = x**y d/dx x**y = y*x**(y-1) = y*f/x d/dy x**y = ln(x)*x**y = ln(x)*f""" x, y = f.operands() dx = y*f/x dy = ln(x)*f return (dx, dy)
def power(self, o, a, b): f, fp = a g, gp = b # Debugging prints, should never happen: if not is_true_ufl_scalar(f): print ":" * 80 print "f =", str(f) print "g =", str(g) print ":" * 80 ufl_assert(is_true_ufl_scalar(f), "Expecting scalar expression f in f**g.") ufl_assert(is_true_ufl_scalar(g), "Expecting scalar expression g in f**g.") # Derivation of the general case: o = f(x)**g(x) # #do_df = g * f**(g-1) #do_dg = ln(f) * f**g #op = do_df*fp + do_dg*gp # #do_df = o * g / f # f**g * g / f #do_dg = ln(f) * o #op = do_df*fp + do_dg*gp # Got two possible alternatives here: if True: # This version looks better. # Rewriting o as f*f**(g-1) we can do: f_g_m1 = f**(g - 1) op = f_g_m1 * (fp * g + f * ln(f) * gp) # In this case we can rewrite o using new subexpression o = f * f_g_m1 else: # Pulling o out gives: op = o * (fp * g / f + ln(f) * gp) # This produces expressions like (1/w)*w**5 instead of w**4 # If we do this, we reuse o o = self.reuse_if_possible(o, f, g) return (o, op)
def power(self, o, a, b): f, fp = a g, gp = b # Debugging prints, should never happen: if not is_true_ufl_scalar(f): print ":"*80 print "f =", str(f) print "g =", str(g) print ":"*80 ufl_assert(is_true_ufl_scalar(f), "Expecting scalar expression f in f**g.") ufl_assert(is_true_ufl_scalar(g), "Expecting scalar expression g in f**g.") # Derivation of the general case: o = f(x)**g(x) # #do_df = g * f**(g-1) #do_dg = ln(f) * f**g #op = do_df*fp + do_dg*gp # #do_df = o * g / f # f**g * g / f #do_dg = ln(f) * o #op = do_df*fp + do_dg*gp # Got two possible alternatives here: if True: # This version looks better. # Rewriting o as f*f**(g-1) we can do: f_g_m1 = f**(g-1) op = f_g_m1*(fp*g + f*ln(f)*gp) # In this case we can rewrite o using new subexpression o = f*f_g_m1 else: # Pulling o out gives: op = o*(fp*g/f + ln(f)*gp) # This produces expressions like (1/w)*w**5 instead of w**4 # If we do this, we reuse o o = self.reuse_if_possible(o, f, g) return (o, op)