`mvp`

package as a motivation for the definition of `disord`

objects(This document motivates the concept of “disordered vector” using coefficients of multivariate polynomials as represented by associative maps such as the `STL`

map class as used by the `mvp`

package. It then presents an illustrative R session in which the `disordR`

package is used abstractly, without reference to any particular application, and then shows how the `disordR`

package is used in the `mvp`

package).

Accessing elements of an `mvp`

object is problematic because the order of the terms of an `mvp`

object is not well-defined. This is because the `map`

class of the `STL`

does not specify an order for the key-value pairs (and indeed the actual order in which they are stored may be implementation dependent). The situation is applicable to the `hyper2`

, `spray`

, `clifford`

and `freealg`

packages which use the `STL`

in a similar way.

A `disord`

object is a vector of coefficients of a `mvp`

object. But it is not a conventional vector; in a conventional vector, we can identify the first element unambiguously, and the second, and so on. An `mvp`

is a map from terms to coefficients, and a map has no intrinsic ordering: the maps

`x -> 1, y -> 3, xy^3 -> 4`

and

`xy^3 -> 4, x -> 1, y -> 3`

are the same map and correspond to the same multinomial (symbolically, \(x+3y+4xy^3=4xy^3+x+3y\)). Thus the coefficients of the multinomial might be `c(1,3,4)`

or `c(4,1,3)`

, or indeed any ordering. But note that any particular ordering imposes an ordering on the terms. If we choose `c(1,3,4)`

then the terms are `x`

, `y`

, `xy^3`

, and if we choose `c(4,1,3)`

the terms are `xy^3`

,`x`

, `y`

.

The `disord`

class of the `disordR`

package is specficially designed for this situation. This class of object has a slot for the coefficients in the form of a numeric R vector, but also another slot which uses hash codes to prevent users from misusing the ordering of the numeric vector.

For example, a multinomial `x+2y+3z`

might have coefficients `c(1,2,3)`

or `c(3,1,2)`

. Package idiom to extract the coefficients of a multivariate polynomial `a`

is `coeffs(a)`

; but this cannot return a standard numeric vector because a numeric vector has elements in a particular order, and the coefficients of a multivariate polynomial are stored in an implementation-specific (and thus unknown) order.

Suppose we have two multivariate polynomials, `a`

as defined as above with `a=x+2y+3z`

and `b=x+3y+4z`

. Even though the product `ab`

is well-defined algebraically, and `coeffs(a+b)`

will return a well-defined `disord`

object, idiom such as `coeffs(a) + coeffs(b)`

is not defined because there is no guarantee that the coefficents of the two multivariate polynomials are stored in the same order. We might have `c(1,2,3)+c(1,3,4)=c(2,5,7)`

or `c(1,2,3)+c(1,4,3)=c(2,6,6)`

, with neither being more “correct” than the other. In the package, this ambiguity is rendered nonproblematic: `coeffs(a) + coeffs(b)`

will return an error. In the same way `coeffs(a) + 1:3`

is not defined and will return an error. Further, idiom such as `coeffs(a) <- 1:3`

and `coeffs(a) <- coeffs(b)`

are not defined and will return an error. However, note that

```
coeffs(a) + coeffs(a)
coeffs(a) + coeffs(a)^2
coeffs(a) <- coeffs(a)^2
coeffs(a) <- coeffs(a)^2 + 7
```

are perfectly well defined, with package idiom behaving as expected.

Idiom such as `disord(a) <- disord(a)^2`

is OK: one does not need to know the order of the coefficients on either side, so long as the order is the same on both sides. The idiomatic English equivalent would be: “the coefficient of each term of `a`

becomes its square”; note that this operation is insensitive to the order of coefficients. The whole shebang is intended to make idiom such as `coeffs(a) <- coeffs(a)%%2`

possible, so we can manipulate polynomials over finite rings, here \(Z/2Z\).

The replacement methods are defined so that an expression like `coeffs(a)[coeffs(a) < 5] <- 0`

