====== Standard form of mathematical expressions ======
Next topic: [[documentation:guide:symmetries_of_tensors]]
----
A core feature of any CAS is its ability to reduce arbitrary expression to some
standard form (**SF**) in which it is then used everywhere in manipulations. This
approach facilitates comparison and matching of expressions and gives a way for
more robust and fast algorithms for almost all CAS operations. Redberry uses the
same paradigm: any intermediate and resulting expression is guaranteed to be in the
**SF**.
====Standard form of indexless expressions ====
The standard form of indexless expressions is same as in the majority of other CASs. Consider the following examples, which give an idea of **SF** in Redberry:
println '(a-b)+c+(b-a)'.t
> c
println 'c*(a-b)*(b-a)/c'.t
> -(a-b)**2
println '2/3-27**(1/3)/9'.t
> 1/3
println 'Sin[2 + 2.*I]**(1/4)'.t
> 1.38307 - 0.144188*I
The first example demonstrates that Redberry performs the reduction of similar
terms. The second --- that same (to within a sign) multipliers are collected into
powers or reduced. Numbers are always collected and reduced if possible. If
expression contains floating-point numbers, then it will be completely reduced
(calculated). This behaviour is similar to the majority of "scalar" CASs and needs no more detailed explanation.
====Standard form of indexed expressions====
The additional conventions on standard form arise in expressions that contain
tensors. The most remarkable convention is on the **SF** of [[documentation:ref:Sum]]. It is best to
demonstrate it by example:
println 'a*F_mn+(a+b)*F_mn'.t
> (2*a+b)*F_{mn}
As one can see, Redberry tries to factor out tensorial and leave “scalar” (with zero sized [[documentation:ref:indices]]) parts of products; this is a general rule used by Redberry for bringing sums into standard form. Consider another example:
println '(x_a^a + y_b^b)*X_m*X_n + (z_a^a - y_d^d)*X_m*X_n'.t
> (x_{a}^{a}+z_{a}^{a})*X_{m}*X_{n}
Here Redberry factored tensorial part ''X_m*X_n'' since both sums ''(x_a^a+y_b^b)'' and ''(z_n^n-y_d^d)'' have indices with zero size (because [[documentation:ref:indices]] of [[documentation:ref:Sum]] are free indices of its summands):
println 'x_a^a + y_b^b'.t.indices.size()
> 0
On the other hand, the following tensor will not be further reduced:
println 'x_a^a * X_m*X_n + y_a^a * X_m*X_n'.t
> x_a^a * X_m*X_n + y_a^a * X_m*X_n
This is because each multiplier of e.g. ''x_a^a * X_m*X_n'' (and in particular ''x_a^a'') has indices of nonzero size:
def ind = 'x_a^a'.t.indices
//only free indices has zero size
println [ind.size(), ind.free.size()]
> [2, 0]
Consider the last example:
println '(x_a^a + y_b^b)*X_m*X^m + (z_m^m - y_d^d)*X_a*X^a'.t
> (x_{a}^{a}+z_{a}^{a})*X^{m}*X_{m}
Here Redberry factored the same tensorial part (''X_m*X^m'' equals to ''X_a*X^a'') and collected similar terms in the formed [[documentation:ref:Sum]]. One can also see that Redberry automatically relabelled conflicting dummy indices.
====The ordering of terms====
The important detail is ordering of summands and multipliers within sums and
products. Elements of sums and products are sorted by their 32 bit hash codes.
Hashes for simple tensors (e.g. ''x'' or ''k_p'') are generated
randomly at each Redberry run, while hashes of complicated tensors (e.g.
''Sin[x]*k_i'') are calculated according to certain complex
rules. Actually, hash functions are organised in such a way that they are "insensitive" for particular names of indices but "sensitive" for their contractions. So, renaming of dummy or free indices does not affect hash code, but any modification of structure of contractions (e.g. contraction of two
free indices) does.
Usage of the pseudorandom generator allows to obtain nearly
uniform distribution of hashes of tensors, which significantly improves the
performance. However, the ordering of expressions changes from run to run, and e.g.
product ''a*b*c'' will be sorted differently at different runs
(''b*c*a'' or ''b*a*c'' etc.). Of course, all similar expressions
will have similar ordering in current session. One can fix
the seed of pseudorandom generator inside, so that expressions will have same
ordering from run to run, by putting the following line in the beginning of the code:
import cc.redberry.core.context.CC
import cc.redberry.groovy.Redberry
use(Redberry) {
CC.resetTensorNames(1)
//your code here
}
====Internal details====
The reduction to **SF** is a light-weight operation which does not perform any time-consuming simplifications.
In contrast to many other open-source tensorial CASs, Redberry not uses so-called //indices canonicalisation// (sorting) approach. It uses another approach for the problem of tensors comparison and simplification, which will be discussed in more detail in [[documentation:guide:Mappings of indices]].
User can rely on the fact that inside any calculation all expressions are reduced to the **SF**. This fairly simplifies implementation of custom transformations and algorithms.