入力:半径R、寸法D
- カーディナリティ≤DのRのすべての整数分割を生成します
- パーティションごとに、繰り返しなしで並べ替えます
- 順列ごとに、すべての記号をいじります
たとえば、Pythonで次のようにコーディングします。
from itertools import *
# we have to write this function ourselves because python doesn't have it...
def partitions(n, maxSize):
if n==0:
yield []
else:
for p in partitions(n-1, maxSize):
if len(p)<maxSize:
yield [1] + p
if p and (len(p)<2 or p[1]>p[0]):
yield [ p[0]+1 ] + p[1:]
# MAIN CODE
def points(R, D):
for part in partitions(R,D): # e.g. 4->[3,1]
part = part + [0]*(D-len(part)) # e.g. [3,1]->[3,1,0] (padding)
for perm in set(permutations(part)): # e.g. [1,3,0], [1,0,3], ...
for point in product(*[ # e.g. [1,3,0], [-1,3,0], [1,-3,0], [-...
([-x,x] if x!=0 else [0]) for x in perm
]):
yield point
radius = 4、dimension = 3のデモ:
>>> result = list( points(4,3) )
>>> result
[(-1, -2, -1), (-1, -2, 1), (-1, 2, -1), (-1, 2, 1), (1, -2, -1), (1, -2, 1), (1, 2, -1), (1, 2, 1), (-2, -1, -1), (-2, -1, 1), (-2, 1, -1), (-2, 1, 1), (2, -1, -1), (2, -1, 1), (2, 1, -1), (2, 1, 1), (-1, -1, -2), (-1, -1, 2), (-1, 1, -2), (-1, 1, 2), (1, -1, -2), (1, -1, 2), (1, 1, -2), (1, 1, 2), (0, -2, -2), (0, -2, 2), (0, 2, -2), (0, 2, 2), (-2, 0, -2), (-2, 0, 2), (2, 0, -2), (2, 0, 2), (-2, -2, 0), (-2, 2, 0), (2, -2, 0), (2, 2, 0), (-1, 0, -3), (-1, 0, 3), (1, 0, -3), (1, 0, 3), (-3, -1, 0), (-3, 1, 0), (3, -1, 0), (3, 1, 0), (0, -1, -3), (0, -1, 3), (0, 1, -3), (0, 1, 3), (-1, -3, 0), (-1, 3, 0), (1, -3, 0), (1, 3, 0), (-3, 0, -1), (-3, 0, 1), (3, 0, -1), (3, 0, 1), (0, -3, -1), (0, -3, 1), (0, 3, -1), (0, 3, 1), (0, -4, 0), (0, 4, 0), (0, 0, -4), (0, 0, 4), (-4, 0, 0), (4, 0, 0)]
>>> len(result)
66
(set(permutations(...))
以前は繰り返しなしで順列を取得していましたが、これは一般的に効率的ではありませんが、ポイントの性質上、ここでは問題にならない可能性があります。効率が重要な場合は、選択した言語で独自の再帰関数を記述できます。)
この方法は、ハイパーボリュームに合わせてスケーリングするのではなく、列挙しようとしているハイパーサーフェスに合わせてスケーリングするため、効率的です(半径が非常に大きい場合を除いて、それほど重要ではない可能性があります。たとえば、速度を約100倍節約できます。半径が100の場合)。