在对称下唯一生成nxnxn立方晶格中所有m个点的集合的算法


10

我正在实现一个算法,该算法将在计算上非常复杂,并且想要尝试确保我没有做不必要的工作。

有一个nxnxn立方晶格,例如,如果n = 2,则由(0,0,0),(0,1,0),(1,0,0),(1,1,0),(0, 1,1),(0,0,1),(1,0,1),(1,1,1)。

从这个格子中,我将递归地生成所有m点的集合,例如:

solve(set_of_points) {
     if set_of_points.size = m, finish

     do some useful computation here

     for each point in lattice not in set_of_points:
         solve(set_of_points + new_point);
}

然后可以从一个空的set_of_points开始调用。

问题的本质是,我实际上不需要m个点的所有排列,而只需要在立方体自然对称下唯一的那些点。

例如,拿一个2x2x2的多维数据集,并假设我们希望所有1点的集合。在以上基本算法下,有8个不同的1点集。

但是,使用立方体的对称性,我们可以将其减少到1个唯一的1点集,因为在立方体的对称性下所有原始的8个点都是等效的(在这种情况下,它们都是“角”)。

如果立方体是2x2x2且m = 2,则基本算法中有28个集合,但是在对称情况下,该集合减少为3个(例如{(0,0,0),(1,0,0)},{(0 ,0,0),(1,1,0)},{(0,0,0),(1,1,1)})

显然,对3个点集进行计算要比28个点好得多,所以我的问题是如何不生成与已经生成的点对称对称的点集?或者,如果这不可能,那么我如何至少减少套数。

(请注意-如果m = 1,这相对容易-只需选择比其他任何一个顶点更接近(0,0,0)的点,并且边界处会有一点毛刺。这是因为m> 1成为一个真正的问题)


1
通过对称等效,您包括哪些操作:通过中心的镜平面?通过中心点反转?通过中心的所有三个4转轴?
BmyGuest

任何等距的
图形

如果您仍在附近,是否可以在m点组中重复?例如,对于m = 3,{(0,0,0),(1,1,1),(0,0,0)}被视为一个有效选择吗?
blackpen

@blackpen不,它必须是3个唯一要点
rbennett485 '16

Answers:


1

基本概念:

(1)我们可以简单地将点(0,0,0)视为000。现在,晶格中的每个点都以简单的顺序排列。第一个点是000,然后是001,然后是010 011 100 101 110和111。这是您尝试将它们添加到点集的顺序。

