====== Product ======
----
=====Basics=====
''Product'' represents a product of terms. Like any other expression, it inherits all properties of [[Tensor]]. ''Product'' adopts the following convention on its indices: the indices of product are sorted concatenated indices of its multipliers:
def t = 'f_ba*t^c_c*h^a'.t
println t.indice
> ^{ac}_{abc}
''Product'' sorts its arguments and collapses equal scalar terms into powers.
''Product'' is one of the most sophisticated entities in Redberry: contractions of indices brings additional structure of mathematical //graph// which is reflected in ''Product'' by introducing several methods to access graph structure of product.
The data structure used to represent product contains three main blocks: numerical factor, subproduct of scalar factors (with ''indices.size() == 0''), and tensorial content (with ''indices.size() != 0''). Each block can be obtained via special additional methods introduced in product.
=====Additional features=====
There are several features in addition to those defined in [[Tensor]] that are inherent only in [[Product]]:
.select(positions) |
returns a product of elements at specified positions |
.remove(positions) |
returns a product with removed elements at specified positions |
.factor |
returns a numerical factor of product |
.indexlessSubProduct |
returns a subproduct of indexless terms, i.e. product of those terms which indices.size() == 0 |
.dataSubProduct |
returns a subproduct of indexed terms, i.e. product of those terms which indices.size() != 0 |
.content |
returns a data structure that allows to access graph structure of product |
Consider examples:
def p = '2*a*b*f_ba*t^c_c*h^a'.t
println p.select(2, 3, 5)
> a*t^{c}_{c}*h^{a}
println p.remove(2, 3, 5)
> 2*b*f_{ba}
println p.factor
> 2
println p.indexlessSubProduct
> 2*b*a
println p.dataSubProduct
> t^{c}_{c}*f_{ba}*h^{a}
=====Advanced features: product content and graph structure =====
The presence of indices bring a //graph structure// of Product: each multiplier represents a graph vertex, while contractions between indices are edges. One can check whether two graph isomorphic, i.e. that two tensors are equal to within free and dummy indices relabelling using [[documentation:guide:mappings_of_indices]].
There is a special property ''.content'', which allows to access graph structure of ''Product''; the object returned by ''.content'' called ''ProductContent''. It holds tensorial part of product and additional low-level data structures used in Redberry to represent tensorial graphs. Besides, ''ProductContent'' provides several useful methods like ''.scalars'' and ''.nonScalar'' which return array of scalar sub-products and non-scalar part of tensor respectively. Consider examples:
def p = '2*a*f_a*t^ba*g_b*t^i_i*t^mn*f_nmk'.t
println p.size()
> 8
def content = p.content
println content.size()
> 6
println content[0..content.size()]
> [f_a, t^ba, g_b, t^i_i, t^mn, f_nmk]
println content.scalars
> [t^{i}_{i}, t^{ba}*g_{b}*f_{a}]
println content.nonScalar
> t^{mn}*f_{nmk}
In order to access low-level structure that encodes ''Product'' graph there is ''.structureOfContractions'' property in ''ProductContent''. This structure allows to check connected components of graph and check for each particular tensor with which tensors it is contracted. Without going into low-level details, let's illustrate this features by the examples:
def p = '3*c*f_i*g_b*t^i_i*t^pq*f_qpk*t^bie'.t
def content = p.content
//get graph representation
def graph = content.structureOfContractions
//array of connected components
println graph.components
> [0, 1, 0, 1, 2, 0]
The array of //components// indicates whether two tensors belongs to the same connected component of graph: two tensors at //i//-th and //j//-th positions belongs to the same component if
''components[i] == components[j]'', and ''components[i]'' is the number of corresponding component.
//get position of tensor t^bie
def i = content.findIndexOf { it.equals('t^bie'.t) }
//contractions of tensor t^bie
def contractions = graph.getContractedWith(i)
for (def c in contractions) {
if (c.tensor == -1)//free index
println "Free indices:" + content[i].indices[c.indicesFrom]
else {
println "With tensor: " + content[c.tensor]
println "This indices:" + content[i].indices[c.indicesFrom]
println "With indices:" + content[c.tensor].indices[c.indicesTo]
}
}
> Free indices:^{e}
> With tensor: g_{b}
> This indices:^{b}
> With indices:_{b}
> With tensor: f_{i}
> This indices:^{i}
> With indices:_{i}
=====See also=====
* Related guides: [[documentation:guide:tensors_and_indices]], [[documentation:guide:tree_traversal]], [[documentation:guide:mappings_of_indices]]
* Reference: [[documentation:ref:tensor]], [[documentation:ref:sum]], [[documentation:ref:indices]], [[documentation:ref:simpletensor]], [[documentation:ref:tensorfield]]
* JavaDocs: [[http://api.redberry.cc/redberry/1.1.9/java-api/cc/redberry/core/tensor/Product.html| Product]]
* Source code: [[https://bitbucket.org/redberry/redberry/src/tip/core/src/main/java/cc/redberry/core/tensor/Product.java|Product.java]]