is.magichypercube {magic}R Documentation

magic hypercubes

Description

Returns TRUE if a hypercube is semimagic, magic, perfect

Usage

is.semimagichypercube(a, give.answers=FALSE, func=sum, boolean=FALSE, ...)
is.diagonally.correct(a, give.answers = FALSE, func=sum, boolean=FALSE, ...) 
is.magichypercube(a, give.answers = FALSE, func=sum, boolean=FALSE, ...) 
is.perfect(a, give.answers = FALSE, func=sum, boolean=FALSE)
is.latinhypercube(a, give.answers=FALSE)
is.alicehypercube(a,ndim,give.answers=FALSE, func=sum, boolean=FALSE)

Arguments

a

The hypercube (array) to be tested

give.answers

Boolean, with TRUE meaning to also return the sums

func

Function to be applied across each dimension

ndim

In is.alicehypercube(), dimensionality of subhypercube to take sums over. See the details section

boolean

Boolean, with TRUE meaning that the hypercube is deemed magic, semimagic, etc, if all applications of func evaluate to TRUE. If boolean is FALSE, the hypercube is magic etc if all applications of func are identical

...

Further arguments passed to func()

Details

(Although apparently non-standard, here a hypercube is defined to have dimension d and order n—and thus has n^d elements).

The terminology in this area is pretty confusing.

In is.magichypercube(), if argument give.answers=TRUE then a list is returned. The first element of this list is Boolean with TRUE if the array is a magic hypercube. The second element and third elements are answers fromis.semimagichypercube() and is.diagonally.correct() respectively.

In is.diagonally.correct(), if argument give.answers=TRUE, the function also returns an array of dimension c(q,rep(2,d)) (that is, q\times 2^d elements), where q is the length of func() applied to a long diagonal of a (if q=1, the first dimension is dropped). If q=1, then in dimension d having index 1 means func() is applied to elements of a with the d^{\rm th} dimension running over 1:n; index 2 means to run over n:1. If q>1, the index of the first dimension gives the index of func(), and subsequent dimensions have indices of 1 or 2 as above and are interpreted in the same way.

An example of a function for which these two are not identical is given below.

If func=f where f is a function returning a vector of length i, is.diagonally.correct() returns an array out of dimension c(i,rep(2,d)), with out[,i_1,i_2,...,i_d] being f(x) where x is the appropriate long diagonal. Thus the 2^d equalities out[,i_1,i_2,...,i_d]==out[,3-i_1,3-i_2,...,3-i_d] hold if and only if identical(f(x),f(rev(x))) is TRUE for each long diagonal (a condition met, for example, by sum() but not by the identity function or function(x){x[1]}).

Note

On this page, “subhypercube” is restricted to rectangularly-oriented subarrays; see the note at subhypercubes.

Not all subhypercubes of a magic hypercube are necessarily magic! (for example, consider a 5-dimensional magic hypercube a. The square b defined by a[1,1,1,,] might not be magic: the diagonals of b are not covered by the definition of a magic hypercube). Some subhypercubes of a magic hypercube are not even semimagic: see below for an example.

Even in three dimensions, being perfect is pretty bad. Consider a 5\times5\times 5 (ie three dimensional), cube. Say a=magiccube.2np1(2). Then the square defined by sapply(1:n,function(i){a[,i,6-i]}, simplify=TRUE), which is a subhypercube of a, is not even semimagic: the rowsums are incorrect (the colsums must sum correctly because a is magic). Note that the diagonals of this square are two of the “extreme point-to-point” diagonals of a.

A pandiagonal magic hypercube (or sometimes just a perfect hypercube) is semimagic and in addition the sums of all diagonals, including broken diagonals, are correct. This is one seriously bad-ass requirement. I reckon that is a total of \frac{1}{2}\left( 3^d-1\right)\cdot n^{d-1} correct summations. This is not coded up yet; I can't see how to do it in anything like a vectorized manner.

Author(s)

Robin K. S. Hankin

References

See Also

is.magic, allsubhypercubes, hendricks

Examples

library(abind)
is.semimagichypercube(magiccube.2np1(1))
is.semimagichypercube(magichypercube.4n(1,d=4))

is.perfect(magichypercube.4n(1,d=4))

# Now try an array with minmax(dim(a))==FALSE:
a <- abind(magiccube.2np1(1),magiccube.2np1(1),along=2)
is.semimagichypercube(a,g=TRUE)$rook.sums

# is.semimagichypercube() takes further arguments:
mymax <- function(x,UP){max(c(x,UP))}
not_mag  <- array(1:81,rep(3,4))
is.semimagichypercube(not_mag,func=mymax,UP=80)  # FALSE
is.semimagichypercube(not_mag,func=mymax,UP=81)  # TRUE


a2 <- magichypercube.4n(m=1,d=4)
is.diagonally.correct(a2)
is.diagonally.correct(a2,g=TRUE)$diag.sums

## To extract corner elements (note func(1:n) != func(n:1)):
is.diagonally.correct(a2,func=function(x){x[1]},g=TRUE)$diag.sums 


#Now for a subhypercube of a magic hypercube that is not semimagic:
is.magic(allsubhypercubes(magiccube.2np1(1))[[10]])

data(hendricks)
is.perfect(hendricks)


#note that Hendricks's magic cube also has many broken diagonals summing
#correctly:

a <- allsubhypercubes(hendricks)
ld <- function(a){length(dim(a))}

jj <- unlist(lapply(a,ld))
f <- function(i){is.perfect(a[[which(jj==2)[i]]])}
all(sapply(1:sum(jj==2),f))

#but this is NOT enough to ensure that it is pandiagonal (but I
#think hendricks is pandiagonal).


is.alicehypercube(magichypercube.4n(1,d=5),4,give.answers=TRUE)


[Package magic version 1.6-1 Index]