dovs
function (K) 
{
    if (is.zero(K) || is.scalar(K)) {
        return(0)
    }
    else {
        return(max(index(K)))
    }
}

To cite the stokes package in publications, please use Hankin (2022); this function monograph discusses dovs(). Function dovs() returns the dimensionality of the underlying vector space of a kk-form. Recall that a kk-form is an alternating linear map from VkV^k to \mathbb{R}, where V=nV=\mathbb{R}^n(Spivak 1965). Function dovs() returns nn [compare arity(), which returns kk]. As seen above, the function is very simple, essentially being max(index(K)), but its use is not entirely straightforward in the context of stokes idiom. Consider the following:

set.seed(0)
a <- rform(n=4,k=2)
a
## An alternating linear map from V^2 to R with V=R^4:
##          val
##  2 4  =    9
##  1 4  =    8
##  2 3  =    1
##  1 3  =   -3
##  3 4  =   -2
##  1 2  =    2

Now object a is notionally a map from (4)2\left(\mathbb{R}^4\right)^2 to \mathbb{R}:

f <- as.function(a)
(M <- matrix(1:8,4,2))
##      [,1] [,2]
## [1,]    1    5
## [2,]    2    6
## [3,]    3    7
## [4,]    4    8
f(M)
## [1] -148

However, a can equally be considered to be a map from (5)2\left(\mathbb{R}^5\right)^2 to \mathbb{R}:

f <- as.function(a)
(M <- matrix(c(1,2,3,4,1454,5,6,7,8,-9564),ncol=2))  # row 5 large numbers
##      [,1]  [,2]
## [1,]    1     5
## [2,]    2     6
## [3,]    3     7
## [4,]    4     8
## [5,] 1454 -9564
f(M)
## [1] -148

If we view aa [or indeed f()] in this way, that is a:(5)2a\colon\left(\mathbb{R}^5\right)^2\longrightarrow\mathbb{R}, we observe that row 5 is ignored: e5=(0,0,0,0,1)Te_5=\left(0,0,0,0,1\right)^T maps to zero in the sense that f(e5,𝐯)=f(𝐯,e5)=0f(e_5,\mathbf{v})=f(\mathbf{v},e_5)=0, for any 𝐯5\mathbf{v}\in\mathbb{R}^5.

(M <- cbind(c(0,0,0,0,1),runif(5)))
##      [,1]      [,2]
## [1,]    0 0.3800352
## [2,]    0 0.7774452
## [3,]    0 0.9347052
## [4,]    0 0.2121425
## [5,]    1 0.6516738
f(M)
## [1] 0

(above we see that rows 1-4 of M are ignored because of the zero in column 1; row 5 is ignored because the index of a does not include the number 5). Because a is alternating, we could have put e5e_5 in the second column with the same result. Alternatively we see that the kk-form a, evaluated with e5e_5 as one of its arguments, returns zero because the index matrix of a does not include the number 5. Most of the time, this kind of consideration does not matter. However, consider this:

dx
## An alternating linear map from V^1 to R with V=R^1:
##        val
##  1  =    1

Now, we know that dx is supposed to be a map from (3)1\left(\mathbb{R}^3\right)^1 to \mathbb{R}; but:

dovs(dx)
## [1] 1

So according to stokes, dx:(1)1\operatorname{dx}\colon\left(\mathbb{R}^1\right)^1\longrightarrow\mathbb{R}. This does not really matter numerically, until we consider the Hodge star operator. We know that dx=dydz\star\operatorname{dx}=\operatorname{dy}\wedge\operatorname{dz}, but

hodge(dx)
## [1] 1

Above we see the package giving, correctly, that the Hodge star of dx\operatorname{dx} is the zero-dimensional volume element (otherwise known as “1”). To get the answer appropriate if dx\operatorname{dx} is considered as a map from (3)1\left(\mathbb{R}^3\right)^1 to \mathbb{R} [that is, dx:(3)1\operatorname{dx}\colon\left(\mathbb{R}^3\right)^1\longrightarrow\mathbb{R}], we need to specify dovs explicitly:

hodge(dx,3)
## An alternating linear map from V^2 to R with V=R^3:
##          val
##  2 3  =    1

Actually this looks a lot better with a more appropriate print method:

options(kform_symbolic_print="dx")
hodge(dx,3)
## An alternating linear map from V^2 to R with V=R^3:
##  + dy^dz

keep() and discard()

Given a kk-form ω\omega, we have ω(v1,,vk)\omega(v_1,\ldots,v_k)\in\mathbb{R}, where v1,,vknv_1,\ldots,v_k\in\mathbb{R}^n. Now, discarding dimension ii is equivalent to asserting (or guaranteeing) that eivj=0e_i\cdot v_j=0 for j=1,,kj=1,\ldots,k. Alternatively, we may say that ω(v1,,vk)\omega(v_1,\ldots,v_k) is independent of eivje_i\cdot v_j for j=1,,kj=1,\ldots,k. If this is the case, we may ignore any row in which an ii appears.

For kk-forms, discarding (and its dual, keeping) is carried out in the package by functions keep() and discard(). In these functions, dovs() is used internally, but its role is somewhat opaque. Consider keep():

keep
## function (K, yes) 
## {
##     jj <- rep(0L, dovs(K))
##     jj[yes] <- 1
##     stretch(K, jj)
## }

Above we see that dovs() is used to create vector jj, which specifies which dimensions to keep and which to discard. This is so that argument yes can use standard square bracket replacement idiom to overwrite jj. Kept dimensions are then stretched (with function stretch()) by a factor of 1 and discarded dimensions are stretched by a factor of 0.

Now, given the current package setup, there is no point in specifying whether a dimension greater than dovs(x) is to be kept or not—such things are already discarded. As a concrete example:

(x <- kform_general(3, 2, seq_len(choose(3, 2))))
## An alternating linear map from V^2 to R with V=R^3:
##          val
##  2 3  =    3
##  1 3  =    2
##  1 2  =    1
dovs(x)
## [1] 3

Above we see a kform x with dovs of 5. Recall that object x is a map from V2V^2 to \mathbb{R}, where vector space V=5V=\mathbb{R}^5. So, for example, x((a1a2a3),(b1b2b3))=a1b2+2a1b3+3a2b3x\left(\left(\begin{array}{c}a_1\\a_2\\a_3\end{array}\right),\left(\begin{array}{c}b_1\\b_2\\b_3\end{array}\right)\right)=a_1b_2+2a_1b_3+3a_2b_3. Now, for example, I might only care about the first and third row of each argument [that would be the xx- and zz- components of a 3-vector]. If I wished to simplify x I would only keep the first and third:

keep(x, c(1,3))
## An alternating linear map from V^2 to R with V=R^3:
##          val
##  1 3  =    2

Observe that there is no point asking whether to keep “the fourth component”, for that has already been discarded by the class.

References

Hankin, R. K. S. 2022. “Stokes’s Theorem in R.” arXiv. https://doi.org/10.48550/ARXIV.2210.17008.
Spivak, M. 1965. Calculus on Manifolds. Addison-Wesley.