【问题标题】:How can I structure for and if loops to construct Latin squares?如何构造 for 和 if 循环来构造拉丁方格?
【发布时间】:2020-03-31 00:09:08
【问题描述】:

我的目标是在给定大小 n 的情况下构造每个唯一的 Latin Square。 R 命令 rlatin(n) 使用马尔可夫链构造一个大小为 n x n 的随机拉丁方。但是,此命令不仅会构建其大小的所有拉丁方格。

下面是我的代码:

library(magic)

L <- function(n){
  size <- factorial(n) * factorial(n-1)
  l <- list()
  l[[1]] <- rlatin(n)
  for(k in 2:size){
    new <- rlatin(n)
    for(j in 1:(k-1)){
      if(new == l[[j]]){
        new <- rlatin(n)
      }
    }
    l[[k]] <- new
  }
  l
} 

这不能正常工作,我不明白为什么。有人可以阐明我的错误吗?另外,一旦所有的拉丁方格都构建好了,我有没有办法组织它们,以便在拉丁方格中有一些清晰的内容?

【问题讨论】:

  • 首先,这个问题需要更清楚地了解拉丁方的数学 - 为什么你会尝试找到“每一个独特的拉丁方”,当已知即使对于一个小的 n = 10,你会大约有 9,982,437,658,213,039,871,725,064,756,920,320,000 个独特的解决方案,如果将其限制为简化形式,您仍然会有大约 7,580,721,483,160,132,811,489,280 个解决方案。来源en.wikipedia.org/wiki/Latin_square)。您的代码确实适用于 n=3 并且如果您有一台具有足够功率的较新计算机,则适用于 n=4 和 5。因此,很可能是计算能力问题
  • 另外,正如上面 [r] 标签明确提到的,使用library() 调用指定所有非基础包。 rlatin函数从何而来?
  • 第8行,要不要:if(identical(new, l[[j]]))){
  • 您只想构建正方形的规范形式,还是每个排列?如果是后者,我建议您为找到的每个正方形生成所有排列,并且只检查任何新正方形的规范形式。会更有效率。
  • @aiatay7n 我真的只会使用这个函数来获得最多 n=5 的每个唯一正方形。出于某种原因,当我使用 n=3 时,上面的代码对我不起作用。它获得了 12 个拉丁方格,但有些是重复的。

标签: r for-loop if-statement


【解决方案1】:

您的代码无法防止重复,因为一旦您的相等性测试成功,您就会找到一个新的拉丁方格,但是您不会使用当前的拉丁方格列表来测试那个新的拉丁方格!您可能需要一个 while 循环,该循环仅在当前拉丁方格与所有以前的拉丁方格不同时才中断。这可以使用sapply 进行评估,尽管当 n 变大时这可能会很慢。

L <- function(n) {
  size <- factorial(n) * factorial(n-1)
  l <- list()
  l[[1]] <- rlatin(n)
  for(k in 2:size) {
    new <- rlatin(n)
    while(sum(sapply(l, function(x) any(identical(x, new)))) > 0) {
      new <- rlatin(n)
    }
    l[[k]] <- new
  }
  l
} 

对于 n=4 (size=144),代码只需几秒钟。但是对于 n=5 (size=2880),代码需要永远和一天。也许有更快的解决方案。


L4 <- L(4)  # About 10 seconds.

检查重复项:

x <- list()
for(i in 1:length(L4)) {
    x[[i]] <- sapply(L4[-i], function(x) any(identical(x, L4[[i]])))
}

sum(sapply(x, sum))
# [1] 0

L5 <- L(5) # Still waiting... or as grampa used to say: 
                                            "you'll be wait'n til the cows come home".

啊,终于。

   user  system elapsed 
 816.16    0.54  827.20

【讨论】:

  • 您的代码看起来很棒!非常感谢。我确实有几个cmets。该函数快速获取L3和L4;但是,它似乎无法计算 L2。此外,L4 仅包含 144 个矩阵,而 Wikipedia 说应该有 576 个 4 阶的唯一拉丁方格。
  • L5 是一个包含 2880 个矩阵的列表,而它也应该是 161,280。不过,我觉得我们真的很亲近!
  • 但是您的代码使用size 初始化列表。那是你的代码,不是我的。如果不是阶乘 (n) * 阶乘 (n-1) 应该是什么?
  • 这是因为 rlatin 函数总是返回相同的拉丁方格,用于 n=2。那是一个错误吗?似乎微不足道,只有两种可能。
  • 奇怪的是,rlatin(n=2, size=2) 两者都给出,但结果是数组形式。
猜你喜欢
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 2019-09-30
  • 1970-01-01
相关资源
最近更新 更多