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
first_vector=first_point-center second_vector=second_point-center radius=norm(first_vector) if norm(second_vector)!=radius: raise ValueError("Ellipse not implemented") first_unit_vector=first_vector/radius second_unit_vector=second_vector/radius normal_vector=second_vector-(second_vector*first_unit_vector)*first_unit_vector if norm(normal_vector)==0: print (first_point,second_point) return normal_unit_vector=normal_vector/norm(normal_vector) scalar_product=first_unit_vector*second_unit_vector if abs(scalar_product) == 1: raise ValueError("The points are alligned") angle=arccos(scalar_product) var('t') return parametric_plot3d(center+first_vector*cos(t)+radius*normal_unit_vector*sin(t),(0,angle),**kwds) def _arc(p,q,s,**kwds): #rewrite this to use polar_plot and get points to do filled triangles from sage.misc.functional import det from sage.plot.line import line from sage.misc.functional import norm from sage.symbolic.all import pi from sage.plot.arc import arc p,q,s = map( lambda x: vector(x), [p,q,s])
def angle(self, other): # UHP r""" Return the angle between any two given completed geodesics if they intersect. INPUT: - ``other`` -- a hyperbolic geodesic in the UHP model OUTPUT: - the angle in radians between the two given geodesics EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: g = UHP.get_geodesic(2, 4) sage: h = UHP.get_geodesic(3, 3 + I) sage: g.angle(h) 1/2*pi sage: numerical_approx(g.angle(h)) 1.57079632679490 If the geodesics are identical, return angle 0:: sage: g.angle(g) 0 It is an error to ask for the angle of two geodesics that do not intersect:: sage: g = UHP.get_geodesic(2, 4) sage: h = UHP.get_geodesic(5, 7) sage: g.angle(h) Traceback (most recent call last): ... ValueError: geodesics do not intersect """ if self.is_parallel(other): raise ValueError("geodesics do not intersect") # Make sure the segments are complete or intersect if (not(self.is_complete() and other.is_complete()) and not self.intersection(other)): print("Warning: Geodesic segments do not intersect. " "The angle between them is not defined.\n" "Returning the angle between their completions.") # Make sure both are in the same model if other._model is not self._model: other = other.to_model(self._model) (p1, p2) = sorted([k.coordinates() for k in self.ideal_endpoints()], key=str) (q1, q2) = sorted([k.coordinates() for k in other.ideal_endpoints()], key=str) # if the geodesics are equal, the angle between them is 0 if (abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON): return 0 elif p2 != infinity: # geodesic not a straight line # So we send it to the geodesic with endpoints [0, oo] T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1 + p2) / 2, p2) else: # geodesic is a straight line, so we send it to the geodesic # with endpoints [0,oo] T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1 + 1, p2) # b1 and b2 are the endpoints of the image of other b1, b2 = [mobius_transform(T, k) for k in [q1, q2]] # If other is now a straight line... if (b1 == infinity or b2 == infinity): # then since they intersect, they are equal return 0 return real(arccos((b1 + b2) / abs(b2 - b1)))
def angle(self, other): # UHP r""" Return the angle between any two given completed geodesics if they intersect. INPUT: - ``other`` -- a hyperbolic geodesic in the UHP model OUTPUT: - the angle in radians between the two given geodesics EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: g = UHP.get_geodesic(2, 4) sage: h = UHP.get_geodesic(3, 3 + I) sage: g.angle(h) 1/2*pi sage: numerical_approx(g.angle(h)) 1.57079632679490 If the geodesics are identical, return angle 0:: sage: g.angle(g) 0 It is an error to ask for the angle of two geodesics that do not intersect:: sage: g = UHP.get_geodesic(2, 4) sage: h = UHP.get_geodesic(5, 7) sage: g.angle(h) Traceback (most recent call last): ... ValueError: geodesics do not intersect """ if self.is_parallel(other): raise ValueError("geodesics do not intersect") # Make sure the segments are complete or intersect if (not (self.is_complete() and other.is_complete()) and not self.intersection(other)): print("Warning: Geodesic segments do not intersect. " "The angle between them is not defined.\n" "Returning the angle between their completions.") # Make sure both are in the same model if other._model is not self._model: other = other.to_model(self._model) (p1, p2) = sorted([k.coordinates() for k in self.ideal_endpoints()], key=str) (q1, q2) = sorted([k.coordinates() for k in other.ideal_endpoints()], key=str) # if the geodesics are equal, the angle between them is 0 if (abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON): return 0 elif p2 != infinity: # geodesic not a straight line # So we send it to the geodesic with endpoints [0, oo] T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1 + p2) / 2, p2) else: # geodesic is a straight line, so we send it to the geodesic # with endpoints [0,oo] T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1 + 1, p2) # b1 and b2 are the endpoints of the image of other b1, b2 = [mobius_transform(T, k) for k in [q1, q2]] # If other is now a straight line... if (b1 == infinity or b2 == infinity): # then since they intersect, they are equal return 0 return real(arccos((b1 + b2) / abs(b2 - b1)))
second_vector = second_point - center radius = norm(first_vector) if norm(second_vector) != radius: raise ValueError("Ellipse not implemented") first_unit_vector = first_vector / radius second_unit_vector = second_vector / radius normal_vector = second_vector - (second_vector * first_unit_vector) * first_unit_vector if norm(normal_vector) == 0: print(first_point, second_point) return normal_unit_vector = normal_vector / norm(normal_vector) scalar_product = first_unit_vector * second_unit_vector if abs(scalar_product) == 1: raise ValueError("The points are alligned") angle = arccos(scalar_product) var('t') return parametric_plot3d( center + first_vector * cos(t) + radius * normal_unit_vector * sin(t), (0, angle), **kwds) def _arc(p, q, s, **kwds): #rewrite this to use polar_plot and get points to do filled triangles from sage.misc.functional import det from sage.plot.line import line from sage.misc.functional import norm from sage.symbolic.all import pi from sage.plot.arc import arc p, q, s = map(lambda x: vector(x), [p, q, s])