Skip to content

Instantly share code, notes, and snippets.

@miguelgondu
Last active May 25, 2018 18:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miguelgondu/0e8ba345f25b6c9ab007084e472202c8 to your computer and use it in GitHub Desktop.
Save miguelgondu/0e8ba345f25b6c9ab007084e472202c8 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The basics of `generalrepytivity` "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`generalrepytivity` contains some algorithms related to the basics of multilinear algebra and differential geometry, algorithms which relate to some of the calculations that appear in the everyday work of a physicist or a mathematician who works in general relativity. These algorithms are built upon [`sympy`](http://www.sympy.org/en/index.html).\n",
"\n",
"In this first tutorial, we deal with multilinear algebra and the manipulation of the `Tensor` object. In the next one we learn about index manipulation, and we show how the library allows for the calculation of some special tensors in differential geometry in the specific example of Gödel's solution to Einstein's equations."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import generalrepytivity as gr\n",
"import sympy\n",
"sympy.init_printing(use_latex=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Multiindices"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The main object of the library (i.e. the `Tensor` object) relies heavily on multiindices and their manipulation. For us, a $p$-multiindex is just a tuple $(a_0, \\dots, a_{p-1})$ in which every $a_i$ is between $0$ and $n-1$ for some $n$ (the dimension of a vector space in our particular case).\n",
"\n",
"This library includes a function for getting all multiindices of certain length $p$ and certain dimension $n$:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/latex": [
"$$\\left [ \\left ( 0, \\quad 0\\right ), \\quad \\left ( 0, \\quad 1\\right ), \\quad \\left ( 0, \\quad 2\\right ), \\quad \\left ( 0, \\quad 3\\right ), \\quad \\left ( 1, \\quad 0\\right ), \\quad \\left ( 1, \\quad 1\\right ), \\quad \\left ( 1, \\quad 2\\right ), \\quad \\left ( 1, \\quad 3\\right ), \\quad \\left ( 2, \\quad 0\\right ), \\quad \\left ( 2, \\quad 1\\right ), \\quad \\left ( 2, \\quad 2\\right ), \\quad \\left ( 2, \\quad 3\\right ), \\quad \\left ( 3, \\quad 0\\right ), \\quad \\left ( 3, \\quad 1\\right ), \\quad \\left ( 3, \\quad 2\\right ), \\quad \\left ( 3, \\quad 3\\right )\\right ]$$"
],
"text/plain": [
"[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1\n",
"), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"n = 4\n",
"p = 2\n",
"list_of_multiindices = gr.get_all_multiindices(p, n)\n",
"list_of_multiindices"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Special types of multiindices"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The only $0$-multiindex is the python empty tuple (); $1$-multiindices must still be tuples, so one must write them like `(a_0, )` in python."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[(0,), (1,), (2,), (3,)]\n"
]
}
],
"source": [
"n = 4\n",
"p = 1\n",
"list_of_multiindices = gr.get_all_multiindices(p, n)\n",
"print(list_of_multiindices)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The `Tensor` object "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`generalrelativity` implements the tensor object in a very algebraic and generic sense. Sadly, we have the bound of dealing always in coordinates (that is, always talking about the coefficients with respect to some basis). To create a tensor $\\Gamma \\in T^{(p,q)}(V)$ we must specify a **basis**, a **type** and a dictionary (or map) of **values**:\n",
"- The **basis** is a list of sympy symbols, which represent a basis for the generic vector space $V$.\n",
"- The **type** is a tuple $(p, q)$ of nonnegative integers.\n",
"- The **vales** has for keys tuples of multiindices $(a, b)$ and values the tensor coefficient $\\Gamma^a_b$.\n",
"\n",
"For example, say we want to create the tensor\n",
"\n",
"$$T = 3e_0\\otimes e_0\\otimes e_0^*\\otimes e_1^* - 2 e_0\\otimes e_1\\otimes e_1^*\\otimes e_3^* \\in T^{(2,2)}(V)$$\n",
"\n",
"we do so like this:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(-2)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (3)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(-2)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (3)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"e0, e1, e2, e3 = sympy.symbols('e_0 e_1 e_2 e_3')\n",
"basis = [e0, e1, e2, e3]\n",
"values = {\n",
" ((2,2), (0,1)): 3, # The first sumand\n",
" ((0,1), (1,3)): -2 # The second sumand\n",
"}\n",
"T = gr.Tensor(basis, (2, 2), values)\n",
"T"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(1)\\partial/\\partial e_{1} \\otimes de_0 \\otimes de_0$"
],
"text/plain": [
"(1)e_1 \\otimes e_0* \\otimes e_0*"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"values = {\n",
" (1, (0,0)): 1,\n",
"}\n",
"T = gr.Tensor(basis, (1, 2), values)\n",
"T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The tensors object have a LaTeX printing function (but this depends obviously on the availability of IPython, LaTeX and on the running of `sympy.init_printing(use_latex=True)`). We could also print it raw:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1)e_1 \\otimes e_0* \\otimes e_0*\n"
]
}
],
"source": [
"print(T)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## More details about the `dict_of_values` "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Say we want to construct a $(0,2)$ Tensor. Initially, the `dict_of_values` should be of the form"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"values_1 = {\n",
" ((), (0,0)): -1,\n",
" ((), (1,1)): 1,\n",
" ((), (2,2)): 1,\n",
" ((), (3,3)): 1,\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That is, one should specify the $0$-multiindex `()`. In the long run, this becomes tedious, and it is because of this that the `Tensor` object can also accept, for this case, the following `dict_of_values`:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"values_2 = {\n",
" (0,0): -1,\n",
" (1,1): 1,\n",
" (2,2): 1,\n",
" (3,3): 1,\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and the two tensors generated would be equal (once we specify equal bases and equal types)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"T1 = gr.Tensor(basis, (0, 2), values_1)\n",
"T2 = gr.Tensor(basis, (0, 2), values_2)\n",
"print(T1 == T2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The same happens for $1$-multiindices: a priori a $1$-multiindex is of the form `(a_1, )`, so if we wanted to create for example a $(1,2)$ tensor one should create a `dict_of_values` of the form"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"values_1 = {\n",
" ((0, ), (1, 1)): 3,\n",
" ((1, ), (0, 1)): -1,\n",
" ((0, ), (2, 3)): 2\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We relax the conditions to `values` such that it accepts integers $a_0$ instead of python 1-tuples `(a_0,)`:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"values_2 = {\n",
" (0, (1, 1)): 3,\n",
" (1, (0, 1)): -1,\n",
" (0, (2, 3)): 2\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"T1 = gr.Tensor(basis, (1, 2), values_1)\n",
"T2 = gr.Tensor(basis, (1, 2), values_2)\n",
"print(T1 == T2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Operations with `Tensor` objects "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One can **add** tensor objects if they have the same basis and type, one can **multiply** a tensor object with `int`s, `float`s, $(0,0)$-tensors and even `sympy` objects and symbols. Moreover, one can contract indices and raise and lower indices according to a special $(0,2)$-tensor, but we will explain this on the second tutorial."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(-2)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (3)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(-2)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (3)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"values = {\n",
" ((2,2), (0,1)): 3, \n",
" ((0,1), (1,3)): -2 \n",
"}\n",
"T = gr.Tensor(basis, (2, 2), values)\n",
"T"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"values_S = {\n",
" ((0,0), (0,1)): 4,\n",
" ((1,1), (2,1)): -1,\n",
"}\n",
"S = gr.Tensor(basis, (2, 2), values_S)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(-2)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (3)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(-2)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (3)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(4)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{0} \\otimes de_0 \\otimes de_1 + (-1)\\partial/\\partial e_{1} \\otimes \\partial/\\partial e_{1} \\otimes de_2 \\otimes de_1$"
],
"text/plain": [
"(4)e_0 \\otimes e_0 \\otimes e_0* \\otimes e_1* + (-1)e_1 \\otimes e_1 \\otimes e_2* \\otimes e_1*"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"S"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(4)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{0} \\otimes de_0 \\otimes de_1 + (-1)\\partial/\\partial e_{1} \\otimes \\partial/\\partial e_{1} \\otimes de_2 \\otimes de_1 + (-2)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (3)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(4)e_0 \\otimes e_0 \\otimes e_0* \\otimes e_1* + (-1)e_1 \\otimes e_1 \\otimes e_2* \\otimes e_1* + (-2)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (3)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T + S"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(-6)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (9)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(-6)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (9)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"3*T"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(- 2 \\pi)\\partial/\\partial e_{0} \\otimes \\partial/\\partial e_{1} \\otimes de_1 \\otimes de_3 + (3 \\pi)\\partial/\\partial e_{2} \\otimes \\partial/\\partial e_{2} \\otimes de_0 \\otimes de_1$"
],
"text/plain": [
"(-2*pi)e_0 \\otimes e_1 \\otimes e_1* \\otimes e_3* + (3*pi)e_2 \\otimes e_2 \\otimes e_0* \\otimes e_1*"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sympy.pi*T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Substitution of `sympy.symbols` in tensors "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nothing impedes us of using `sympy.symbols` in our tensors. For example:"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(t^{2})\\partial/\\partial r \\otimes dt \\otimes dt + (r t)\\partial/\\partial \\theta \\otimes dr \\otimes dt + (\\sin{\\left (\\phi + \\theta \\right )})\\partial/\\partial t \\otimes dr \\otimes d\\phi$"
],
"text/plain": [
"(t**2)r \\otimes t* \\otimes t* + (r*t)\\theta \\otimes r* \\otimes t* + (sin(\\phi + \\theta))t \\otimes r* \\otimes \\phi*"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t, r, theta, phi = sympy.symbols('t r \\\\theta \\\\phi')\n",
"values = {\n",
" (1, (0, 0)): t**2,\n",
" (2, (1, 0)): r*t,\n",
" (0, (1, 3)): sympy.sin(theta + phi)\n",
"}\n",
"basis = [t, r, theta, phi]\n",
"T = gr.Tensor(basis, (1, 2), values)\n",
"T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"we can substitute values with the usual `subs` function, which takes a list of tuples of the substitutions to be performed:"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(25)\\partial/\\partial r \\otimes dt \\otimes dt + (12.5)\\partial/\\partial \\theta \\otimes dr \\otimes dt + (\\sin{\\left (\\phi + 0.5 \\pi \\right )})\\partial/\\partial t \\otimes dr \\otimes d\\phi$"
],
"text/plain": [
"(25)r \\otimes t* \\otimes t* + (12.5000000000000)\\theta \\otimes r* \\otimes t* + (sin(\\phi + 0.5*pi))t \\otimes r* \\otimes \\phi*"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"new_T = T.subs([(t, 5), (r, 2.5), (theta, (1/2)*sympy.pi)])\n",
"new_T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This creates a new object, $T$ remains unmodified."
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(t^{2})\\partial/\\partial r \\otimes dt \\otimes dt + (r t)\\partial/\\partial \\theta \\otimes dr \\otimes dt + (\\sin{\\left (\\phi + \\theta \\right )})\\partial/\\partial t \\otimes dr \\otimes d\\phi$"
],
"text/plain": [
"(t**2)r \\otimes t* \\otimes t* + (r*t)\\theta \\otimes r* \\otimes t* + (sin(\\phi + \\theta))t \\otimes r* \\otimes \\phi*"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Change of basis of a Tensor"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each Tensor comes equipped with a `change_basis` and `change_coordinates` with the following syntax:\n",
"\n",
"```python\n",
"new_tensor = tensor.change_basis(new_basis, basis_change)\n",
"new_tensor = tensor.change_coordinates(new_basis, coordinate_change)\n",
"```\n",
"\n",
"where `basis_change` (or `coordinate_change`) is a dict that holds the relation between the old and the new basis (or coordinates, respectively). This function does **not** change the vector in place, it returns a new tensor."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A vectorial example "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Because vectors $v\\in V$ are just $(1,0)$-tensors, we could perform the usual change of basis for vectors. Consider these two bases for a vector space $V$: $\\{e_0, e_1, e_2\\}$ and $\\{f_0, f_1, f_2\\}$ where\n",
"\n",
"$$\\begin{array}{rcl}\n",
"e_0 &=& f_0 + f_1\\\\\n",
"e_1 &=& f_2\\\\\n",
"e_2 &=& f_0 - f_2\\\\\n",
"\\end{array}$$\n",
"\n",
"Let's compute the basis change for $v = e_0 + 2e_1 - 3e_2$ both manually and with the `change_basis` method. Manually:\n",
"\n",
"$$ v = e_0 + 2e_1 - 3e_2 = (f_0 + f_1) + 2f_2 - 3(f_0 - f_2) = -2f_0 + f_1 + 5f_2$$\n",
"\n",
"and with the method:"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(2)\\partial/\\partial e_{1} + (-3)\\partial/\\partial e_{2} + (1)\\partial/\\partial e_{0}$"
],
"text/plain": [
"(2)e_1 + (-3)e_2 + (1)e_0"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"e0, e1, e2, f0, f1, f2 = sympy.symbols('e_0 e_1 e_2 f_0 f_1 f_2')\n",
"basis = [e0, e1, e2]\n",
"values = {\n",
" (0, ): 1,\n",
" (1, ): 2,\n",
" (2, ): -3\n",
"}\n",
"v = gr.Tensor(basis, (1,0), values)\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(1)\\partial/\\partial f_{1} + (5)\\partial/\\partial f_{2} + (-2)\\partial/\\partial f_{0}$"
],
"text/plain": [
"(1)f_1 + (5)f_2 + (-2)f_0"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"new_basis = [f0, f1, f2]\n",
"basis_change = {\n",
" e0: f0 + f1,\n",
" e1: f2,\n",
" e2: f0 - f2\n",
"}\n",
"new_v = v.change_basis(new_basis, basis_change)\n",
"new_v"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A change of coordinates in differential geometry"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example, consider the following tensor in $T^{(0,2)}(M)$ where $M$ is a manifold (that is, the underlying vector space is the tangent bundle of the manifold):\n",
"\n",
"$$ g = dx\\otimes dx + dy\\otimes dy $$\n",
"\n",
"(that is, the basis is $\\{\\partial/\\partial x, \\partial/\\partial y\\}$ and its dual is $\\{dx, dy\\}$). Consider the following change of coordinates:\n",
"\n",
"$$ x = r\\cos \\theta, y = r\\sin\\theta$$\n",
"\n",
"Let's compute $g$ in terms of the new basis induced by this change of coordinates:"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$(1)dr \\otimes dr + (r^{2})d\\theta \\otimes d\\theta$"
],
"text/plain": [
"(1)r* \\otimes r* + (r**2)\\theta* \\otimes \\theta*"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x, y, r, theta = sympy.symbols('x y r \\\\theta')\n",
"basis = [x, y]\n",
"new_basis = [r, theta]\n",
"values = {\n",
" (0,0): 1,\n",
" (1,1): 1\n",
"}\n",
"g = gr.Tensor(basis, (0,2), values)\n",
"coordinate_change = {\n",
" x: r*sympy.cos(theta),\n",
" y: r*sympy.sin(theta)\n",
"}\n",
"new_g = g.change_coordinates(new_basis, coordinate_change)\n",
"new_g"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment