Тензоры: опыт создания пользовательского пакета программ
Функции для работы с таблицами
Как мы уже выясняли в прошлом семестре, в Mathematica имеется ряд команд, манипулирующих списками. К наиболее популярным из них относятся команды, имена которых начинаются с Map: Map, MapThread, MapIndexed и др. Команда Map настолько широко используется, что для нее была придумана специальная форма, а именно, f /@ list (этой формой записи команды Map мы будем пользоваться многократно):
In[26]:=Map[f [#] &, {{а, b}, {с, d}}] f[#] &/@{{a, b}, {с, d}} MapThread[f[#l, #2, #3] &, {{{a}, {b}}, {{c}, {d}}, {{e}, {f}}}] (* #l соответствует элементам первого списка, #2 - второго и т.д.*) MapIndexed[f [#1] [#2] &, {{а, b} , {с, d} } ] (* #2 соответствует номеру текущего элемента списка взятого в фигурные скобки *) Out[26]={f [{a, b}], f [{с, d}]} Out[27]={f [{a, b}], f [{с, d}]} Out[28]={f[{a}, {с}, {е}], f[{b}, {d}, {f}]} Out[29]={f [{a, b}] [{1}], f[{c, d}] [{2}]}
Эти команды допускают явное указание уровня списка, к элементам которого и нужно применять функцию:
In[30]:=Map[f [#] &, {{а, b} , {с, d} } , {2}] MapThread [ f [ #l, #2, #3] &, {{{a}, {b}}, {{c}, {d}}, {{e}, {f}}}, 2] (* #l соответствует элементам первого списка, #2 - второго и т.д.*) MapIndexedff[#1][#2] &, {{а, b}, {с, d}}, {2}] (* #2 соответствует номеру текущего элемента списка, взятого в фигурные скобки *) Out[30]={{f [a], f [b]}, {f [с], f [d]}} Out[3l]={{f [а, с, e]}, {f[b, d, f ]}} Out[32] = {{f[a] [{1, 1}], f[b] [{1, 2}] }, {f[c] [{2, 1}], f[d] [{2, 2}]}}
Заметьте, что теперь номер текущего элемента является списком длины 2. Такая общность интерпретации команды MapIndexed и объясняет, почему номер элемента берется в фигурные скобки.
Следующая команда Tuples строит или n -кратное декартово произведение списка на себя:
In[33] := Tuples [{а, b, с}, 3] Out[33] = {{а, а, а},{а,а, b},{а, а, с},{a, b, a},{a,b, b}, {а, b, с}, {а, с, а},{а,с, b},{а, с, с},{b, a, a},{b,a, b}, {b, а, с}, {b, b, а},{b,b, b},b, b, с},{b, с, а},{b,с, b}, {b, с, с},{с,а, а},{с, а, b},{с, а, с},{с,b, а}, {с, b, b},{с,b, с},{с, с, а},{с, с, b},{с,с, с}}
или, более общо, декартово произведение списков:
In[34]:= Tuples [{{a1, a2 } , {b1, b2 , b3}, {c1, c2}}] Out[34] = {{a1, b1, c1}, {a1, b1, c2 }, {a1, b2 , c1}, {a1, b2, c2 }, {a1, b3, c1}, {a1, b3, c2}, {a2, b1, c1}, {a2, b1, c2}, {a2, b2, c1}, {a2, b2, c2}, {a2, b3, c1}, {a2, b3, c2}}
Наконец, еще две очень популярные команды: Outer и Inner, являющиеся обобщениями тензорного произведения и свертки тензоров (в частности, скалярного произведения).
Команда Outer[f,list1,list2,...] применяет произвольную функцию f к всевозможным комбинациям элементов списков list1,list2,...:
![In[35}:=Outer[CircleTimes, \left \{\begin{matrix}&&&\\ e, &e, &e,\\ 1&2&3 \end{matrix}\right\},\\
\begin{matrix}
& & & &\left\{ \begin{matrix}1&2&3\\ e, &e, &e,\\ & & & \end{matrix} \right\}, \left \{ \begin{matrix} \\ 3,\\ 1 \end{matrix} Underscript[e, 2] \right \} \right ]
\end{matrix}\\
Out[35]=\left\{ \left\{ \left\{\begin{matrix}&&1&&\\e&\otimes &e& \otimes &e\\1&&&&1\end{matrix}, \begin{matrix}&&1&&\\e&\otimes&e&\otimes&e\\1&&&&2
\end{matrix} \right\},\left\{\begin{matrix}&&2&&\\e&\otimes &e& \otimes &e\\ 1&&&&1 \end{matrix}, \begin{matrix} &&2&&\\ e&\otimes&e&\otimes&e\\ 1&&&&2 \end{matrix} \right\},\left\{\begin{matrix}&&3&&\\e&\otimes &e& \otimes &e\\ 1&&&&1 \end{matrix}, \begin{matrix} &&3&&\\ e&\otimes&e&\otimes&e\\ 1&&&&2 \end{matrix} \right\}\right\}\\](/sites/default/files/tex_cache/29e2e7f66dc12619e503d882304d97eb.png)
![\left\{ \left\{\begin{matrix}&&1&&\\e&\otimes &e& \otimes &e\\ 2&&&&1 \end{matrix}, \begin{matrix} &&1&&\\ e&\otimes&e&\otimes&e\\ 2&&&&2 \end{matrix} \right\}, \left\{\begin{matrix}&&2&&\\e&\otimes &e& \otimes &e\\ 2&&&&1 \end{matrix}, \begin{matrix} &&2&&\\ e&\otimes&e&\otimes&e\\ 2&&&&2 \end{matrix} \right\}\left\{\begin{matrix}&&3&&\\e&\otimes &e& \otimes&e\\2&&&&1\end{matrix},\begin{matrix}&&3&&\\e&\otimes&e&\otimes&e\\2&&&&2 \end{matrix} \right\}\right\}\\](/sites/default/files/tex_cache/51bf81c4a0094c64663089e7854bfaf2.png)
![\left\{\left\{\begin{matrix}&&1&&\\e&\otimes &e& \otimes &e\\3&&&&1 \end{matrix}, \begin{matrix}&&1&&\\ e&\otimes&e&\otimes&e\\ 3&&&&2 \end{matrix} \right\}, \left\{\begin{matrix}&&2&&\\e&\otimes &e& \otimes &e\\3&&&&1 \end{matrix}, \begin{matrix} &&2&&\\ e&\otimes&e&\otimes&e\\ 3&&&&2 \end{matrix} \right\}, \left\{\begin{matrix}&&3&&\\e&\otimes &e& \otimes e\\3&&&&1 \end{matrix}, \begin{matrix}&&3&&\\e&\otimes&e&\otimes&e\\3&&&&2\end{matrix} \right\} \right\}\right\}](/sites/default/files/tex_cache/f1dbc2b04e5c81c5730ca2a84b5d3705.png)
Команда Inner[f,list1,list2,g] обобщает команду Dot[] (или ".")
In[36]:={a, b, с} . {х, у, z} Out[36] =ax+by+cz
причем f играет роль умножения, а g - сложения:
In[37] := Inner [Min, {а, b, с}, {х, у, z}, Max] Inner [CircleTimes, {a, b, с}, {х, у, z}, Plus] Out[37]=Max [Min [a, x] , Min[b, у], Min [с, z] ]
![Out[38] = a x + b \otimes y + c \otimes z](/sites/default/files/tex_cache/eef952a2106b0552e311c8b75795f886.png)
Тензорные поля
В курсе дифференциальной геометрии, тензоры используются для изучения многообразий и порождают тензорные поля, т. е. тензоры одного и того же типа, заданные на касательных пространствах к многообразию. Теперь базисы в этих линейных пространствах выбираются исходя из локальных координат, а тензорный закон, как следствие, использует матрицу Якоби перехода от одной системы координат к другой. Таким образом, чтобы получить координатное представление тензорного поля, нужно вместо базисов еь ..., е" брать локальные координаты , вместо чисел
- функции
, а тензорный закон писать с использованием матриц Якоби.
Пример создания пакета для работы с тензорами
Опишем разработанный нами пакет для работы с тензорами. Мы приведем здесь лишь небольшую часть того, что необходимо при работе с тензорами и тензорными полями. Наш центральный принцип - сделать работу с тензорами наиболее наглядной. Чтобы загрузить наш пакет, следует выполнить команду
In[39] =Needs ["Tensors " " , NotebookDirectory [ ] <> "tensors.m"]
где второй аргумент - это имя файла, в котором пакет содержится. (Здесь мы предполагаем, что пакетный файл tensors.m расположен в той же папке, что и файл, с которым вы сейчас работаете, причем ваш файл или был открыт, уже находясь в указанной папке, или был сохранен в ней, иначе значение функции NotebookDirectory[] не определено.)
Правила работы в пакете Tensors
В данном разделе мы опишем возможности текущей версии пакета. Разумеется, их можно и нужно расширять.
Начало работы, создание базиса и тензоров, тензорные операции.
В пакете реализованы возможности работы как с алгебраическими тензорами (т. е. тензорами в линейном пространстве), так и с тензорными полями (в последнем случае, в текущей версии пакета, тензорные поля рассматриваются на многообразии, состоящем из одной карты, т. е. на области в ). Чтобы начать работу в пакете, следует задать или базис линейного пространства (функция makeBasis ), или локальные координаты и соответствующий канонический базис (функция makeBasisDif). Чтобы посмотреть формат интересующей вас функции пакета, следует выполнить команду ?<имя функции>. Например:
In40] := ? makeBasis
Зададим базис в трехмерном пространстве.
In[41] :=makeBasis [e, 3]
Все создаваемые базисы последовательно нумеруются. Номер текущего базиса записывается в переменную curBas, а сам базис - в список базисов basis:
In[42] := curBas basis[curBas] val[e] basis[1] Out[42] = 1
![Out[43]=\left\{ \begin{matrix}
1&2&3&&&\\
e,&e,&e,&e,&e,&e\\
&&&1&2&3
\end{matrix} \right\}\\
Out[44]=val[e]\\
Out[45]=\left\{ \begin{matrix}
1&2&3&&&\\
e,&e,&e,&e,&e,&e\\
&&&1&2&3
\end{matrix} \right\}](/sites/default/files/tex_cache/e3f2a662de861a88ed6ec9933f3c5051.png)
Отметим, что на самом деле команда создает также двойственный базис. Обратите внимание, что мы пишем индексы непосредственно над и под буквами (а не справа вверху и справа внизу). Это объясняется тем, что правый верхний индекс Mathematica воспринимает как степень. Набирать такие индексы удобно с помощью сочетаний клавиш Ctrl+= для нижнего индекса и Ctrl+7 для верхнего индекса. Если же требуется поставить одновременно верхний и нижний индексы, то следует набрать одновременно Ctrl+= +5.
После того как базис фиксирован, можно создать тензор любого типа. При этом предусмотрена возможность задать абстрактный тензор с неопределенными компонентами ( makeTensor ) и возможность задать тензор с конкретными значениями компонент ( makeTensorTab ):
In[46] =makeTensor [T, 1, 1] ; makeTensorTab [W, {2, b, с}, 1, 0] ;
Чтобы посмотреть значения компонент тензора, надо выполнить команду val:
In[47] : = val[T] val[W]
![Out[47]=\left\{\left\{ \begin{matrix}
1&1&1\\
T,&T,&T\\
1&2&3
\end{matrix} \right\}, \left\{ \begin{matrix}
2&2&2\\
T,&T,&T\\
1&2&3
\end{matrix} \right\}, \left\{ \begin{matrix}
3&3&3\\
T,&T,&T\\
1&2&3
\end{matrix}\right\}\right\}](/sites/default/files/tex_cache/f0a854db81948cfb2f68a586521f3b15.png)
Out[48] = {2, b, c}
Над заданными тензорами можно выполнять тензорные операции. Реализованы линейная комбинация, тензорное произведение, свертка, перестановка индексов, симметрирование, альтернирование.
![In[49] :=makeTensor [\xi , 0,1]](/sites/default/files/tex_cache/b362c00fdc26c1ad7c492786367a225c.png)
Значок тензорного произведения можно получить, набрав Esc c* Esc :
![In[50] : = val [\xi \otimes W]](/sites/default/files/tex_cache/b79f9fc2a99cdab9be96b3be72e96627.png)
![Out[50]=\left\{\left\{ \begin{matrix}
&&\\
2 \xi,&2\xi,&2\xi\\
1&2&3
\end{matrix} \right\}, \left\{ \begin{matrix}
&&\\
b \xi,&b \xi,&b \xi\\
1&2&3
\end{matrix} \right\}, \left\{ \begin{matrix}
&&\\
c \xi,& c \xi,& c\xi\\
1&2&3
\end{matrix}\right\}\right\}](/sites/default/files/tex_cache/33fc0be811016ecd1f49d711393b82e3.png)
Линейная комбинация допустима только для тензоров одного типа:
![In[51] : = val [xT + 4 \xi \otimes W] //MatrixForm](/sites/default/files/tex_cache/df15a0dfd6fd66ae7f68d39b1825468c.png)
![out[51]= \begin{pmatrix}
x\begin{matrix}1\\T\\1\end{matrix}+8\begin{matrix}\\\xi\\1 \end{matrix}&x\begin{matrix}1\\T\\2\end{matrix}+8\begin{matrix}\\\xi\\2 \end{matrix}&x\begin{matrix}1\\T\\3\end{matrix}+8\begin{matrix}\\\xi\\3 \end{matrix}\\
x\begin{matrix}2\\T\\1\end{matrix}+4b\begin{matrix}\\\xi\\1 \end{matrix}&x\begin{matrix}2\\T\\2\end{matrix}+4b\begin{matrix}\\\xi\\2 \end{matrix}&x\begin{matrix}2\\T\\3\end{matrix}+4b\begin{matrix}\\\xi\\3 \end{matrix}\\
x\begin{matrix}3\\T\\1\end{matrix}+4c\begin{matrix}\\\xi\\1 \end{matrix}&x\begin{matrix}2\\T\\3\end{matrix}+4c\begin{matrix}\\\xi\\2 \end{matrix}&x\begin{matrix}3\\T\\3\end{matrix}+4c\begin{matrix}\\\xi\\3 \end{matrix}
\end{pmatrix}](/sites/default/files/tex_cache/033d6ddc1fcd40cdee587e814e1acf2b.png)
![In[52]: = val[T + 2 \xi ]
\\
Out[52] =val [T + 2 \xi ]](/sites/default/files/tex_cache/1018e8aed771151f67fc40f6d3d1e26a.png)
Результат применения тензорных операций можно присвоить с помощью обычного оператора Set (т. е. =):
![In[53]:=R = хТ + 4 \xi \otimes W;
\\
val[R]](/sites/default/files/tex_cache/ba6f3fc123c7d43d73555c4e9ec9a9fc.png)
![\left\{\left\{x \begin{matrix}1\\T\\1 \end{matrix}+8 \begin{matrix}\\\xi\\1 \end{matrix},x \begin{matrix}1\\T\\2 \end{matrix}+8 \begin{matrix}\\\xi\\2 \end{matrix}, x \begin{matrix}1\\T\\3 \end{matrix}+8 \begin{matrix}\\\xi\\3 \end{matrix}\right\}, \left\{x \begin{matrix}2\\T\\1 \end{matrix}+4b \begin{matrix}\\\xi\\1 \end{matrix}, x \begin{matrix}2\\T\\2 \end{matrix}+4b \begin{matrix}\\\xi\\2 \end{matrix}, x \begin{matrix}2\\T\\3 \end{matrix}+4b \begin{matrix}\\\xi\\3 \end{matrix}\right\},\\
\left\{x \begin{matrix}3\\T\\1 \end{matrix}+4c \begin{matrix}\\\xi\\1 \end{matrix}, x \begin{matrix}3\\T\\2 \end{matrix}+4c\begin{matrix}\\\xi\\2 \end{matrix}, x \begin{matrix}3\\T\\3 \end{matrix}+4c\begin{matrix}\\\xi\\3 \end{matrix}\right\}\right\}](/sites/default/files/tex_cache/30c8fb5c11604f2c9fc31dfed41b1c3c.png)
Свертка записывается просто указанием номеров индексов, по которым надо сворачивать:
![In[55] : = val \left [\begin{matrix}1\\R\\1 \end{matrix} \right ]\\
Out[55]=x\begin{matrix}1\\T\\1 \end{matrix}+x\begin{matrix}2\\T\\2\end{matrix}+x\begin{matrix}3\\T\\3\end{matrix}+8\begin{matrix}\\\xi\\1\end{matrix}+4b\begin{matrix}\\\xi\\2\end{matrix}+4c\begin{matrix}\\\xi\\3\end{matrix}](/sites/default/files/tex_cache/7578690ce28b146210e3e2479b14d592.png)
Перестановка индексов указывается в виде списка, элементы которого суть
-образы последовательных натуральных чисел начиная с 1. При этом список заключается в дополнительные фигурные скобки и пишется сверху или снизу, в зависимости от того, какие индексы мы собираемся переставлять:
![In[56]:=makeTensor[B,0,2]\\
\begin{matrix}
&&&Row\left[\left\{"val[B]=", val[B]//MatrixForm,",\\
&&&val [\begin{matrix}\\B\\\{\{2,1\}\}\end{matrix} ]=", val \left [\begin{matrix}\\B\\\{\{2,1\}\}\end{matrix}\right ]//MatrixForm \}]
\end{matrix}\\
Out[57]=val[B]=\begin{pmatrix}
\begin{matrix}\\B\\11\end{matrix}&\begin{matrix}\\B\\12\end{matrix}&\begin{matrix}\\B\\13\end{matrix}\\
\begin{matrix}\\B\\21\end{matrix}&\begin{matrix}\\B\\22\end{matrix}&\begin{matrix}\\B\\23\end{matrix}\\
\begin{matrix}\\B\\31\end{matrix}&\begin{matrix}\\B\\32\end{matrix}&\begin{matrix}\\B\\33\end{matrix}
\end{pmatrix},\\
\begin{matrix}
&&&&val[\begin{matrix}\\B\\\{\{2,1\}\}\end{matrix}]=\begin{pmatrix}
\begin{matrix}\\B\\11\end{matrix}&\begin{matrix}\\B\\21\end{matrix}&\begin{matrix}\\B\\31\end{matrix}\\
\begin{matrix}\\B\\12\end{matrix}&\begin{matrix}\\B\\22\end{matrix}&\begin{matrix}\\B\\32\end{matrix}\\
\begin{matrix}\\B\\13\end{matrix}&\begin{matrix}\\B\\23\end{matrix}&\begin{matrix}\\B\\33\end{matrix}
\end{pmatrix}
\end{matrix}](/sites/default/files/tex_cache/0c9d9280ce618f935b67c3a3386ea141.png)