Тензоры: опыт создания пользовательского пакета программ
Аналогично выглядят команды альтернирования и симметрирования:
Также часто удобно вывести конкретную компоненту тензора. Это делается с помощью явного указания списков соответствующих индексов:
Аналогично, имеется возможность породить сразу симметричный или кососимметричный тензор типа (0,q). Для этого используются команды makeSymm, makeSkew, makeSymmTab, makeSkewTab. Для симметричных и ко сосимметричных тензоров определены операции симметричного произведения ( SmallCircle, Esc sc Esc ) и, соответственно, кососимметричного произведения ( Wedge, Esc ^ Esc ). Пакет относит к симметричным (кососимметричным) тензорам или тензоры, созданные перечисленными четырьмя операциями, или полученные в результате симметрирования или альтернирования тензоров типа (0,q) :
Отметим, что при создании (косо)симметричного тензора по таблице значений соответствующая функция не проверяет (косо)симметричность таблицы, а просто использует только часть данных, доопределяя значения по симметрии:
In[71]:=vall[bb]//MatrixForm
Запись тензора в тензорном базисе, вычисление значения тензора на наборе ковекторов и векторов0. Имеется возможность записать созданный тензор в базисе пространства тензоров данного типа:
In[72] : = makeTensor [T, 1, 2]; toBasis[T]
Для (косо)симметричных тензоров можно воспользоваться базисом в пространстве (косо)симметричных тензоров:
In[76]:=val[B]
Предусмотрен также набор обратных операций, вычисляющих список компонент тензора, заданного в виде линейной комбинации базисных. Это функции toList, toListSkew, toListSymm:
In[78]:=toBasis[T]
Out[81]=basis[5]
Напомним, что тензор типа (p,q) можно представлять себе как полилинейное отображение, заданное на прямом произведении p экземпляров двойственного пространства и q экземпляров самого пространства. Чтобы вычислить значение такого отображения, в пакете имеется функция apply :
In[86]:={a,b,c}
При этом, как видно из примера, имеется возможность подставлять сразу компоненты тензора. Если количество или вид аргументов не соответствует типу, выдается сообщение об ошибке или функция просто не выполняется:
Перезапуск. Чтобы отменить все созданные базисы, координаты и пр. следует выполнить команду resetTensors:
In[92] =basis [curBas] resetTensors basis[curBas]
Пакет Tensors перезапущен. Результаты вычислений аннулированы. Out[94] = basis [0]
Особенности работы с локальными координатами и тензорными полями. Если вы задали локальные координаты и соответствующий базис (команда makeBasisDif ), то появляется возможность задавать тензорные поля, компоненты которых суть абстрактные функции от координат. Соответствующий набор функций - это makeTensorField, makeSkewField и makeSymmField . Результат их работы - соответствующее тензорное поле, к которому можно применять обычные тензорные операции:
Замена координат или базиса, пересчет компонент, граф замен. Если мы хотим сделать замену координат, то следует создать новые координаты или новый базис с помощью команд makeBasisDif и makeBasis , указав явно связь нового базиса (координат) с каким-нибудь уже заданным (по умолчанию - с текущим) базисом (координатами). В линейно-алгебраическом случае это делается с помощью задания матрицы перехода (столбцы которой - суть компоненты векторов нового базиса в старом), а в случае локальных координат следует задавать функции перехода, выражающие текущие координаты через новые (см. примеры ниже). Кроме того, в качестве четвертого аргумента функции makeBasisDif можно задать функции, задающие обратное отображение и выражающие новые координаты через текущие. Проверка взаимной обратности остается на совести пользователя. Если переход задан, то новые координаты становятся текущими и значения всех тензоров автоматически в них пересчитывают.
Приведем соответствующие примеры. Чтобы удобнее было контролировать вычисления, пакет создает ориентированный граф graphBas замен координат (базисов). Вершины этого графа - системы координат. Две вершины соединены стрелкой, если соответствующая замена координат задана явно. Этот граф удобно вывести динамически. В приведенной ниже программе предусмотрен переход к координатам, выбранным мышкой. А именно, чтобы сделать замену, нужно кликнуть в соответствующую вершину графа:
In[99] := (*Создаем евклидовы координаты на плоскости*) resetTensors; makeBasisDif[{х, у}]; (*Задаем в них постоянную билинейную форму и произвольный вектор*)
makeTensorTab[W, {а, b} , 1, 0] ; (*Задаем полярные координаты. При этом Записываем функции перехода от них к текущим координатам, т.е. функции х[r, ϕ] и у[r, ϕ]. При этом текущими координатами становятся полярные *) makeBasisDif [ {r, ϕ , {r Cos [ϕ] , r Sin [ϕ] } ] ; In[104] := (*Программа, динамически выводящая граф замен*) DynamicModule[{}, Dynamic[Deploy[GraphPlot[graphBas, DirectedEdges -> True, VertexRenderingFunction -> ({White, EdgeForm[Black], EventHandler[Disk[#, .15], { "MouseDown" : > (changeBas [curBas , #2] ) } ] , If [#2 == curBas, Red, Black], EventHandler[Style[Text[Column[{coor[#2] , #2} , Center] , #l] , FontSize -> Scaled [0.03] ] , {"MouseDown" :> (changeBas[curBas, #2])}]} &), ImageSize -> {300, 350}] ] ], Initialization :-> Needs ["Tensors" , NotebookDirectory [] <> "tensors .m"] ]
In[105] := Dynamic [ {val [W] , apply[G, W, W] } // Simplify] Out[105]= {val [W] , apply [G, W, W] } In[106]:=(* Задаем еще одни координаты (u,v) . Функции перехода можно задать к любым имеющимся координатам, указав явно их номер. В следующем примере мы задаем функции перехода к декартовым координатам, т.е. функции x[u,v] и y[u,v]*) makeBasisDif [{u, v} , 1, {и^2 - v^2, 2 u v} ] ; (*A здесь - функции перехода к полярным координатам r[p,q] и ϕ [p,q]*) makeBasisDif [{p, q} , 2, {р1/3 , q\3}];
На графе видно, что переход от текущих (четвертых) координат не задан. Чтобы иметь возможность вернуться, следует прописать явно функции перехода с помощью команды makeTransDif :
In[108] := (*3адаем переход от 4х координат к полярным (вторым)*) makeTransDif[4, 2, {r3, 3ϕ}]; (*И еще переходы*) makeTransDif [3, 2, {Sqrt [r] Cos [ϕ / 2] , Sqrt [r] Sin [ϕ / 2] } ] ; makeTransDif[2, 1, {Sqrt[х^2+у^2] , ArcTan[y/ x] } ] ;
Теперь, кликая мышкой по вершинам графа, можно переходить от координат к координатам. При этом программа проверяет, есть ли в ориентированном графе путь, ведущий из текущей вершины в выбранную, и если есть, то пересчитывает необходимые функции перехода. Граф при этом перерисовывается.
Получающиеся выражения не всегда легко упрощаются. Это объективно связано с тем, что функции перехода определены не всюду. В пакете предусмотрена возможность добавлять предположения о значениях тех или иных переменных в список предположений $Assumptions, которым Mathematica пользуется при упрощениях, или убирать их оттуда. Соответствующие команды - это addAssumptions и clearAssumptions . Отметим, что предположение о вещественности заводимых координат делается автоматически.
In[111] := $Assumptions addAs sumptions [p>0, 0<q<π, r>0, -π / 2 < ϕ < π / 2] ; $As sumptions clearAssumptions [0 < q < π] ; $Assumptions addAs sumptions [p > 0, 0 < q < π / 6, u2-v2>0, u v > o] ; $As sumptions Out[111] = (x | y) º Reals && (r | ϕ) º Reals && (u | v) º Reals && (p | q) º Reals Out[113]= (p | q) º Reals && (r | ϕ) º Reals && (u | v) º Reals && (x | у) º Reals && p > 0 && r > 0 && 0 < q < π && - π/2 < ϕ < π/2 Out[115]= (p | q) º Reals && (r | ϕ) º Reals && (u | v) º Reals && (x | y) º Reals && p > 0 & & r > 0 && - π/2 < ϕ < π/2 Out[117] = (p | q) º Reals && (r | ϕ) º Reals && (u | v) º Reals && (x | у) º Reals && p > 0 && r > 0 && uv > 0 && u2-v2 > 0 && 0 < q < π/6 && -π/2 < ϕ < π/2