def _to_angle((x,y)): from sage.functions.trig import arctan, arccot from sage.symbolic.all import pi if x >= -y and x >= y: return arctan(y/x) if x >= -y and x < y: return arccot(x/y) if x < -y and x < y: return pi+arctan(y/x) if x < -y and x >= y: return pi+arccot(x/y)
def subexpressions_list(f, pars=None): """ Construct the lists with the intermediate steps on the evaluation of the function. INPUT: - ``f`` -- a symbolic function of several components. - ``pars`` -- a list of the parameters that appear in the function this should be the symbolic constants that appear in f but are not arguments. OUTPUT: - a list of the intermediate subexpressions that appear in the evaluation of f. - a list with the operations used to construct each of the subexpressions. each element of this list is a tuple, formed by a string describing the operation made, and the operands. For the trigonometric functions, some extra expressions will be added. These extra expressions will be used later to compute their derivatives. EXAMPLES:: sage: from sage.interfaces.tides import subexpressions_list sage: var('x,y') (x, y) sage: f(x,y) = [x^2+y, cos(x)/log(y)] sage: subexpressions_list(f) ([x^2, x^2 + y, sin(x), cos(x), log(y), cos(x)/log(y)], [('mul', x, x), ('add', y, x^2), ('sin', x), ('cos', x), ('log', y), ('div', log(y), cos(x))]) :: sage: f(a)=[cos(a), arctan(a)] sage: from sage.interfaces.tides import subexpressions_list sage: subexpressions_list(f) ([sin(a), cos(a), a^2, a^2 + 1, arctan(a)], [('sin', a), ('cos', a), ('mul', a, a), ('add', 1, a^2), ('atan', a)]) :: sage: from sage.interfaces.tides import subexpressions_list sage: var('s,b,r') (s, b, r) sage: f(t,x,y,z)= [s*(y-x),x*(r-z)-y,x*y-b*z] sage: subexpressions_list(f,[s,b,r]) ([-y, x - y, s*(x - y), -s*(x - y), -z, r - z, (r - z)*x, -y, (r - z)*x - y, x*y, b*z, -b*z, x*y - b*z], [('mul', -1, y), ('add', -y, x), ('mul', x - y, s), ('mul', -1, s*(x - y)), ('mul', -1, z), ('add', -z, r), ('mul', x, r - z), ('mul', -1, y), ('add', -y, (r - z)*x), ('mul', y, x), ('mul', z, b), ('mul', -1, b*z), ('add', -b*z, x*y)]) :: sage: var('x, y') (x, y) sage: f(x,y)=[exp(x^2+sin(y))] sage: from sage.interfaces.tides import * sage: subexpressions_list(f) ([x^2, sin(y), cos(y), x^2 + sin(y), e^(x^2 + sin(y))], [('mul', x, x), ('sin', y), ('cos', y), ('add', sin(y), x^2), ('exp', x^2 + sin(y))]) """ from sage.functions.trig import sin, cos, arcsin, arctan, arccos variables = f[0].arguments() if not pars: parameters = [] else: parameters = pars varpar = list(parameters) + list(variables) F = symbolic_expression([i(*variables) for i in f]).function(*varpar) lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1) stack = [] const =[] stackcomp=[] detail=[] for i in lis: if i[0] == 'load_arg': stack.append(varpar[i[1]]) elif i[0] == 'ipow': if i[1] in NN: basis = stack[-1] for j in range(i[1]-1): a=stack.pop(-1) detail.append(('mul', a, basis)) stack.append(a*basis) stackcomp.append(stack[-1]) else: detail.append(('pow',stack[-1],i[1])) stack[-1]=stack[-1]**i[1] stackcomp.append(stack[-1]) elif i[0] == 'load_const': const.append(i[1]) stack.append(i[1]) elif i == 'mul': a=stack.pop(-1) b=stack.pop(-1) detail.append(('mul', a, b)) stack.append(a*b) stackcomp.append(stack[-1]) elif i == 'div': a=stack.pop(-1) b=stack.pop(-1) detail.append(('div', a, b)) stack.append(b/a) stackcomp.append(stack[-1]) elif i == 'add': a=stack.pop(-1) b=stack.pop(-1) detail.append(('add',a,b)) stack.append(a+b) stackcomp.append(stack[-1]) elif i == 'pow': a=stack.pop(-1) b=stack.pop(-1) detail.append(('pow', b, a)) stack.append(b**a) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='log': a=stack.pop(-1) detail.append(('log', a)) stack.append(log(a)) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='exp': a=stack.pop(-1) detail.append(('exp', a)) stack.append(exp(a)) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='sin': a=stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(sin(a)) elif i[0] == 'py_call' and str(i[1])=='cos': a=stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(cos(a)) elif i[0] == 'py_call' and str(i[1])=='tan': a=stack.pop(-1) b = sin(a) c = cos(a) detail.append(('sin', a)) detail.append(('cos', a)) detail.append(('div', b, c)) stackcomp.append(b) stackcomp.append(c) stackcomp.append(b/c) stack.append(b/c) elif i[0] == 'py_call' and str(i[1])=='arctan': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('add', 1, a*a)) detail.append(('atan', a)) stackcomp.append(a*a) stackcomp.append(1+a*a) stackcomp.append(arctan(a)) stack.append(arctan(a)) elif i[0] == 'py_call' and str(i[1])=='arcsin': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) detail.append(('pow', 1- a*a, 0.5)) detail.append(('asin', a)) stackcomp.append(a*a) stackcomp.append(-a*a) stackcomp.append(1-a*a) stackcomp.append(sqrt(1-a*a)) stackcomp.append(arcsin(a)) stack.append(arcsin(a)) elif i[0] == 'py_call' and str(i[1])=='arccos': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) detail.append(('pow', 1- a*a, 0.5)) detail.append(('mul', -1, sqrt(1-a*a))) detail.append(('acos', a)) stackcomp.append(a*a) stackcomp.append(-a*a) stackcomp.append(1-a*a) stackcomp.append(sqrt(1-a*a)) stackcomp.append(-sqrt(1-a*a)) stackcomp.append(arccos(a)) stack.append(arccos(a)) elif i[0] == 'py_call' and 'sqrt' in str(i[1]): a=stack.pop(-1) detail.append(('pow', a, 0.5)) stackcomp.append(sqrt(a)) stack.append(sqrt(a)) elif i == 'neg': a = stack.pop(-1) detail.append(('mul', -1, a)) stack.append(-a) stackcomp.append(-a) return stackcomp,detail
def arg(x, y): return arctan(y / x) # up to a constant, but it doesn't matter
def arg(x,y): return arctan(y/x) # up to a constant, but it doesn't matter