2

I need to find all possible 5x5 matrix of integers 1-5 unique to each row and column (imagine a Sudoku) in R.

Is there any efficient way of doing this without creating all 120C5 matrices and then finding the fitting ones?

Thank you!

  • `sapply(1:5, function(i) (1:5 - i) %% 5 + 1)`. (This was an easy one, but for future questions, please show some effort on your part. This isn't a free-code-service. If this is homework, I hope I get an "A".) – r2evans Nov 08 '18 at 23:02
  • Hi sorry I need to find all possible combinations not just one - sorry for not making that clear. – Maximilian Niroomand Nov 08 '18 at 23:05
  • 1
    It's an interesting problem, and one I may put on the back burner for a while. However, it's too much for quick Q/As on SO, so you may not get a response. Or you may, who knows. But this will be more effort than most questions (that I see) typically require. Good luck. – r2evans Nov 08 '18 at 23:09
  • 1
    Such matrices are called latin squares. See https://stackoverflow.com/a/49203589/1320535 for how to generate random ones. Generating all of them is indeed not straightforward, see https://en.wikipedia.org/wiki/Latin_square#Algorithms. – Julius Vainora Nov 08 '18 at 23:18
  • 1
    I agree with @r2evans. This is a computationally interesting question. I strongly recommend that you yourself give this a try first. You can find resources on the net, and even [here on SO](https://stackoverflow.com/questions/6924216/how-to-generate-sudoku-boards-with-unique-solutions). Show a code attempt at solving the problem, and I can guarantee that you will get a much better response (and you will learn a lot more as well). At the moment this reads too much like ["gimme teh codez"](https://meta.stackexchange.com/questions/108551/what-site-to-use-if-you-have-a-gimme-teh-codez-question). – Maurits Evers Nov 08 '18 at 23:19

1 Answers1

3

As I said in my comment above, matrices of this type are called Latin squares.

For a start, we already know that there are 56 so-called reduced Latin squares and 161280 all Latin squares of size 5. The reduced Latin squares are such that both the first column and the first row are just 1, 2, 3, 4, 5 (in this order). Given those reduced Latin squares, one may easily (as long as the size is not greater than 5) generate all Latin squares: permute all the rows except the first one and permute all the columns. Hence, as expected, 161280=5!*4!*56.

By restricting the first row and column one could generate 4!*3!*2!=288 matrices and check which 56 are Latin squares. However, I'm going to skip that and take their list from here.

First we read and rearrange the data

reduced <- read.table("http://users.cecs.anu.edu.au/~bdm/data/reduced5.txt", head = FALSE, colClasses = "character")
reduced <- lapply(1:nrow(reduced), function(r) matrix(as.numeric(unlist(strsplit(unlist(reduced[r, ]), ""))) + 1, 5))
length(reduced)
# [1] 56

Now let's generate all 5! and 4! permutations of 1, 2, 3, 4, 5 and 1, 2, 3, 4, respectively.

library(combinat)
perms5 <- permn(1:5)
perms4 <- permn(1:4)

Lastly, we go over all the reduced Latin squares and permute them in all possible ways

allLS <- sapply(reduced, function(m) {
  LS <- vector("list", gamma(6) * gamma(5))
  for(i in 1:gamma(5))
    for(j in 1:gamma(6))
      LS[[(i - 1) * gamma(6) + j]] <- m[perms4[[i]] + 1, perms5[[j]]]
  LS
})

Takes just a couple of seconds and we have the result

length(allLS)
# [1] 161280

It is easy to verify that they all are different

table(table(sapply(allLS, paste0, collapse = "")))
#      1 
# 161280 

and you could also check if they all are Latin squares.

Julius Vainora
  • 47,421
  • 9
  • 90
  • 102
  • Very impressive, Julius! Now I can turn off my back-burner. (I really like `list()[rep(...)]` instead of `replicate(n,NULL,simplify=F)`, too ... much faster.) – r2evans Nov 09 '18 at 00:29
  • 1
    @r2evans, thanks! And now your comment reminded me of something even nicer and faster: `vector("list", n)`. Around another 5 times faster than `list()[rep(1, n)]`. – Julius Vainora Nov 09 '18 at 00:33
  • I had already benchmarked the first two (2 OOM faster), this third is another OOM faster still (where `n <- gamma(6)*gamma(5)`). I don't know why I keep forgetting the stable `vector` function ... – r2evans Nov 09 '18 at 00:37