Tensor Visualization
Author
Bohan Lu
Title
Tensor Visualization
Description
Tensor Visualization
Category
Essays, Posts & Presentations
Keywords
URL
http://www.notebookarchive.org/2019-08-0gjhxfk/
DOI
https://notebookarchive.org/2019-08-0gjhxfk
Date Added
2019-08-01
Date Last Modified
2019-08-01
File Size
204.05 kilobytes
Supplements
Rights
Redistribution rights reserved
Download
Open in Wolfram Cloud
WOLFRAM SUMMER SCHOOL 2019
Tensor Visualization
Tensor Visualization
Bohan Lu
Jonathan Gorard
Introduction
Introduction
Tensors have wide applications in science and engineering. However, tedious index gymnastics often deter beginners and experienced researchers alike from grasping the physical meaning behind a string of tensors intuitively. The Penrose graphical notation was introduced by Roger Penrose to represent tensors by easily recognizable graphical objects that illustrate key structures at a glance. So far, no simple packages exist in the Wolfram language to convert tensor calculations to the Penrose graphical notations and vice versa. Thus, the aim of this project is to take tensor objects and their operations in the Wolfram language and visualize them using Penrose graphical notation. Here, we have created a package that parses a polynomial of tensor products and draws its graphical notation. A possible problem that might arise in the reverse direction may involve graph isomorphism problems because the Penrose graphical notation may not be unique and might require a sequence of transformations to turn a given diagram into default graphical standards. So it is not attempted in this project.
Crash Course on xAct
Crash Course on xAct
xAct is a Mathematica package for doing symbolic tensor calculations developed by José M. Martín−García. First, let us load the package
In[]:=
<<xAct`xTensor`
------------------------------------------------------------
Package xAct`xTensor` version 1.1.3, {2018,2,28}
CopyRight (C) 2002-2018, Jose M. Martin-Garcia, under the General Public License.
------------------------------------------------------------
These packages come with ABSOLUTELY NO WARRANTY; for details type Disclaimer[]. This is free software, and you are welcome to redistribute it under certain conditions. See the General Public License for details.
------------------------------------------------------------
In[]:=
ClearAll["Global`*"]
To make a tensor, we have to first define the manifold on which it resides :
In[]:=
DefManifold[M3,3,{a,b,c,d,e,f,g}]
** DefManifold: Defining manifold M3.
** DefVBundle: Defining vbundle TangentM3.
This is a three dimensional manifold with seven slots for indices, which tensors residing on it can use. To define the tensor T with some covariant and contravariant indices living on M3,
In[]:=
DefTensor[T[-a,b,-c,d,-e,f,-g],M3]
** DefTensor: Defining tensor T[-a,b,-c,d,-e,f,-g].
However, every instance of the tensor of this form can have any number and pattern of indices, as long as it follows the constraints given by the above definition. For example,
In[]:=
T[-a,b,-c,c]
Out[]=
T |
|
is a valid construction under the above definition. This is a tensor with two covariant (lower) indices “a” and “c”, and two contravariant (upper) indices “b” and “c”, with no symmetry specified.
The Penrose Graphical Notation
The Penrose Graphical Notation
The Penrose graphical notation is set of symbols, that when combined, can be used to described almost all tensorial equations and statements visually. For instance, on Wikipedia, one may find that
Out[]=
which stands for a contravariant vector
Out[]=
which stands for a covariant vector
Out[]=
which stands for a rank 4 tensor with two contravariant and two covariant tensors
Out[]=
which stands for a rank 4 tensor with one contravariant and three covariant tensors.
Design Principles
Design Principles
To visualize tensors, we need to make graph objects. To make everything simple, we opt not to use customized shapes for the head of the tensors, but use a standard boxed frame:
In[]:=
tensorShape[s_][x_,_,_]:=Inset[Framed[Style[s,TextAlignmentCenter,Medium,FontFamily"Times",Italic,Black],BackgroundLightBlue,RoundingRadius5],x]
, where "s" is the tensor head to be displayed, for instance,
. The tensorShape function takes a curried form, where the arguments are separated into two groups--the first argument is for the text we put in, and the second list of arguments including the empty slots are reserved for the VertexShapeFunction to fill in when constructing the graph.
T |
|
The input expression we consider is a tensorial polynomial, which means a linear combination of tensor products. We will construct a function that makes a graph object for each atomic/non-tensor-product type tensor called makeGraph, and a function that adds the tensor product notation ⊗ to each position where a tensor product takes place, called addTensorProduct. Then the final function tensorVisualize substitutes the graphs for atomic tensors in the original polynomial and display the expression as a graphics object of polynomial of tensors.
makeGraph
makeGraph
In[]:=
makeGraph[tensor_, outputContract_:False]:=Module{upIdx,downIdx,upEdgeList,downEdgeList, edgeList,vertexList,legList,upLabelList,downLabelList,graph,contractVertex},upIdx = IndicesOf[Up][Evaluate@tensor]/.IndexListList;downIdx = IndicesOf[Down][Evaluate@tensor]/.IndexListList;downEdgeList = Normal@AssociationMap[0&,downIdx];upEdgeList = Reverse[#,2]&@Normal@AssociationMap[0&,upIdx];edgeList = Join[downEdgeList,upEdgeList];legList=FindIndices@Evaluate@tensor;vertexList =Append[legList,0];upLabelList=Normal@AssociationThreadDirectedEdge@@@upEdgeList,Placed[#,"End"]&/@
/@ToString/@upEdgeList[[All,2]];downLabelList=Normal@AssociationThreadDirectedEdge@@@downEdgeList,Placed[#,"Start"]&/@
/@ToString/@-downEdgeList[[All,1]];graph=Graph[DirectedEdge@@@edgeList,GraphLayout{"RadialEmbedding","RootVertex"0},VertexShapeFunction{0tensorShape[tensor//StandardForm],None},VertexSize0.45,VertexLabelsNone,PerformanceGoal"Quality",EdgeLabelsJoin[upLabelList,downLabelList]];If [IntersectingQ[upIdx,-downIdx],contractVertex=Intersection[upIdx,-downIdx];graph =VertexContract[graph,#]&@Thread[{contractVertex,-contractVertex}];If[outputContract,contractVertex,EdgeAdd[graph,DirectedEdge[0,0],EdgeLabelsJoin[Options[graph,EdgeLabels][[1,2]],{DirectedEdge[0,0]StringRiffle[contractVertex,", "]}]]],graph]
Function[ ] |
Function[ ] |
In[]:=
Clear[makeGraph]
The IndicesOf and FindIndices are functions from xAct that returns the list of indices of the tensor, with which we build a list of edges that will constitute the graph. For the head of the tensor, we by convention set its vertex to be “1”. Then we distinguish contra- and covariant indices by using DirectedEdge. All edges that go from the vertex representing the index to “1” are covariant, and all edges that go from “1” to the indices are contravariant. So for example, if we have a tensor with a contravariant index “a”, and two covariant indices “b” and “c”, then the list of edges are
In[]:=
DirectedEdge@@@{{1,a},{b,1},{c,1}}
Out[]=
{1a,b1,c1}
For tensors that have repeating indices that appear both in the top and the bottom, the indices will be contracted according the Einstein summation rule. So if the original tensor has rank n, the contracted tensor will have rank n-2. To take contraction into account, we used VertexContract to remove the edges that represent indices to be contracted. Then we add a self-directed loop to goes from “1” to “1” to represent all the contracted indices.
addTensorProduct
addTensorProduct
In[]:=
addTensorProduct[tensor_]:=Replace[tensor,(HoldPattern[Times[pre___,tensors:Repeated[_?(xTensorQ[Head[#]]&),{2,Infinity}]]])Times[pre,CircleTimes[tensors]],Infinity]
, where xTensorQ is a function from xAct that tests whether the head of a expression is a tensor that has been defined. This function searches for occasions where two or more tensor objects are multiplied together, and inserts a tensor product symbol ⊗ in between.
replaceByGraph
replaceByGraph
In[]:=
replaceByGraph[tensor_]:=tensor/.t_?(xTensorQ[#[[0]]]&) Show[makeGraph@t,ImageSizeMedium]
This function replace all the atomic tensor expressions by their graphical representation produced by makeGraph. It looks for all expression that has a tensorial head using
_?(xTensorQ[#[[0]]]&)
and maps the tensor to the graph using RuleDelayed.
tensorVisualize
tensorVisualize
In[]:=
tensorVisualize[tensor_,size_:60,simple_:True]/;BooleanQ[simple]:=If[simple,Style[#,FontSizesize]&@replaceByGraph@addTensorProduct@Simplification@tensor,Style[#,FontSizesize]&@replaceByGraph@addTensorProduct@tensor]
This function composes the functions above and visualizes a polynomial of tensor products, with the option to view the simplified version returned xAct.
Examples
Examples
In[]:=
tensorExpr1=T[-a,b,-c,c]
Out[]=
T |
|
Let us visualize it!
In[]:=
tensorVisualize@tensorExpr1
Out[]=
Let us build a polynomial of tensors and see how it can be visualized. First , we can define some other tensors, say
In[]:=
DefTensor[G[a,-b,-c,d,-e,f],M3]
** DefTensor: Defining tensor G[a,-b,-c,d,-e,f].
In[]:=
DefTensor[v[a],M3]
** DefTensor: Defining tensor v[a].
In[]:=
tensorExpr2=T[-a,b,-c,c]G[d,-e,-f,e,-g,h]+7*v[a]
Out[]=
G |
|
T |
|
v |
|
If we visualize this tensor with the default option, where simplification from xAct is turned on, then it will return:
In[]:=
tensorVisualize[tensorExpr2]
::inhom
Out[]=
Hold[Throw[Null]]
, because the tensor polynomial is not a validate expression. A valid tensor polynomial must be homogenous, that is, all tensor products being summed up must have the same rank. This is not the case here, nonetheless, we can visualize this ill-defined tensor by turning off the simplification option:
In[]:=
tensorVisualize[tensorExpr2,60,False]
Out[]=
⊗
+7
Cite this as: Bohan Lu, "Tensor Visualization" from the Notebook Archive (2019), https://notebookarchive.org/2019-08-0gjhxfk
Download