Title: | Non-Ordered Vectors |
---|---|
Description: | Functionality for manipulating values of associative maps. The package is a dependency for mvp-type packages that use the STL map class: it traps plausible idiom that is ill-defined (implementation-specific) and returns an informative error, rather than returning a possibly incorrect result. To cite the package in publications please use Hankin (2022) <doi:10.48550/ARXIV.2210.03856>. |
Authors: | Robin K. S. Hankin [aut, cre] |
Maintainer: | Robin K. S. Hankin <[email protected]> |
License: | GPL (>= 2) |
Version: | 0.9-8-4 |
Built: | 2025-01-12 06:07:07 UTC |
Source: | https://github.com/robinhankin/disordr |
Arithmetic operations including low-level helper functions
disord_inverse(a) disord_mod_disord(a,b) disord_mod_numeric(a,b) disord_negative(a) disord_plus_disord(a,b) disord_plus_numeric(a,b) disord_power_disord(a,b) disord_power_numeric(a,b) numeric_power_disord(a,b) disord_prod_disord(a,b) disord_prod_numeric(a,b) disord_arith_unary(e1,e2) disord_arith_disord(e1,e2) disord_arith_numeric(e1,e2) numeric_arith_disord(e1,e2)
disord_inverse(a) disord_mod_disord(a,b) disord_mod_numeric(a,b) disord_negative(a) disord_plus_disord(a,b) disord_plus_numeric(a,b) disord_power_disord(a,b) disord_power_numeric(a,b) numeric_power_disord(a,b) disord_prod_disord(a,b) disord_prod_numeric(a,b) disord_arith_unary(e1,e2) disord_arith_disord(e1,e2) disord_arith_numeric(e1,e2) numeric_arith_disord(e1,e2)
a , b
|
at least one is a disord object |
e1 , e2
|
Formal arguments for S4 dispatch |
Basic low-level arithmetic operations, intended to be called from S4 dispatch.
These functions return a disord
object or a regular vector as
appropriate. Consistency is required. The hash is set to be that of
the disord object if appropriate.
Return a disord object or logical
signature(e1="disord", e2="disord")
:
Dispatched to disord_arith_disord()
signature(e1="disord", e2="numeric")
:
Dispatched to disord_arith_numeric()
signature(e1="numeric", e2="disord")
:
Dispatched to numeric_arith_disord()
signature(e1="disord", e2="missing")
:
Dispatched to disord_arith_unary()
Robin K. S. Hankin
a <- rdis() a a + 2*a a > 5 a[a > 5] <- a[a > 5] + 100 a
a <- rdis() a a + 2*a a > 5 a[a > 5] <- a[a > 5] + 100 a
Concatenation simply does not make sense for disord
objects.
Returns an error.
I could not figure out how to stop idiom like “c(1,rdis())
” from
returning a result. Just don't use it, OK?
Robin K. S. Hankin
disord
objectsArithmetic comparison methods (greater than, etc) for disord
objects.
signature(e1="disord", e2="disord")
:
Dispatched to disord_compare_disord()
signature(e1="disord", e2="ANY")
:
Dispatched to disord_compare_any()
signature(e1="ANY", e2="disord")
:
Dispatched to any_compare_disord()
All the comparison methods use drop=TRUE
to avoid inconsistent
results when all the values are the same [that is, all TRUE
or
all FALSE
]. Comparing two disord
objects requires their
hash code to agree as per disordR discipline. Comparing a
disord
with a numeric returns a disord
object. In each
case, the hash code of the original object is preserved in the returned
value.
rdis() > 4 rdis() > 1000
rdis() > 4 rdis() > 1000
The disordR package is designed to make permitted operations transparent and to prevent forbidden operations from being executed.
Function consistent()
checks for matching hash codes of its
arguments and returns a Boolean. It is called by function
check_matching_hash()
which either returns TRUE
or
reports an informative error message if not.
consistent(x,y) x %~% y check_matching_hash(e1,e2,use=NULL)
consistent(x,y) x %~% y check_matching_hash(e1,e2,use=NULL)
x , y , e1 , e2
|
Objects of class |
use |
optional object designed to give a more intelligible error
message; typically |
Function consistent()
checks that its arguments have the same
hash code, and thus their elements can be paired up (e.g. added).
Idiom a %~% b
is equivalent to consistent(a,b)
.
The package generally checks for consistency with function
check_matching_hash()
which provides some helpful diagnostics
if consistent()
finds a hash mismatch.
Boolean or an error as appropriate
Robin K. S. Hankin
# rdis() + rdis() # this would make check_matching_hash() report an error, if executed
# rdis() + rdis() # this would make check_matching_hash() report an error, if executed
"disindex"
Experimental disindex
class provides a disordR
-compliant
method for indexing disord
objects. The idea is that
which(x)
, where x
is Boolean of class disord
,
should have meaning under disordR
discipline. Thus
which()
gives a disindex
object. This object can be
used as an index for other disord
objects. One application
would be the dismat
class of matrices, currently under
development.
Function values()
coerces its argument to an integer vector.
Objects can be created by calls of the form new("disindex", ...)
,
although which()
is more natural.
value
:Numeric vector
hash
:Object of class character
that
specifies the hash code
Robin K. S. Hankin
(x <- disord(c(1,2,1,2,2,7))) x==2 w <- which(x==2) w x[w] <- 100 x
(x <- disord(c(1,2,1,2,2,7))) x==2 w <- which(x==2) w x[w] <- 100 x
disord
objectsAllows arithmetic operators to be used for disord objects; the canonical application is coefficients of multivariate polynomials (as in the mvp package). The issue is that the storage order of disord objects is implementation-specific but the order (whatever it is) must be consistent between the list of keys and values in an associative array.
is.disord(x) hash(x) hashcal(x,ultra_strict=FALSE) disord(v,h,drop=TRUE) elements(x)
is.disord(x) hash(x) hashcal(x,ultra_strict=FALSE) disord(v,h,drop=TRUE) elements(x)
x |
Object of class |
v |
Vector of coefficients |
h |
Hash code |
drop |
Boolean, with default |
ultra_strict |
Boolean, with default |
A detailed vignette is provided that motivates the package. In applications such as the mvp or clifford packages, the user will not need to even think about the disordR package: it works in the background. The purpose of the package is to trap plausible idiom that is ill-defined (implementation-specific) and return an informative error, rather than returning a possibly incorrect result.
The package provides a single S4 class, disord
,
which has two slots, .Data
and hash
.
Function disord()
takes an R object such as a vector or list
and returns a disord
object, which is useful in the context of
the STL
map class.
Function hash()
returns the hash of an object (compare
hashcal()
which is used to actually calculate the hash code).
The package detects acceptable and forbidden operations using hash
codes: function consistent()
checks for its arguments having
the same hash code, and thus their elements can be paired up
(e.g. added). Idiomatically, a %~% b
is equivalent to
consistent(a,b)
.
Function elements()
takes a disord
and returns a regular
R object, typically a vector or a list.
Boolean, hash code, or object of class disord
as
appropriate.
Robin K. S. Hankin
(a <- rdis()) (b <- rdis()) a + 2*a + 2^a # fine # a + b # this would give an error if executed a[a<0.5] <- 0 # round down; replacement works as expected elements(a)
(a <- rdis()) (b <- rdis()) a + 2*a + 2^a # fine # a + b # this would give an error if executed a[a<0.5] <- 0 # round down; replacement works as expected elements(a)
"disord"
The disord
class provides basic arithmetic and extract/replace
methods for disord objects.
Objects can be created by calls of the form new("disord", ...)
,
although functions disord()
and (eventually) as.disord()
are more user-friendly.
.Data
:Object of class vector
that specifies the
elements
hash
:Object of class character
that
specifies the hash code
Robin K. S. Hankin
showClass("disord")
showClass("disord")
Coerce disord
objects to vector when this makes sense
drop(x) allsame(x)
drop(x) allsame(x)
x |
|
If one has a disord object all of whose elements are identical, one
usually wants to drop the disord attribute and coerce to a vector.
This can be done without breaking disordR
discipline. Function
disord()
takes a drop
argument, defaulting to
TRUE
, which drops the disord
class from its return value
if all the elements are the same.
Similarly, function drop()
takes a disord object and if all
elements are identical it returns the elements in the form of a
vector. Some extraction methods take a drop
argument, which
does the same thing if TRUE
. This is only useful for disord
objects created with disord(...,drop=FALSE)
The drop
functionality is conceptually similar to the
drop
argument of base R's array extraction, as in
a <- matrix(1:30,5,6) a[1,,drop=TRUE] a[1,,drop=FALSE]
Function allsame()
takes a vector and returns TRUE
if
all elements are identical.
Function drop()
returns either a vector or object of class
disord
as appropriate; allsame()
returns a Boolean.
Robin K. S. Hankin
disord(c(3,3,3,3,3)) # default is drop=TRUE disord(c(3,3,3,3,3),drop=FALSE) # retains disord class drop(disord(c(3,3,3,3),drop=FALSE)) ## In extraction, argument drop discards disorderliness when possible: a <- rdis() a a[] <- 6 # a becomes a vector a
disord(c(3,3,3,3,3)) # default is drop=TRUE disord(c(3,3,3,3,3),drop=FALSE) # retains disord class drop(disord(c(3,3,3,3),drop=FALSE)) ## In extraction, argument drop discards disorderliness when possible: a <- rdis() a a[] <- 6 # a becomes a vector a
"disord"
The disord
class provides basic arithmetic and extract/replace
methods for disord objects.
Class index is taken from the excellent Matrix package
and is a setClassUnion()
of classes numeric
,
logical
, and character
.
signature(x = "disord", i = "ANY", j = "ANY")
: ...
signature(x = "disord", i = "index", j = "index")
: ...
signature(x = "disord", i = "index", j = "missing")
: ...
signature(x = "disord", i = "missing", j = "index")
: ...
signature(x = "disord", i = "missing", j = "missing")
: ...
signature(x = "disord", i = "matrix", j = "missing")
: ...
signature(x = "disord", i = "index", j = "index")
: ...
signature(x = "disord", i = "index", j = "missing")
: ...
signature(x = "disord", i = "missing", j = "index")
: ...
signature(x = "disord", i = "matrix", j = "missing")
: ...
signature(x = "disord", i = "missing", j = "missing")
: ...
signature(x = "disord", i = "index")
: ...
signature(x = "disord", i = "index",value="ANY")
: ...
signature(x="disord",i="disindex",j="missing",drop="ANY")
: ...
signature(x="disord",i="disindex",j="ANY",drop="ANY")
: ...
signature(x="ANY",i="disindex",j="ANY",drop="ANY")
: ...
signature(x="disord",i="disindex",j="missing",value="ANY")
: ...
signature(x="disord",i="disindex",j="ANY",value="ANY")
: ...
signature(x="disord",i="disindex",j="missing",drop="ANY")
: ...
signature("disord",i="disindex")
: ...
signature("ANY",i="disindex")
: ...
signature(x="disord",i="disindex",j="missing",value="ANY")
...
signature(x="ANY",i="disindex",j="ANY",value="ANY")
...
The extraction method takes a drop
argument which if
TRUE
, returns the drop()
of its value. Extraction, as
in x[i]
, is rarely useful. It is only defined if one extracts
either all, or none, of the elements: anything else is undefined.
Note that the hash code is unchanged if all elements are extracted
(because the order might have changed) but unchanged if none are
(because there is only one way to extract no elements).
Missing arguments for extraction and replacement are slightly
idiosyncratic. Extraction idiom such as x[]
returns an object
identical to x
except for the hash code, which is changed. I
can't quite see a sensible use-case for this, but the method allows
one to define an object y <- x[]
for which x
and
y
are incompatible. Replacement idiom x[] <- v
always
coerces to a vector.
Double square extraction, as in x[[i]]
and x[[i]] <-
value
, is via (experimental) disindex
functionality.
Package versions prior to disordR_0.0-9-6
allowed idiom such as
a <- disord(1:9) a[a<3] + a[a>7]
but this is now disallowed. The issue is discussed in
inst/note_on_extraction.Rmd
.
Robin K. S. Hankin
a <- disord(sample(9)) a a + 6*a^2 a[a>5] # "give me all elements of a that exceed 5" a[] # a disord object, same elements as 'a', but with a different hash a[a<5] <- a[a<5] + 100 # "replace all elements of 'a' less than 5 with their value plus 100" a ## Following expressions would return an error if executed: if(FALSE){ a[1] a[1] <- 44 a[1:2] <- a[3:4] } b <- disord(sample(9)) ## Following expressions would also return an error if executed: if(FALSE){ a+b # (not really an example of extraction) a[b>5] a[b>5] <- 100 a[b>5] <- a[b>5] + 44 }
a <- disord(sample(9)) a a + 6*a^2 a[a>5] # "give me all elements of a that exceed 5" a[] # a disord object, same elements as 'a', but with a different hash a[a<5] <- a[a<5] + 100 # "replace all elements of 'a' less than 5 with their value plus 100" a ## Following expressions would return an error if executed: if(FALSE){ a[1] a[1] <- 44 a[1:2] <- a[3:4] } b <- disord(sample(9)) ## Following expressions would also return an error if executed: if(FALSE){ a+b # (not really an example of extraction) a[b>5] a[b>5] <- 100 a[b>5] <- a[b>5] + 44 }
Logical operations including low-level helper functions
disord_logical_negate(x) disord_logic_disord(e1,e2) disord_logic_any(e1,e2) any_logic_disord(e1,e2)
disord_logical_negate(x) disord_logic_disord(e1,e2) disord_logic_any(e1,e2) any_logic_disord(e1,e2)
e1 , e2 , x
|
Formal arguments for S4 dispatch: logical
|
Basic low-level logical operations, intended to be called from S4 dispatch.
These functions return a logical disord
object. appropriate.
Consistency is required. The hash is set to be that of the disord
object if appropriate.
Return a disord object or logical
signature(e1="disord", e2="disord")
:
Dispatched to disord_logic_disord()
signature(e1="disord", e2="ANY")
:
Dispatched to disord_logic_any()
signature(e1="ANY", e2="disord")
:
Dispatched to any_logic_disord()
Robin K. S. Hankin
a <- disord(1:7) l <- a>3 sum(l) any(l) all(l | !l)
a <- disord(1:7) l <- a>3 sum(l) any(l) all(l | !l)
This page documents various functions that work for disords, and I will
add to these from time to time as I add new functions that make sense
for disord objects (or identify functions that break disord discipline).
Functions like sin()
and abs()
work as expected: they take
and return disord
objects with the same hash as x
(which
means that idiom like x + sin(x)
is accepted). However, there
are a few functions that are a little more involved:
rev()
reverses its argument and returns a disord
object with a reversed hash, which ensures that rev(rev(x))==x
(and the two are consistent).
sort()
returns a vector of sorted elements (not a
disord
)
length()
returns the length of the data component of the
object
sapply(X,f)
returns a disord object which is the result of
applying f()
to each element of X
.
match(x,table)
should behave as expected but note that if
table
is a disord
, the result is not defined (because it
is not known where the elements of x
occur in table
).
Nevertheless x %in% table
is defined and returns a
disord
object.
lapply(x,f)
returns
disord(lapply(elements(x),f,...),h=hash(x))
. Note that double
square bracket extraction, as in x[[i]]
, is disallowed (see
extract.Rd
).
which()
returns a disind
object when given a
Boolean disord
unlist()
takes a disord
list, flattens it and
returns a disord
vector. It requires the recursive
flag
of base::unlist()
to be TRUE
, which it is by default,
interpreting this to mean “kill all the structure in any
sublists”. If the list comprises only length-one vectors, the
returned value retains the same hash as the argument; if not, a new
hash is generated.
diff()
is undefined for disord
objects.
rbind()
and cbind()
are undefined for disord
objects as they break disord discipline. Function binder()
returns a generic, and hopefully informative, error message [the
package defines methods for rbind2()
and cbind2()
]
jitter()
takes a disord
object, jitters the
elements, and returns a disord
object with the correct hash
code.
x |
Object of class |
Returns a disord
Some functionality is not yet implemented. Factors, lists, and named
vectors do not behave entirely consistently in the package;
paste()
gives inconsistent results when called with disords.
Also, for()
loops are incompatible with disord discipline, as
they impose an ordering (for()
accesses the .Data
slot of
its argument, which is a regular R vector). Thus:
> (a <- disord(1:3)) A disord object with hash 555f6bea49e58a2c2541060a21c2d4f9078c3086 and elements [1] 1 2 3 (in some order) > for(i in a){print(i)} [1] 1 [1] 2 [1] 3 >
Above, we see that for()
uses the ordering of the .Data
slot of S4 object a
, even though elements()
has
not been explicitly called.
Robin K. S. Hankin
a <- disord(c(a=1,b=2,c=7)) a names(a) length(a) sqrt(a) # powers() and vars() in the mvp package return lists; see the vignette # for more discussion. l <- disord(list(3,6:9,1:10)) sapply(l,length) unlist(l) ## Quick illustration of rev(): revstring <- function(s){paste(rev(unlist(strsplit(s, NULL))),collapse="")} x <- rdis() revstring(hash(x)) == hash(rev(x))
a <- disord(c(a=1,b=2,c=7)) a names(a) length(a) sqrt(a) # powers() and vars() in the mvp package return lists; see the vignette # for more discussion. l <- disord(list(3,6:9,1:10)) sapply(l,length) unlist(l) ## Quick illustration of rev(): revstring <- function(s){paste(rev(unlist(strsplit(s, NULL))),collapse="")} x <- rdis() revstring(hash(x)) == hash(rev(x))
Returns a random disord object
rdis(n=9)
rdis(n=9)
n |
Set to sample from, as interpreted by |
A simple disord
object, intended as a quick
“get you going” example
A disord
object.
Robin K. S. Hankin
rdis() rdis(99) rdis(letters)
rdis() rdis(99) rdis(letters)
Show methods for disords
## S4 method for signature 'disord' show(x) disord_show(x)
## S4 method for signature 'disord' show(x) disord_show(x)
x |
Object of class disord |
The print method simply prints the object's hash and its elements,
together with a reminder that the elements are listed in an
implementation-specific order. Function disord_show()
is a
helper function, not really intended for the end-user.
Robin K. S. Hankin
print(rdis())
print(rdis())
A summary method for disord objects, and a print method for summaries.
## S4 method for signature 'disord' summary(object, ...) ## S4 method for signature 'disindex' summary(object, ...) ## S3 method for class 'summary.disord' print(x, ...)
## S4 method for signature 'disord' summary(object, ...) ## S4 method for signature 'disindex' summary(object, ...) ## S3 method for class 'summary.disord' print(x, ...)
object , x
|
Object of class |
... |
Further arguments, currently ignored |
A summary.disord
object is summary of a disord
object
x
: a list with first element being the hash(x)
and the
second being summary(elements(x))
. The print method is just a
wrapper for this.
Robin K. S. Hankin
summary(rdis(1000))
summary(rdis(1000))