(2)同样,集合{(0,0,0),(0,0,1),(0,1,0)}可以简单地看成000001010,而集合{(0,0,0) ,((0,1,0),(0,0,1)}可以简单地看作是000010001。两个不同的集合不能具有相同的序列,并且您可以轻松地将000001010视为数字或字母小于000010001。我们称其为设定值。现在,每个可能的N点集都有一个设定值,并且所有可能的N点集现在都位于一个简单的有序列表中。

(3)每个点集的同构组只有一个成员,它将具有最低的设定值。这些是我们实际进行“有用计算”的唯一方法。

(4)这是需要大量工作的部分。在运行solve(set_of_points + new_point)之前,您想查看是否有任何同构会降低set_of_points + new_point的设置值。如果任何同构会降低设定值,则这不是同构集的最低值成员。我们跳过对此new_point的任何工作。我们还将跳过在此solve(set_of_points,candidate_point)中本应完成的所有递归工作。

solve(set_of_points,new_point) {
 set_of_points = set_of_points + new_point
 do some useful computation here
 if set_of_points.size = m, compute how many isomophisms exist, apply that multiple, finish
 for(candidate_point = new_point+1 to last_point) { /skips point-permutations for free!/
  if ISOMORPH_TESTS_CANNOT_LOWER_VALUE_OF(set_of_points+candidate_point) {
   solve(set_of_points,candidate_point);
  }
 }
}

1

以上面答案的符号表示。

首先定义函数rotate(direction,number_of_time)提出的对称性

解:

(1)创建每个排列的所有集合的哈希,其中每个标记= 0。例如n = 2,m = 2 000,001 = 0 000,010 = 0 000,011 = 0等...

(2)从初始化集开始,例如i = 000,001

(3)例如,使用旋转函数(或您喜欢的任何其他对称性)将集合i旋转到所有方向,对于旋转的每个排列,旋转函数应调用24次。

在此处输入图片说明

解释:前面有1-6个数字,每个数字可以旋转4次,因此6 * 4 = 24

(4)对于从组合中移出的每个集合,将hash标志设置为1(它已经对称设置)

(5)将i更新到下一个集合,例如i = 000,010

(6)如果哈希中的集合i已被标记,则转到(5),否则转到(3)

当所有哈希标记为1时,我们就完成了。


我很喜欢这种方法,但是对于原始问题并没有那么有用(不是我告诉过您什么!)。原因是这仍然需要生成每组点,并且我必须对每组点进行的工作非常小,因此这可能会增加所节省的开销。对于需要为每个集合进行大量计算的应用程序,这将很方便
rbennett485 '16

1

注意:我只考虑镜像对称性,而不考虑旋转对称性。

假设我们有一个d维的(超)立方体,每个立方体长n个单位(Rubik的立方体将是d = 3,n = 3)。

天真的算法会生成n个点的组合,并检查每个点是否与所有其他点对称冲突。

如果我们将点的组合表示为长度为n ^ d比特的比特向量,则可以使用映射(比特向量->布尔值)来将比特向量的所有对称性标记为true。如果组合已经在地图中标记,我们可以跳过该组合。

这种方法空间效率非常低:它需要一个包含2 ^(n ^ d)个条目的映射,即一个具有这么多位的位图。(对于Rubik的多维数据集,它将是2 ^ 27 = 128Mbit = 16 MB。)

我们只能记住规范表示,即,如果表示为n ^ d位无符号字,则它们具有最小的整数值。当我们生成一个新的点排列时,我们会生成它的所有对称性,并且仅检查是否看到了具有最小数值的对称性。这将使我们仅存储2 ^ n位的映射(对于Rubik's cube,仅存储1个字节),因为我们具有2 ^ d个对称性。但是,这使我们在每个步骤上生成了这2 ^ d个对称性,因此我们花费O(2 ^(d ^ n + d))= O(2 ^(d ^ n)* 2 ^ d)的时间。仍然很差。

我们可以将上一段中的想法应用于一维案例。为了在长度为d的向量中生成所有组合,我们只需从所有s 开始增加二进制数d位长即可0。让我们将向量划分为两个d / 2个长段,例如左和右。我们可以注意到,对于1左段中的每个位,我们只需要查看1在右侧部分的对称位置具有位的组合。否则,当交换位的位置并且0出现在之前时,我们将早先生成对称组合1。这样,对于右半部分(r)中的每个位位置,以及左半部分中的对称位置(l)我们只需要生成3个组合:(l = 0,r = 0); (l = 1,r = 1);(l = 1,r = 0)。因此,我们只需要生成长度为d的向量的2 ^(d / 2)个置换,就可以为每个置换生成3个组合。

d维的多维数据集可以由n ^(d-1)个向量构成。上面的技巧使我们的向量比朴素的方法便宜。要生成一个立方体,我们需要O(n ^(d-1)* 2 ^(d / 2))时间。

如果我们沿着一维向量的维度看立方体,我们可以看到我们不必检查这个维度的对称性:在生成立方体时,我们消除了每个涉及向量的对称性。

现在,如果我们看一下整个这个维度,我们可以重复使用同样的伎俩。

当我们看时,我们看例如构成特定平面的矢量的第一位。这些位代表一维位向量。如上所述,我们可以出于对称原因消除其位的大多数组合。因此,如果我们选择多维数据集的特定一维矢量(例​​如,最左边的最顶部),则可以基于特定位的值来消除同一平面的许多矢量(例如,最顶部)。因此,对于平面上镜像对称位置的向量,我们可以避免生成可能已设置(或未设置)该位的所有组合,从而大大减少了必须为特定平面生成的向量的数量。每个消除的位将镜面反射位置的可能矢量减半。这为我们提供了一系列平面,每个平面上没有对称的对应部分。

该技巧可以应用于进一步限制后续平面沿第三维等的排列生成。

虽然不是完整的算法,但希望对您有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.