Title: | Ricci Calculus |
Version: | 0.1.1 |
Description: | Provides a compact 'R' interface for performing tensor calculations. This is achieved by allowing (upper and lower) index labeling of arrays and making use of Ricci calculus conventions to implicitly trigger contractions and diagonal subsetting. Explicit tensor operations, such as addition, subtraction and multiplication of tensors via the standard operators, raising and lowering indices, taking symmetric or antisymmetric tensor parts, as well as the Kronecker product are available. Common tensors like the Kronecker delta, Levi Civita epsilon, certain metric tensors, the Christoffel symbols, the Riemann as well as Ricci tensors are provided. The covariant derivative of tensor fields with respect to any metric tensor can be evaluated. An effort was made to provide the user with useful error messages. |
License: | GPL (≥ 3) |
Encoding: | UTF-8 |
RoxygenNote: | 7.3.2 |
Suggests: | knitr, rmarkdown, Ryacas, testthat (≥ 3.0.0), waldo |
Config/testthat/edition: | 3 |
Imports: | calculus, cli, rlang |
Depends: | R (≥ 4.1.0) |
URL: | https://github.com/lschneiderbauer/ricci, https://lschneiderbauer.github.io/ricci/ |
BugReports: | https://github.com/lschneiderbauer/ricci/issues |
VignetteBuilder: | knitr, rmarkdown |
NeedsCompilation: | no |
Packaged: | 2025-08-30 15:28:10 UTC; lukas |
Author: | Lukas Schneiderbauer
|
Maintainer: | Lukas Schneiderbauer <lukas.schneiderbauer@gmail.com> |
Repository: | CRAN |
Date/Publication: | 2025-09-04 14:20:02 UTC |
Index slot label specification
Description
This function creates a index slot label specification. Any R symbol
can serve as a label. .()
is typically used in conjunction with
%_%.
Usage
.(...)
Arguments
... |
Index labels separated by commas optionally prefixed by "+" and "-" to indicate the index position (upper and lower respectively). If no prefix is provided, a lower index ("-") is assumed. This argument uses non-standard evaluation: any R symbol that is not a reserved keyword can be used. |
Value
A named list of two character vectors representing the index label names and index position.
Examples
# three lower index slots
.(i, j, k)
# one lower and upper index
.(i, +j)
Arithmetic tensor operations
Description
Once a labeled array (tensor) has been defined, tensor arithmetic operations
can be carried out with the usual +
, -
, *
, /
, and ==
symbols.
Usage
## S3 method for class 'tensor'
Ops(e1, e2)
Arguments
e1 , e2 |
Labeled arrays created with %_%. |
Value
A resulting labeled array in case of +
, -
, *
, /
.
TRUE
or FALSE
in case of ==
.
Addition and Subtraction
Addition and subtraction requires the two tensors to have an equal index structure, i.e. the index names their position and the dimensions associated to the index names have to agree. The index order does not matter, the operation will match dimensions by index name.
Multiplication
Tensor multiplication takes into account implicit Ricci calculus rules depending on index placement.
Equal-named and opposite-positioned dimensions are contracted.
Equal-named and equal-positioned dimensions are subsetted.
The result is an outer product for distinct index names.
Division
Division performs element-wise division. If the second argument is a scalar, each element is simply divided by the scalar. Similar to addition and subtraction, division requires the two tensors to have an equal index structure, i.e. the index names their position and the dimensions associated to the index names have to agree.
Equality check
A tensor a_{i_1 i_2 ...}
is equal to a tensor b_{j_1 j_2 ...}
if
and only if the index structure agrees and all components are equal.
See Also
Other tensor operations:
asym()
,
kron()
,
l()
,
r()
,
subst()
,
sym()
Examples
a <- array(1:4, c(2, 2))
b <- array(3 + 1:4, c(2, 2))
# addition
a %_% .(i, j) + b %_% .(j, i)
# multiplication
a %_% .(i, j) * b %_% .(+i, k)
# division
a %_% .(i, j) / 10
# equality check
a %_% .(i, j) == a %_% .(i, j)
a %_% .(i, j) == a %_% .(j, i)
a %_% .(i, j) == b %_% .(i, j)
# this will err because index structure does not agree
try(a %_% .(i, j) == a %_% .(k, j))
Strip array labels
Description
Converts a tensor()
to an array()
by stripping the index labels.
An index label order
needs to be provided so that the array's dim()
order is well defined.
Usage
## S3 method for class 'tensor'
as.array(
x,
index_order = NULL,
...,
arg = "index_order",
call = rlang::caller_env()
)
Arguments
x |
A labeled array ("tensor" object) created by |
index_order |
An index specification created with |
... |
Not used. |
arg , call |
Used for error handling. Can be ignored by the user. |
Value
The tensor components as usual array()
object without any index labels
attached.
Examples
array(1:8, dim = c(2, 2, 2)) %_% .(i, +i, k) |> as.array(.(k))
Strip array labels
Description
Converts a tensor()
to an array()
by stripping the index labels.
An index label order
needs to be provided so that the array's dim()
order is well defined.
Usage
as_a(x, ...)
Arguments
x |
A labeled array ("tensor" object) created by |
... |
Index labels separated by commas optionally prefixed by "+" and "-"
to indicate the index position (upper and lower respectively).
If no prefix is provided, a lower index ("-") is assumed.
This argument uses non-standard evaluation: any R symbol
that is not a reserved keyword can be used.
The specification needs to match all the labels occurring in |
Value
A usual array()
without attached labels. The dimension order is
determined by ...
.
See Also
The same functionality is implemented in as.array.tensor()
but with standard evaluation.
Examples
array(1:8, dim = c(2, 2, 2)) %_% .(i, +i, k) |> as_a(k)
Antisymmetric tensor part
Description
Takes the antisymmetric tensor part of a tensor x
with respect to the
specified indices ...
.
An error is thrown if the specified indices do not exist.
Usage
asym(x, ...)
Arguments
x |
|
... |
Any number of index expressions. The indices need to occur
in |
Value
A modified tensor object.
See Also
Wikipedia: Ricci calculus - Symmetric and antisymmetric parts
Other tensor operations:
Ops.tensor()
,
kron()
,
l()
,
r()
,
subst()
,
sym()
Examples
a <- array(1:4, dim = c(2, 2))
a %_% .(i, j) |> asym(i, j)
Evaluate a symbolic array
Description
Evaluates a symbolic array at a particular point in parameter space. Partial evaluation is not allowed, all variables/symbols need to be accounted for. The result is a numeric array.
Usage
at(x, vars)
## S3 method for class 'array'
at(x, vars)
## S3 method for class 'tensor'
at(x, vars)
Arguments
x |
|
vars |
A named vector with parameter-value assignments. Each named entry represents a substitution of a symbol with the given value. |
Value
A numeric array()
or tensor()
.
Examples
g_sph(3) |> at(c(ph1 = 0, ph2 = 0))
Christoffel symbols
Description
Provides the Christoffel symbols of the first kind \Gamma_{ijk}
with
respect to the Levi Civita connection for a given metric tensor.
Usage
christoffel(g)
Arguments
g |
A covariant metric tensor, a "metric_field" object. See |
Details
The Christoffel symbols are a rank 3 array of numbers.
Value
Returns the Christoffel symbols of the first kind \Gamma_{ijk}
as rank 3 array()
.
See Also
Wikipedia: Christoffel symbols
Other geometric tensors:
ricci()
,
ricci_sc()
,
riemann()
Examples
christoffel(g_eucl_sph(3))
Covariant Derivative
Description
Calculates the (symbolic) covariant derivative
\nabla_\rho a_{\mu_{1} \mu_{2} ...}^{\nu_{1}\nu_{2}...}
with respect
to the Levi Civita connection of any (symbolic) tensor field.
The result is a new tensor of one rank higher than
the original tensor rank.
Usage
covd(x, i, g, act_on = NULL)
Arguments
x |
A labeled tensor object, created by |
i |
An index slot label specification created with |
g |
A covariant metric tensor, a "metric_field" object. See |
act_on |
An optional index slot label specification created with |
Details
Note that symbolic derivatives are not always completely trustworthy.
They usually ignore subtle issues like undefined expressions at certain
points. The example \nabla_a \nabla^a r^{-1}
from below is telling:
The symbolic derivative
evaluates to zero identically, although strictly speaking the derivative
is not defined at r = 0
.
Value
The covariant derivative: a new labeled array with one or more additional
indices (depending on i
).
See Also
Wikipedia: Covariant Derivative
Examples
options(ricci.auto_simplify = TRUE)
# gradient of "sin(sqrt(x1^2+x2^2+x3^2))" in 3-dimensional euclidean space
covd("sin(x1)", .(k), g = g_eucl_cart(3))
# laplace operator
covd("sin(x1)", .(-k, +k), g = g_eucl_cart(3))
covd("1/r", .(-k, +k), g = g_eucl_sph(3))
Kronecker delta
Description
Provides a labeled generalized Kronecker delta. In the special case of two labels this represents simply the identity matrix. The Kronecker delta always has an even number of indices. Note that the first half of the tensor labels need to be lowered, while the second half needs upper indices. Otherwise an error is thrown.
Usage
d(n)
Arguments
n |
The dimension. |
Value
A function that expects index labels (see .()
) and returns a
labeled tensor. The underlying data will differs depending on
the number of labels provided.
See Also
Underlying implementation: calculus::delta()
Wikipedia: Generalized Kronecker delta
Other tensor symbols:
e()
Examples
d(3)(i, +j)
d(3)(i, j, +k, +l)
Levi-Civita epsilon
Description
Provides a labeled Levi-Civita epsilon (pseudo) tensor. The indices are required to be lowered. Otherwise an error is thrown.
Usage
e(...)
Arguments
... |
Index labels separated by commas optionally prefixed by "+" and "-" to indicate the index position (upper and lower respectively). If no prefix is provided, a lower index ("-") is assumed. This argument uses non-standard evaluation: any R symbol that is not a reserved keyword can be used. |
Value
A labeled tensor object. The underlying data will differs depending on the number of labels provided.
See Also
Underlying implementation: calculus::epsilon()
Wikipedia: Levi-Civita symbol
Other tensor symbols:
d()
Examples
e(i, j)
e(i, j, k)
Does code return the expected value?
Description
Adds an expectation function that can be used with the testthat package. Compares two tensors and determines whether they are equal or not.
Usage
expect_tensor_equal(object, expected, ...)
Arguments
object , expected |
Computation and value to compare it to. Both arguments supports limited unquoting to make it easier to generate readable failures within a function or for loop. See quasi_label for more details. |
... |
Arguments passed on to
|
Value
The actual value invisibly.
Euclidean metric tensor
Description
Provides the Euclidean metric tensor of \mathbb{E}^n
.
g_eucl_cart()
returns a numeric (constant) tensor in Cartesian coordinates,
ds^2=\sum_{i=1}^n dx_i^2
while g_eucl_sph()
returns a symbolic tensor field in generalized spherical
coordinates {r, \phi_1, \phi_2, ..., \phi_{n-1}}
.
ds^2=dr^2 + r^2 d\Omega^2
Usage
g_eucl_cart(n, coords = paste0("x", 1:n))
g_eucl_sph(n, coords = c("r", paste0("ph", 1:(n - 1))))
Arguments
n |
The dimension of the metric tensor. |
coords |
A character vector of coordinate names. The length needs to match the tensor dimensions. |
Details
As usual, spherical coordinates are degenerate at r = 0
and \phi_l = 0
, so be
careful around those points.
Value
The covariant metric tensor as array imputed with coordinate names.
See Also
Wikipedia: Euclidean metric tensor
Other metric tensors:
g_mink_cart()
,
g_sph()
,
g_ss()
,
metric_field()
Examples
g_eucl_cart(3)
g_eucl_cart(3) %_% .(+i, +j)
g_eucl_sph(3)
g_eucl_sph(3) %_% .(+i, +j)
Minkowski metric tensor
Description
g_mink_cart()
provides the covariant metric tensor in n
dimensions in
Cartesian coordinates with signature (-1, 1, 1, ...)
.
ds^2=-dx_0^2+\sum_{i=1}^{n-1} dx_i^2
g_mink_sph()
provides the same tensor where the spatial part uses spherical
coordinates.
ds^2=-dt^2 + dr^2 + r^2 d\Omega^2
Usage
g_mink_cart(n, coords = paste0("x", 1:n - 1))
g_mink_sph(n, coords = c("t", "r", paste0("ph", 1:(n - 2))))
Arguments
n |
The dimension of the metric tensor. |
coords |
A character vector of coordinate names. The length needs to match the tensor dimensions. |
Value
The covariant metric tensor as array imputed with coordinate names.
See Also
Wikipedia Minkowski metric tensor
Other metric tensors:
g_eucl_cart()
,
g_sph()
,
g_ss()
,
metric_field()
Examples
g_mink_cart(4)
g_mink_cart(4) %_% .(+i, +j)
g_mink_sph(4)
g_mink_sph(4) %_% .(+i, +j)
Metric tensor of the sphere
Description
Provides the metric tensor of the sphere S^n
with radius 1.
g_sph()
returns a symbolic tensor field in generalized spherical
coordinates {\phi_1, \phi_2, ..., \phi_{n-1}}
.
d\Omega^2= d\phi_1^2 + \sum_{i=1}^{n-1} \prod_{m=1}^{i-1} sin(\phi_m)^2 d\phi_i^2
Usage
g_sph(n, coords = paste0("ph", 1:n))
Arguments
n |
The dimension of the metric tensor. |
coords |
A character vector of coordinate names. The length needs to match the tensor dimensions. |
Details
As usual, spherical coordinates are degenerate at \phi_l = 0
, so be
careful around those points.
Value
The covariant metric tensor as array imputed with coordinate names.
See Also
Wikipedia: Sphere
Other metric tensors:
g_eucl_cart()
,
g_mink_cart()
,
g_ss()
,
metric_field()
Examples
g_sph(3)
g_sph(3) %_% .(+i, +j)
Schwarzschild metric tensor
Description
Provides the metric tensor of the Einstein equation's Schwarzschild solution
in Schwarzschild coordinates where the Schwarzschild radius r_s
is set to 1.
ds^2 = - \left(1-\frac{r_s}{r}\right) dt^2 + \left(1-\frac{r_s}{r}\right)^{-1} dr^r + r^2 d\Omega^2
Usage
g_ss(n, coords = c("t", "r", paste0("ph", 1:(n - 2))))
Arguments
n |
The dimension of the metric tensor. |
coords |
A character vector of coordinate names. The length needs to match the tensor dimensions. |
Details
Note that Schwarzschild coordinates become singular at the Schwarzschild
radius (event horizon) r=r_s=1
and at r=0
.
Value
The covariant metric tensor as array imputed with coordinate names.
See Also
Wikipedia: Schwarzschild metric
Other metric tensors:
g_eucl_cart()
,
g_mink_cart()
,
g_sph()
,
metric_field()
Examples
g_ss(4)
g_ss(4) %_% .(+i, +j)
Kronecker product
Description
A Kronecker product is simply a tensor product whose underlying vector space basis is relabeled. In the present context this is realized by combining multiple index labels into one. The associated dimension to the new label is then simply the product of the dimensions associated to the old index labels respectively.
Usage
kron(x, ...)
Arguments
x |
|
... |
Any number of expressions (separated by a comma) of the form
|
Value
A modified tensor object.
See Also
Wikipedia: Kronecker Product
Other tensor operations:
Ops.tensor()
,
asym()
,
l()
,
r()
,
subst()
,
sym()
Examples
a <- array(1:8, dim = c(2, 2, 2))
a %_% .(i, j, k) |> kron(.(i, j) -> l)
Lower tensor indices
Description
l()
lowers specified tensor indices using a covariant metric tensor
provided in g
.
Note that the order of indices is not preserved due to performance reasons.
An error is thrown if the specified indices do not exist or are not in the
correct position.
Usage
l(x, ..., g = NULL)
Arguments
x |
|
... |
Any number of index expressions. The indices need to occur
in |
g |
A covariant metric tensor, a "metric_field" object. See |
Value
A modified tensor object.
See Also
Other tensor operations:
Ops.tensor()
,
asym()
,
kron()
,
r()
,
subst()
,
sym()
Create a metric tensor field
Description
Metric tensors are an essential ingredient of (Pseudo-) Riemannian
manifolds and define distance relations between points.
They are used to define geometric tensors such as e.g. the Ricci curvature
ricci()
, and a metric connection, i.e. a covariant derivative.
They are also essential for raising and lowering indices of tensor fields
correctly when using non-flat coordinates.
Usage
metric_field(metric, metric_inv, coords)
Arguments
metric |
A |
metric_inv |
A |
coords |
A character vector of |
Value
An object of class c("metric_field", "array")
that represents the
components of a metric tensor on a (Pseudo-) Riemannian manifold in a
certain coordinate system specified by coords
.
See Also
Wikipedia: Metric tensor
Other metric tensors:
g_eucl_cart()
,
g_mink_cart()
,
g_sph()
,
g_ss()
Raise tensor indices
Description
r()
raises specified tensor indices using a covariant metric tensor
provided in g
.
Note that the order of indices is not preserved due to performance reasons.
An error is thrown if the specified indices do not exist or are not in the
correct position.
Usage
r(x, ..., g = NULL)
Arguments
x |
|
... |
Any number of index expressions. The indices need to occur
in |
g |
A covariant metric tensor, a "metric_field" object. See |
Value
A modified tensor object.
See Also
Other tensor operations:
Ops.tensor()
,
asym()
,
kron()
,
l()
,
subst()
,
sym()
Ricci curvature tensor
Description
Provides the covariant Ricci curvature tensor R_{ij}=R^{s}_{i s j}
.
Usage
ricci(g)
Arguments
g |
A covariant metric tensor, a "metric_field" object. See |
Value
Returns the covariant Ricci curvature tensor R_{ij}
as rank 2 array()
.
See Also
Wikipedia: Ricci curvature tensor
Other geometric tensors:
christoffel()
,
ricci_sc()
,
riemann()
Examples
ricci(g_eucl_sph(3))
Ricci scalar
Description
Provides the Ricci scalar R
.
Usage
ricci_sc(g)
Arguments
g |
A covariant metric tensor, a "metric_field" object. See |
Value
Returns the Ricci scalar R
as single number/expression.
See Also
Wikipedia: Ricci scalar
Other geometric tensors:
christoffel()
,
ricci()
,
riemann()
Examples
ricci_sc(g_eucl_sph(3))
Riemann curvature tensor
Description
Provides the covariant Riemann curvature tensor R_{ijkl}
.
Usage
riemann(g)
Arguments
g |
A covariant metric tensor, a "metric_field" object. See |
Value
Returns the covariant Riemann curvature tensor R_{ijkl}
as rank 4 array()
.
See Also
Wikipedia: Riemann curvature tensor
Other geometric tensors:
christoffel()
,
ricci()
,
ricci_sc()
Examples
riemann(g_eucl_sph(3))
Simplify symbolic expressions
Description
Attempts to simplify expressions in an array or tensor.
Non-array objects are coerced to arrays with as.array()
.
Usage
simplify(x)
Arguments
x |
A character |
Details
Instead of using an explicit call to simplify()
you also have the option
to enable automatic simplification via option(ricci.auto_simplify = TRUE)
.
Note however that this comes at a significant performance cost.
This operation requires the Ryacas package.
Value
A character array()
or tensor()
of the same form, potentially
with simplified expressions.
Examples
simplify("x + y - x")
Substitute tensor labels
Description
Substitutes tensor labels with other labels. This is simply a renaming procedure. The operation might trigger implicit diagonal subsetting. An error is thrown if the specified indices do not exist.
Usage
subst(x, ...)
Arguments
x |
|
... |
Any number of expressions (separated by a comma) of the form
|
Value
A modified tensor object.
See Also
Other tensor operations:
Ops.tensor()
,
asym()
,
kron()
,
l()
,
r()
,
sym()
Symmetric tensor part
Description
Takes the symmetric tensor part of a tensor x
with respect to the
specified indices ...
.
An error is thrown if the specified indices do not exist.
Usage
sym(x, ...)
Arguments
x |
|
... |
Any number of index expressions. The indices need to occur
in |
Value
A modified tensor object.
See Also
Wikipedia: Ricci calculus - Symmetric and antisymmetric parts
Other tensor operations:
Ops.tensor()
,
asym()
,
kron()
,
l()
,
r()
,
subst()
Examples
a <- array(1:4, dim = c(2, 2))
a %_% .(i, j) |> sym(i, j)
Create a labeled array (tensor)
Description
Creates a labeled array (tensor) from an array. %_%
and tensor()
serve
the same purpose, but typically usage of %_%
is preferred due to
brevity.
tensor()
is exported to provide a standard-evaluation interface
as well which might be useful under some circumstances.
Usage
tensor(a, index_names, index_positions, call = NULL)
a %_% i
Arguments
a |
An array or any object that can be coerced to an array via
|
index_names |
A character vector of index names / labels. |
index_positions |
A character vector of index positions with two allowed
values "+" and "-", for "upper" and "lower" position respectively.
The length of |
call |
For internal use only. |
i |
An index slot label specification created with |
Value
A labeled tensor object of class "tensor"
, an array()
with attached dimension labels. Note that the index structure
of the resulting tensor does not necessarily have to match i
. In case
implicit calculations are already triggered (e.g. contractions)
the index structure reflects the resulting tensor.
Examples
a <- array(1:4, dim = c(2, 2))
a %_% .(i, j)