def _TR56(rv, f, g, h, max, pow):
 def _f(rv):
  if (not (rv.is_Pow and (rv.base.func == f))):
   return rv
  if ((rv.exp < 0) == True):
   return rv
  if ((rv.exp > max) == True):
   return rv
  if (rv.exp == 2):
   return h((g(rv.base.args[0]) ** 2))
  else:
   if (rv.exp == 4):
    e = 2
   elif (not pow):
    if (rv.exp % 2):
     return rv
    e = (rv.exp // 2)
   else:
    p = perfect_power(rv.exp)
    if (not p):
     return rv
    e = (rv.exp // 2)
   return (h((g(rv.base.args[0]) ** 2)) ** e)
 return bottom_up(rv, _f)

def _TR56 ( rv , f , g , h , max , pow ) : def _f ( rv ) : if ( not ( rv . is_Pow and ( rv . base . func == f ) ) ) : return rv if ( ( rv . exp < 0 ) == True ) : return rv if ( ( rv . exp > max ) == True ) : return rv if ( rv . exp == 2 ) : return h ( ( g ( rv . base . args [ 0 ] ) ** 2 ) ) else : if ( rv . exp == 4 ) : e = 2 elif ( not pow ) : if ( rv . exp % 2 ) : return rv e = ( rv . exp // 2 ) else : p = perfect_power ( rv . exp ) if ( not p ) : return rv e = ( rv . exp // 2 ) return ( h ( ( g ( rv . base . args [ 0 ] ) ** 2 ) ) ** e ) return bottom_up ( rv , _f )
helper for tr5 and tr6 to replace f**2 with h options max : controls size of exponent that can appear on f e .