The most frequent transformation in all computations is a substitution. Here we shall discuss the usage aspects of substitutions, while the idea of the underlying algorithms can be found in Mappings of indices.

The very important feature of any tensorial CAS is automatic relabelling of dummy indices in the case of dummy indices clash. Redberry takes care about it in all types of substitutions. Consider, for example, the following simple substitution: \[ x = x_a{}^a \qquad\text{in}\qquad (x\, f_a + y_a) (x \, f_b + z_b) \] Here is a code to perform this substitution in Redberry:

def s = 'x = x_a^a'.t
def t = '(x*f_a + y_a)*(x*f_b + z_b)'.t
println s >> t
   > (x_{d}^{d}*f_{a}+y_{a})*(x_{c}^{c}*f_{b}+z_{b})
As one can see, the appropriate relabelling was performed automatically.

Substitutions of tensor fields

Redberry supports substitutions of tensorial functions and automatically performs matching of function arguments during substitution:

def s = 'F_ij[x_m, y_m] = x_i*y_j'.t
def t = 'T^ab*F_ab[p^a - q^a, p^a + q^a]'.t
println s >> t
   > T^{ab}*(p_{a}-q_{a})*(p_{b}+q_{b})
If TensorField depends on indexed argument, then some ambiguities arise when mapping the arguments. For example, the following substitution: \[ F_i (x_{mn}) \,=\, x_{ij} f^j \qquad \rightarrow \qquad F_k(x_i\,y_j) \] can be performed in two different ways: (a) matching $x_{ij} \to x_i y_j$ gives $x_k y_j f^j$, (b) matching $x_{ij} \to x_j y_i$ gives $y_k x_j f^j$. This is because the indices of product ($x_i y_j$) are not ordered by their nature. To explicitly specify the matching rule in such ambiguous situations, Redberry allows to enter the correspondence of indices in the field arguments:
def s = 'F_i[x_mn] = x_ik*f^k'.t
def t = 'F_k[x_i*y_j]'.t //equivalent to F_k[x_i*y_j:_ij]
println s >> t
   > x_{k}*y_{a}*f^{a}
t = 'F_k[x_i*y_j:_ji]'.t 
println s >> t
   > x_{a}*y_{k}*f^{a}

Substitutions of products, sums, etc.

As well as SimpleTensor and TensorField substitutions, Redberry fully supports all other types of substitutions, taking into account both indices symmetries and indices contractions. Consider the following complicated example. Let's apply the following substitution \[ f_{m} + R_{bma}\,F^{ba} - R_{ljm}\,F^{lj} = R_{bam}\,F^{ab} \] to tensor \[ f_i + R_{ijk} F^{jk} + R_{ijk}\,F^{kj} - R_{kij}\,F^{jk}, \] where $R_{abc}$ is antisymmetric: \( R_{abc} \,=\, - R_{cba}\). It is easy to show that the result will be zero. In Redberry one can e.g. do

addSymmetry 'R_mnp', -[[0, 2]].p
def s = 'f_m + R_bma*F^ba - R_ljm*F^lj =  R_bam*F^ab'.t
def t = 'f_i + R_ijk*F^jk + R_ijk*F^kj - R_kij*F^jk'.t
println s >> t
   > 0
We see, that Redberry matched the l.h.s. of the substitution in tensor t and automatically reduced the resulting sum to the standard form, which, in turn, gave zero.

Redberry takes into account not only predefined symmetries of simple tensors, but also symmetries of any complicated expression, which arise from its structure. For example:

def s = 'K_a * (A^ab - A^ba) = F^a*A_a^b'.t
def t = 'K_p * (A^qp - A^pq) + F^b*A_b^q'.t
println s >> t
   > 0
The result is zero since tensor $(A_{cb} - A_{bc})$ is antisymmetric. As well, Redberry takes care about symmetries of indexless objects:
def c = 'Cos[a - b] = c'.t,
    s = 'Sin[a - b] = s'.t,
    t = 'x = Cos[b - a]**3 + Sin[b - a]**3'.t
println (c | s) >> t
   > x = c**3 - s**3 
As one can see, the built-in definitions of sine and cosine are set up to be odd and even respectively.

Sequential vs. simultaneous substitutions

There is an important note on applying several substitutions at a time using the joining of transformations. Substitutions joined with & operator will be applied sequentially. However, sometimes it is necessary to apply several substitution rules “simultaneously”. Consider the following example:

def X2YandY2X = 'x=y'.t & 'y=x'.t,
    X2YorY2X  = 'x=y'.t | 'y=x'.t,
    tensor = 'x+2*y'.t    
println X2YandY2X >> tensor
   > 3*x
println X2YorY2X >> tensor
   > y+2*x
The first transformation (X2YandY2X) means just sequential applying of two provided substitutions, while the second (X2YorY2X) performs both substitutions “simultaneously”.

Constructing substitutions

Sometimes it is necessary to create substitution from a given l.h.s and r.h.s that are raised from other calculations (not entered “by hand”). In order to construct such expression programmatically from a given l.h.s. and r.h.s. one can use the following syntax:

 def lhs = 'x'.t,
    rhs = 'a + b'.t
//this is equivalent to subs = 'x = a + b'.t
def subs = lhs.eq(rhs)
//or equivalently
subs = "$lhs = $rhs".t
println subs >> 'x**2'.t
   > (a + b)**2

See also