works as expected; the English idiom would be “Replace any coefficient less than 5 with 0”.

To fix ideas, consider a fixed small mvp object, for example `a <- rmvp(8)`

. Extraction presents issues; consider `coeffs(a)<5`

. This object has Boolean elements but has the same ordering ambiguity as `coeffs(a)`

. One might expect that we could use this to extract elements of `coeffs(a)`

specifically elements less than 5. However, `coeffs(a)[coeffs(a)<5]`

in isolation is meaningless: what can be done with such an object? However, it makes sense on the left hand side of an assignment, as long as the right hand side is a length-one vector. Idiom such as

```
coeffs(a)[coeffs(a)<5] <- 4 + coeffs(a)[coeffs(a)<5]
coeffs(a) <- pmax(a,3)
```

is algebraically meaningful. Idiomatically: “Add 4 to any element less than 5”; “coefficients become the parallel maximum of themselves and 3” respectively [but note that package idiom is `pmaxdis()`

here]. Further note that `coeffs(a) <- rev(coeffs(a))`

is disallowed.

So the output of `coeffs(x)`

is defined only up to an unknown rearrangement. The same considerations apply to the output of `vars()`

, which returns a list of character vectors in an undefined order, and the output of `powers()`

, which returns a numeric list whose elements are in an undefined order. However, even though the order of these three objects is undefined individually, their ordering is jointly consistent in the sense that the first element of `coeffs(x)`

corresponds to the first element of `vars(x)`

and the first element of `powers(x)`

. The identity of this element is not defined—but whatever it is, the first element of all three accessor methods refers to it.

Note also that a single term (something like `4a3*b*c^6`

) has the same issue: the variables are not stored in a well-defined order. This does not matter because the algebraic value of the term does not depend on the order in which the variables appear and this term would be equivalent to `4bc^6*a^3`

.

`disordR`

packageWe will use the `disordR`

package to show how the idiom works.

`library("disordR")`

`## Loading required package: digest`

```
a <- rdis()
a
```

```
## A disord object with hash 906e1eaeea6c6cda4f16803547f8b3bf67bac487 and elements
## [1] 0.4148606 0.9568112 0.9957079 0.3180338 0.4673644 0.1462054 0.7697941
## [8] 0.2737005 0.1653056
## (in some order)
```

Object `a`

is a `disord`

object but it behaves similarly to a regular numeric vector in many ways:

`a^2`

```
## A disord object with hash 906e1eaeea6c6cda4f16803547f8b3bf67bac487 and elements
## [1] 0.17210934 0.91548772 0.99143419 0.10114549 0.21842944 0.02137603 0.59258302
## [8] 0.07491195 0.02732594
## (in some order)
```

`max(a)`

`## [1] 0.9957079`

`sort(a)`

```
## [1] 0.1462054 0.1653056 0.2737005 0.3180338 0.4148606 0.4673644 0.7697941
## [8] 0.9568112 0.9957079
```

However, if we try to combine object `a`

with another object with different hash, we get errors:

```
b <- rdis()
b
```

```
## A disord object with hash a3a1b725411eb0118ba56914825d50836ccaacbd and elements
## [1] 0.52408923 0.73192164 0.81462980 0.02245134 0.43962042 0.06871523 0.42596683
## [8] 0.93813506 0.59498170
## (in some order)
```

`a+b`

`## Error in a + b: consistent(e1, e2) is not TRUE`

The error is given because objects `a`

and `b`

are stored in a non-compatible order. Many extract and replace methods are implemented:

```
a[a<0.5] <- 0 # round down
a
```

```
## A disord object with hash 906e1eaeea6c6cda4f16803547f8b3bf67bac487 and elements
## [1] 0.0000000 0.9568112 0.9957079 0.0000000 0.0000000 0.0000000 0.7697941
## [8] 0.0000000 0.0000000
## (in some order)
```

```
b[b>0.6] <- b[b>0.6] + 3 # add 3 to every element greater than 0.6
b
```

