def __invert__(self): r""" Return the inverse automorphism. """ from sage.matrix.constructor import matrix from sage.tensor.modules.comp import Components from vectorframe import CoordFrame from utilities import simplify_chain if self._is_identity: return self if self._inverse is None: if self._name is None: inv_name = None else: inv_name = self._name + '^(-1)' if self._latex_name is None: inv_latex_name = None else: inv_latex_name = self._latex_name + r'^{-1}' fmodule = self._fmodule si = fmodule._sindex nsi = fmodule._rank + si self._inverse = fmodule.automorphism(name=inv_name, latex_name=inv_latex_name) for frame in self._components: if isinstance(frame, CoordFrame): chart = frame._chart else: chart = self._domain._def_chart #!# to be improved try: mat_self = matrix([[ self.comp(frame)[i, j, chart]._express for j in range(si, nsi) ] for i in range(si, nsi)]) except (KeyError, ValueError): continue mat_inv = mat_self.inverse() cinv = Components(fmodule._ring, frame, 2, start_index=si, output_formatter=fmodule._output_formatter) for i in range(si, nsi): for j in range(si, nsi): cinv[i, j] = { chart: simplify_chain(mat_inv[i - si, j - si]) } self._inverse._components[frame] = cinv return self._inverse
def inverse(self): r""" Return the inverse automorphism. """ from sage.matrix.constructor import matrix from component import Components from utilities import simplify_chain if self._inverse is None: if self.name is None: inv_name = None else: inv_name = 'inv-' + self.name if self.latex_name is None: inv_latex_name = None else: inv_latex_name = self.latex_name + r'^{-1}' manif = self.manifold dom = self.domain si = manif.sindex nsi = manif.dim + si self._inverse = AutomorphismField(dom, inv_name, inv_latex_name) for frame_name in self.components: if frame_name[-2:] == '_b': # coordinate basis chart_name = frame_name[:-2] else: chart_name = dom.def_chart.name #!# to be improved try: mat_self = matrix([[ self.comp(frame_name)[i, j, chart_name].express for j in range(si, nsi) ] for i in range(si, nsi)]) except (KeyError, ValueError): continue mat_inv = mat_self.inverse() cinv = Components(dom.frames[frame_name], 2) for i in range(si, nsi): for j in range(si, nsi): cinv[i, j, chart_name] = simplify_chain(mat_inv[i - si, j - si]) self._inverse.components[frame_name] = cinv return self._inverse
def __invert__(self): r""" Return the inverse automorphism. """ from sage.matrix.constructor import matrix from sage.tensor.modules.comp import Components from vectorframe import CoordFrame from utilities import simplify_chain if self._is_identity: return self if self._inverse is None: if self._name is None: inv_name = None else: inv_name = self._name + '^(-1)' if self._latex_name is None: inv_latex_name = None else: inv_latex_name = self._latex_name + r'^{-1}' fmodule = self._fmodule si = fmodule._sindex ; nsi = fmodule._rank + si self._inverse = fmodule.automorphism(name=inv_name, latex_name=inv_latex_name) for frame in self._components: if isinstance(frame, CoordFrame): chart = frame._chart else: chart = self._domain._def_chart #!# to be improved try: mat_self = matrix( [[self.comp(frame)[i, j, chart]._express for j in range(si, nsi)] for i in range(si, nsi)]) except (KeyError, ValueError): continue mat_inv = mat_self.inverse() cinv = Components(fmodule._ring, frame, 2, start_index=si, output_formatter=fmodule._output_formatter) for i in range(si, nsi): for j in range(si, nsi): cinv[i, j] = {chart: simplify_chain(mat_inv[i-si,j-si])} self._inverse._components[frame] = cinv return self._inverse
def inverse(self): r""" Return the inverse automorphism. """ from sage.matrix.constructor import matrix from component import Components from utilities import simplify_chain if self._inverse is None: if self.name is None: inv_name = None else: inv_name = 'inv-' + self.name if self.latex_name is None: inv_latex_name = None else: inv_latex_name = self.latex_name + r'^{-1}' manif = self.manifold dom = self.domain si = manif.sindex ; nsi = manif.dim + si self._inverse = AutomorphismField(dom, inv_name, inv_latex_name) for frame_name in self.components: if frame_name[-2:] == '_b': # coordinate basis chart_name = frame_name[:-2] else: chart_name = dom.def_chart.name #!# to be improved try: mat_self = matrix( [[self.comp(frame_name)[i, j, chart_name].express for j in range(si, nsi)] for i in range(si, nsi)]) except (KeyError, ValueError): continue mat_inv = mat_self.inverse() cinv = Components(dom.frames[frame_name], 2) for i in range(si, nsi): for j in range(si, nsi): cinv[i, j, chart_name] = simplify_chain( mat_inv[i-si,j-si]) self._inverse.components[frame_name] = cinv return self._inverse
def inverse(self, chartname1=None, chartname2=None): r""" Returns the inverse diffeomorphism. INPUT: - ``chartname1`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold1 will be used - ``chartname2`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold2 will be used OUTPUT: - the inverse diffeomorphism EXAMPLES: The inverse of a rotation in the plane:: sage: m = Manifold(2, "plane") sage: c_cart = Chart(m, 'x y', 'cart') sage: # A pi/3 rotation around the origin: sage: rot = Diffeomorphism(m, m, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2)) sage: p = Point(m,(1,2)) sage: q = rot(p) sage: irot = rot.inverse() sage: p1 = irot(q) sage: p1 == p True """ from sage.symbolic.ring import SR from sage.symbolic.relation import solve from utilities import simplify_chain if self._inverse is not None: return self._inverse if chartname1 is None: chartname1 = self.manifold1.def_chart.name if chartname2 is None: chartname2 = self.manifold2.def_chart.name coord_map = self.coord_expression[(chartname1, chartname2)] chart1 = self.manifold1.atlas[chartname1] chart2 = self.manifold2.atlas[chartname2] n1 = len(chart1.xx) n2 = len(chart2.xx) # New symbolic variables (different from chart2.xx to allow for a # correct solution even when chart2 = chart1): x2 = [ SR.var('xxxx' + str(i)) for i in range(n2) ] equations = [x2[i] == coord_map.functions[i] for i in range(n2) ] solutions = solve(equations, chart1.xx, solution_dict=True) if len(solutions) == 0: raise ValueError("No solution found") if len(solutions) > 1: raise ValueError("Non-unique solution found") #!# This should be the Python 2.7 form: # substitutions = {x2[i]: chart2.xx[i] for i in range(n2)} # # Here we use a form compatible with Python 2.6: substitutions = dict([(x2[i], chart2.xx[i]) for i in range(n2)]) inv_functions = [solutions[0][chart1.xx[i]].subs(substitutions) for i in range(n1)] for i in range(n1): x = inv_functions[i] try: inv_functions[i] = simplify_chain(x) except AttributeError: pass self._inverse = Diffeomorphism(self.manifold2, self.manifold1, inv_functions, chartname2, chartname1) return self._inverse
def inverse(self, chart1=None, chart2=None): r""" Return the inverse diffeomorphism. INPUT: - ``chart1`` -- (default: None) chart in which the computation of the inverse is performed if necessary; if none is provided, the default chart of the start domain will be used - ``chart2`` -- (default: None) chart in which the computation of the inverse is performed if necessary; if none is provided, the default chart of the arrival domain will be used OUTPUT: - the inverse diffeomorphism EXAMPLES: The inverse of a rotation in the Euclidean plane:: sage: m = Manifold(2, 'R^2', r'\RR^2') sage: c_cart.<x,y> = m.chart('x y') sage: # A pi/3 rotation around the origin: sage: rot = Diffeomorphism(m, m, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2), name='R') sage: rot.inverse() diffeomorphism 'R^(-1)' on the 2-dimensional manifold 'R^2' sage: rot.inverse().view() R^(-1): R^2 --> R^2, (x, y) |--> (1/2*sqrt(3)*y + 1/2*x, -1/2*sqrt(3)*x + 1/2*y) Checking that applying successively the diffeomorphism and its inverse results in the identity:: sage: (a, b) = var('a b') sage: p = Point(m, (a,b)) # a generic point on M sage: q = rot(p) sage: p1 = rot.inverse()(q) sage: p1 == p True """ from sage.symbolic.ring import SR from sage.symbolic.relation import solve from utilities import simplify_chain if self._inverse is not None: return self._inverse if chart1 is None: chart1 = self.domain1.def_chart if chart2 is None: chart2 = self.domain2.def_chart coord_map = self.coord_expression[(chart1, chart2)] n1 = len(chart1.xx) n2 = len(chart2.xx) # New symbolic variables (different from chart2.xx to allow for a # correct solution even when chart2 = chart1): x2 = [ SR.var('xxxx' + str(i)) for i in range(n2) ] equations = [ x2[i] == coord_map.functions[i].express for i in range(n2) ] solutions = solve(equations, chart1.xx, solution_dict=True) if len(solutions) == 0: raise ValueError("No solution found") if len(solutions) > 1: raise ValueError("Non-unique solution found") #!# This should be the Python 2.7 form: # substitutions = {x2[i]: chart2.xx[i] for i in range(n2)} # # Here we use a form compatible with Python 2.6: substitutions = dict([(x2[i], chart2.xx[i]) for i in range(n2)]) inv_functions = [solutions[0][chart1.xx[i]].subs(substitutions) for i in range(n1)] for i in range(n1): x = inv_functions[i] try: inv_functions[i] = simplify_chain(x) except AttributeError: pass if self.name is None: name = None else: name = self.name + '^(-1)' if self.latex_name is None: latex_name = None else: latex_name = self.latex_name + r'^{-1}' self._inverse = Diffeomorphism(self.domain2, self.domain1, inv_functions, chart2, chart1, name=name, latex_name=latex_name) return self._inverse
def sqrt_abs_det(self, frame=None): r""" Square root of the absolute value of the determinant of the metric components in the specified frame. INPUT: - ``frame`` -- (default: None) vector frame with respect to which the components `g_{ij}` of ``self`` are defined; if None, the domain's default frame is used. If a chart is provided, the associated coordinate frame is used OUTPUT: - `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField` EXAMPLES: Standard metric in the Euclidean space `\RR^3` with spherical coordinates:: sage: m = Manifold(3, 'M', start_index=1) sage: c_spher.<r,th,ph> = m.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi') sage: g = Metric(m, 'g') sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2 sage: g.view() g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph sage: g.sqrt_abs_det().expr() r^2*sin(th) Metric determinant on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', start_index=1) sage: X.<x,y> = M.chart('x y') sage: g = Metric(M, 'g') sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y sage: g[:] [ x + 1 x*y] [ x*y -y + 1] sage: s = g.sqrt_abs_det() ; s scalar field on the 2-dimensional manifold 'M' sage: s.expr() sqrt(-x^2*y^2 - (x + 1)*y + x + 1) Determinant in a frame different from the default's one:: sage: Y.<u,v> = M.chart('u v') sage: ch_X_Y = CoordChange(X, Y, x+y, x-y) sage: ch_X_Y.inverse() coordinate change from chart (M, (u, v)) to chart (M, (x, y)) sage: g.comp(Y.frame)[:, Y] [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u] [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2] sage: g.sqrt_abs_det(Y.frame).expr() 1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1) sage: g.sqrt_abs_det(Y.frame).expr(Y) 1/8*sqrt(-u^4 - v^4 + 2*(u^2 + 2)*v^2 - 4*u^2 + 16*v + 16) A chart can be passed instead of a frame:: sage: g.sqrt_abs_det(Y) is g.sqrt_abs_det(Y.frame) True The metric determinant depends on the frame:: sage: g.sqrt_abs_det(X.frame) == g.sqrt_abs_det(Y.frame) False """ from sage.functions.other import sqrt from scalarfield import ScalarField from utilities import simplify_chain manif = self.manifold dom = self.domain if frame is None: frame = dom.def_frame if frame in dom.atlas: # frame is actually a chart and is changed to the associated # coordinate frame: frame = frame.frame if frame not in self._sqrt_abs_dets: # a new computation is necessary detg = self.determinant(frame) resu = ScalarField(dom) for chart in detg.express: x = self._indic_signat * detg.express[chart].express # |g| x = simplify_chain(sqrt(x)) resu.add_expr(x, chart=chart) self._sqrt_abs_dets[frame] = resu return self._sqrt_abs_dets[frame]
def determinant(self, frame=None): r""" Determinant of the metric components in the specified frame. INPUT: - ``frame`` -- (default: None) vector frame with respect to which the components `g_{ij}` of ``self`` are defined; if None, the domain's default frame is used. If a chart is provided, the associated coordinate frame is used OUTPUT: - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField` EXAMPLES: Metric determinant on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', start_index=1) sage: X.<x,y> = M.chart('x y') sage: g = Metric(M, 'g') sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y sage: g[:] [ x + 1 x*y] [ x*y -y + 1] sage: s = g.determinant() # determinant in M's default frame sage: s.expr() -x^2*y^2 - (x + 1)*y + x + 1 Determinant in a frame different from the default's one:: sage: Y.<u,v> = M.chart('u v') sage: ch_X_Y = CoordChange(X, Y, x+y, x-y) sage: ch_X_Y.inverse() coordinate change from chart (M, (u, v)) to chart (M, (x, y)) sage: g.comp(Y.frame)[:, Y] [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u] [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2] sage: g.determinant(Y.frame).expr() -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4 sage: g.determinant(Y.frame).expr(Y) -1/64*u^4 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 - 1/16*u^2 + 1/4*v + 1/4 A chart can be passed instead of a frame:: sage: g.determinant(X) is g.determinant(X.frame) True sage: g.determinant(Y) is g.determinant(Y.frame) True The metric determinant depends on the frame:: sage: g.determinant(X.frame) == g.determinant(Y.frame) False """ from sage.matrix.constructor import matrix from scalarfield import ScalarField from utilities import simple_determinant, simplify_chain manif = self.manifold dom = self.domain if frame is None: frame = dom.def_frame if frame in dom.atlas: # frame is actually a chart and is changed to the associated # coordinate frame: frame = frame.frame if frame not in self._determinants: # a new computation is necessary resu = ScalarField(dom) gg = self.comp(frame) i1 = manif.sindex for chart in gg[[i1, i1]].express: gm = matrix( [[ gg[i, j, chart].express for j in manif.irange()] for i in manif.irange()] ) detgm = simplify_chain(simple_determinant(gm)) resu.add_expr(detgm, chart=chart) self._determinants[frame] = resu return self._determinants[frame]
def inverse(self): r""" Return the inverse metric. EXAMPLES: Inverse metric on a 2-dimensional manifold:: sage: m = Manifold(2, 'M', start_index=1) sage: c_xy.<x,y> = m.chart('x y') sage: g = Metric(m, 'g') sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x sage: g[:] # components in the manifold's default frame [ x + 1 x*y] [ x*y -x + 1] sage: ig = g.inverse() ; ig tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M' sage: ig[:] [ (x - 1)/(x^2*y^2 + x^2 - 1) x*y/(x^2*y^2 + x^2 - 1)] [ x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)] If the metric is modified, the inverse metric is automatically updated:: sage: g[1,2] = 0 ; g[:] [ x + 1 0] [ 0 -x + 1] sage: g.inverse()[:] [ 1/(x + 1) 0] [ 0 -1/(x - 1)] """ from sage.matrix.constructor import matrix from component import CompFullySym from vectorframe import CoordFrame from utilities import simplify_chain # Is the inverse metric up to date ? for frame in self.components: if frame not in self._inverse.components: # the computation is necessary manif = self.manifold dom = self.domain if isinstance(frame, CoordFrame): chart = frame.chart else: chart = dom.def_chart si = manif.sindex nsi = manif.dim + si try: gmat = matrix( [[self.comp(frame)[i, j, chart].express for j in range(si, nsi)] for i in range(si, nsi)]) except (KeyError, ValueError): continue gmat_inv = gmat.inverse() cinv = CompFullySym(frame, 2) for i in range(si, nsi): for j in range(i, nsi): # symmetry taken into account cinv[i, j, chart] = simplify_chain( gmat_inv[i-si,j-si]) self._inverse.components[frame] = cinv return self._inverse
def sqrt_abs_det(self, frame_name=None): r""" Square root of the absolute value of the determinant of the metric components in the specified frame. INPUT: - ``frame_name`` -- (default: None) name of the vector frame with respect to which the components `g_{ij}` of ``self`` are defined; if None, the manifold's default frame is used. If a chart name is provided, the associated coordinate basis is used OUTPUT: - `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField` EXAMPLES: Standard metric in the Euclidean space `\RR^3` with spherical coordinates:: sage: m = Manifold(3, 'M', start_index=1) sage: c_spher = Chart(m, r'r:positive th:positive:\theta ph:\phi', 'spher') sage: assume(th>=0); assume(th<=pi) sage: g = Metric(m, 'g') sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2 sage: g.show() g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph sage: g.sqrt_abs_det().expr() r^2*sin(th) Metric determinant on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', start_index=1) sage: X = Chart(M, 'x y', 'xy') sage: g = Metric(M, 'g') sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y sage: g[:] [ x + 1 x*y] [ x*y -y + 1] sage: s = g.sqrt_abs_det() ; s scalar field on the 2-dimensional manifold 'M' sage: s.expr() sqrt(-x^2*y^2 - (x + 1)*y + x + 1) Determinant in a frame different from the default's one:: sage: Y = Chart(M, 'u v', 'uv') sage: ch_X_Y = CoordChange(X, Y, x+y, x-y) sage: ch_X_Y.inverse() coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y) sage: g.comp('uv_b')[:, 'uv'] [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u] [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2] sage: g.sqrt_abs_det('uv_b').expr() 1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1) sage: g.sqrt_abs_det('uv_b').expr('uv') 1/8*sqrt(-u^4 - 4*u^2 - v^4 + 2*(u^2 + 2)*v^2 + 16*v + 16) The name of a chart can be passed instead of the name of a frame:: sage: g.sqrt_abs_det('uv') is g.sqrt_abs_det('uv_b') True The metric determinant depends on the frame:: sage: g.sqrt_abs_det('xy_b') == g.sqrt_abs_det('uv_b') False """ from sage.functions.other import sqrt from scalarfield import ScalarField from utilities import simplify_chain manif = self.manifold if frame_name is None: frame_name = manif.def_frame.name if frame_name in manif.atlas: # frame_name is actually the name of a chart and is changed to the # name of the associated coordinate basis: frame_name = manif.atlas[frame_name].frame.name if frame_name not in self._sqrt_abs_dets: # a new computation is necessary detg = self.determinant(frame_name) resu = ScalarField(manif) for chart_name in detg.express: x = self._indic_signat * detg.express[chart_name].express # |g| x = simplify_chain(sqrt(x)) resu.set_expr(x, chart_name=chart_name, delete_others=False) self._sqrt_abs_dets[frame_name] = resu return self._sqrt_abs_dets[frame_name]
def determinant(self, frame_name=None): r""" Determinant of the metric components in the specified frame. INPUT: - ``frame_name`` -- (default: None) name of the vector frame with respect to which the components `g_{ij}` of ``self`` are defined; if None, the manifold's default frame is used. If a chart name is provided, the associated coordinate basis is used OUTPUT: - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField` EXAMPLES: Metric determinant on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', start_index=1) sage: X = Chart(M, 'x y', 'xy') sage: g = Metric(M, 'g') sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y sage: g[:] [ x + 1 x*y] [ x*y -y + 1] sage: s = g.determinant() # determinant in M's default frame sage: s.expr() -x^2*y^2 - (x + 1)*y + x + 1 Determinant in a frame different from the default's one:: sage: Y = Chart(M, 'u v', 'uv') sage: ch_X_Y = CoordChange(X, Y, x+y, x-y) sage: ch_X_Y.inverse() coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y) sage: g.comp('uv_b')[:, 'uv'] [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2 1/4*u] [ 1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2] sage: g.determinant('uv_b').expr() -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4 sage: g.determinant('uv_b').expr('uv') -1/64*u^4 - 1/16*u^2 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 + 1/4*v + 1/4 The name of a chart can be passed instead of the name of a frame:: sage: g.determinant('xy') is g.determinant('xy_b') True sage: g.determinant('uv') is g.determinant('uv_b') True The metric determinant depends on the frame:: sage: g.determinant('xy_b') == g.determinant('uv_b') False """ from sage.matrix.constructor import matrix from scalarfield import ScalarField from utilities import simple_determinant, simplify_chain manif = self.manifold if frame_name is None: frame_name = manif.def_frame.name if frame_name in manif.atlas: # frame_name is actually the name of a chart and is changed to the # name of the associated coordinate basis: frame_name = manif.atlas[frame_name].frame.name if frame_name not in self._determinants: # a new computation is necessary resu = ScalarField(manif) gg = self.comp(frame_name) i1 = manif.sindex for chart_name in gg[[i1, i1]].express: gm = matrix( [[gg[i, j, chart_name].express for j in manif.irange()] for i in manif.irange()]) detgm = simplify_chain(simple_determinant(gm)) resu.set_expr(detgm, chart_name=chart_name, delete_others=False) self._determinants[frame_name] = resu return self._determinants[frame_name]
def inverse(self): r""" Return the inverse metric. EXAMPLES: Inverse metric on a 2-dimensional manifold:: sage: m = Manifold(2, 'M', start_index=1) sage: c_xy = Chart(m, 'x y', 'xy') sage: g = Metric(m, 'g') sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x sage: g[:] # components in the manifold's default frame [ x + 1 x*y] [ x*y -x + 1] sage: ig = g.inverse() ; ig tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M' sage: ig[:] [ (x - 1)/(x^2*y^2 + x^2 - 1) x*y/(x^2*y^2 + x^2 - 1)] [ x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)] If the metric is modified, the inverse metric is automatically updated:: sage: g[1,2] = 0 ; g[:] [ x + 1 0] [ 0 -x + 1] sage: g.inverse()[:] [ 1/(x + 1) 0] [ 0 -1/(x - 1)] """ from sage.matrix.constructor import matrix from component import CompFullySym from utilities import simplify_chain # Is the inverse metric up to date ? for frame_name in self.components: if frame_name not in self._inverse.components: # the computation is necessary manif = self.manifold if frame_name[-2:] == '_b': # coordinate basis chart_name = frame_name[:-2] else: chart_name = manif.def_chart.name si = manif.sindex nsi = manif.dim + si try: gmat = matrix([[ self.comp(frame_name)[i, j, chart_name].express for j in range(si, nsi) ] for i in range(si, nsi)]) except KeyError: continue gmat_inv = gmat.inverse() cinv = CompFullySym(manif, 2, frame_name) for i in range(si, nsi): for j in range(i, nsi): # symmetry taken into account cinv[i, j, chart_name] = simplify_chain(gmat_inv[i - si, j - si]) self._inverse.components[frame_name] = cinv return self._inverse
def inverse(self, chartname1=None, chartname2=None): r""" Returns the inverse diffeomorphism. INPUT: - ``chartname1`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold1 will be used - ``chartname2`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold2 will be used OUTPUT: - the inverse diffeomorphism EXAMPLES: The inverse of a rotation in the plane:: sage: m = Manifold(2, "plane") sage: c_cart = Chart(m, 'x y', 'cart') sage: # A pi/3 rotation around the origin: sage: rot = Diffeomorphism(m, m, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2)) sage: p = Point(m,(1,2)) sage: q = rot(p) sage: irot = rot.inverse() sage: p1 = irot(q) sage: p1 == p True """ from sage.symbolic.ring import SR from sage.symbolic.relation import solve from utilities import simplify_chain if self._inverse is not None: return self._inverse if chartname1 is None: chartname1 = self.manifold1.def_chart.name if chartname2 is None: chartname2 = self.manifold2.def_chart.name coord_map = self.coord_expression[(chartname1, chartname2)] chart1 = self.manifold1.atlas[chartname1] chart2 = self.manifold2.atlas[chartname2] n1 = len(chart1.xx) n2 = len(chart2.xx) # New symbolic variables (different from chart2.xx to allow for a # correct solution even when chart2 = chart1): x2 = [SR.var('xxxx' + str(i)) for i in range(n2)] equations = [x2[i] == coord_map.functions[i] for i in range(n2)] solutions = solve(equations, chart1.xx, solution_dict=True) if len(solutions) == 0: raise ValueError("No solution found") if len(solutions) > 1: raise ValueError("Non-unique solution found") #!# This should be the Python 2.7 form: # substitutions = {x2[i]: chart2.xx[i] for i in range(n2)} # # Here we use a form compatible with Python 2.6: substitutions = dict([(x2[i], chart2.xx[i]) for i in range(n2)]) inv_functions = [ solutions[0][chart1.xx[i]].subs(substitutions) for i in range(n1) ] for i in range(n1): x = inv_functions[i] try: inv_functions[i] = simplify_chain(x) except AttributeError: pass self._inverse = Diffeomorphism(self.manifold2, self.manifold1, inv_functions, chartname2, chartname1) return self._inverse