```
## A disord object with hash a3a1b725411eb0118ba56914825d50836ccaacbd and elements
## [1] 0.52408923 3.73192164 3.81462980 0.02245134 0.43962042 0.06871523 0.42596683
## [8] 3.93813506 0.59498170
## (in some order)
```

Usual semantics follow, provided one is careful to maintain the hash code:

```
a <- disord(1:10)
a
```

```
## A disord object with hash 65e11d78de79b7f584068ad856749e3748cb837c and elements
## [1] 1 2 3 4 5 6 7 8 9 10
## (in some order)
```

```
x <- a + a^2
x
```

```
## A disord object with hash 65e11d78de79b7f584068ad856749e3748cb837c and elements
## [1] 2 6 12 20 30 42 56 72 90 110
## (in some order)
```

```
a[a<5] <- x[a<5]
a
```

```
## A disord object with hash 65e11d78de79b7f584068ad856749e3748cb837c and elements
## [1] 2 6 12 20 5 6 7 8 9 10
## (in some order)
```

`mvp`

packageThe `mvp`

package implements multivariate polynomials using the `STL`

map class. Following commands only work as intended here with `mvp >= 1.0-12`

(which is not on CRAN, pending `disordR`

).

[NB: the following lines need `mvp`

version `1.0-12`

or above. In particular, they will not execute with the CRAN version of the `mvp`

package (version `1.0-8`

), which does not use the `disordR`

package. So, as a temporary measure, the R code below is just text, `knitr`

will not execute them. I will change these lines back when I upload the `mvp`

package, but of course I can’t do that until the `disordR`

version `0.0-6`

is uploaded].

```
{r}
library("mvp")
a <- rmvp()
b <- rmvp()
a
b
```

We can extract the coefficients of these polynomials using the `coeffs()`

function:

```
{r}
coeffs(a)
coeffs(b)
```

observe that the coefficients are returned as a `disord`

object. We may manipulate the coefficients of a polynomial in many ways. We may do the following things:

```
{r}
coeffs(a)[coeffs(a) < 4] <- 0 # set any coefficient < 4 to zero
a
coeffs(b) <- coeffs(b)%%2 # consider coefficients modulo 2
b
```

However, many operations which have reasonable idiom are in fact meaningless and are implicitly prohibited. For example:

```
{r}
x <- rmvp() # set up new mvp objects x and y
y <- rmvp()
x
y
coeffs(x)
coeffs(y)
```

Then the following should all produce errors:

```
{r,error=TRUE}
coeffs(x) + coeffs(y) # order not specified
coeffs(x) <- coeffs(y) # order not specified
coeffs(x) <- 1:2 # replacement value not length 1
coeffs(x)[coeffs(x) < 3] <- coeffs(x)[coeffs(y) < 3]
```

`vars()`

and `powers()`

return `disord`

objectsThe `disord()`

function takes a list argument, and this is useful for working with `mvp`

objects:

```
{r}
(a <- rmvp())
vars(a)
powers(a)
coeffs(a)
```

Note that the hash is identical, generated from the polynomial itself (not just the relevant element of the three-element list that is an `mvp`

object). This allows us to do some rather interesting things:

```
{r}
double <- function(x){2*x}
a <- rmvp()
pa <- powers(a)
va <- vars(a)
ca <- coeffs(a)
pa[ca<4] <- sapply(pa,double)[ca<4]
mvp(va,pa,ca)
```

Above, `a`

was a multivariate polynomial and we doubled the powers of all variables in terms with coefficients less than 4. Or even:

```
{r}
a <- rmvp()
pa <- powers(a)
va <- vars(a)
ca <- coeffs(a)
va[sapply(pa,length) > 4] <- sapply(va,toupper)[sapply(pa,length) > 4]
mvp(va,pa,ca)
```

Above, we took `a`

and replaced the variables in every term with more than four variables with their uppercase equivalents. The `mvp`

package does not include `powers<-()`

or `vars<-()`

functions, but these would have made the idiom nicer (I will get round to writing them when the `disordR`

package is more stable).