対称性の下で一意である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点のすべてのセットが必要だとします。上記の基本的なアルゴリズムの下では、1つのポイントの8つの異なるセットがあります。

ただし、立方体の対称性を使用すると、元の8はすべて立方体の対称性の下で同等であるため、これを1ポイントの一意の1セットに減らすことができます(この場合、それらはすべて「コーナー」です)。

立方体が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
対称的に同等である場合、どの操作を含めるか:中心を通る鏡面?センターを介したポイント反転?中心を通る3つの4回転軸すべて?
BmyGuest 2016年

どのアイソメトリでも効果があります
rbennett485 2016年

あなたがまだそこにいる場合、mセットの点で繰り返しが許可されますか?たとえば、m = 3の場合、{(0,0,0)、(1,1,1)、(0,0,0)}は1つの有効な選択と見なされますか?
2016

@blackpenいいえ、3つの一意のポイントである必要があります
rbennett485

回答:


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と見なすことができます。2つの異なるセットに同じシーケンスを含めることはできません。000001010は、数字またはアルファベット順で000010001より小さいと簡単に表示できます。これをセット値と呼びましょう。Nポイントの可能なすべてのセットにセット値があり、Nポイントの可能なすべてのセットが単純な順序付けされたリストに含まれるようになりました。

(3)ポイントセットの同型グループにはすべて、セット値が最も低いメンバーが1つだけあります。これらは、実際に「有用な計算」を行う唯一のものです。

(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 ect '...

(2)initセットから開始します(例:i = 000,001)

(3)たとえば、回転関数(または他の対称性)を使用してセットiを全方向に回転させます。回転の順列ごとに、回転関数を24回呼び出す必要があります。

ここに画像の説明を入力してください

説明:1から6までの任意の数字を前に置くことができ、各数字を4回回転させることができるため、6 * 4 = 24

(4)組み合わせから取得した各セットについて、ハッシュのフラグを1に設定します(すでに対称的なセットがあります)

(5)iを次のセットに更新します(例:i = 000,010)

(6)ハッシュのセットiがすでにマークされている場合は(5)に進み、そうでない場合は(3)に進む

すべてのハッシュが1としてマークされたら完了です。


私はこのアプローチがとても好きですが、元の問題にはそれほど役立ちません(それが何であるかを話したわけではありません!)。その理由は、これでもポイントの各セットの生成が必要であり、各セットで実行する必要がある作業は非常に少なかったため、節約した分だけオーバーヘッドが増える可能性があるためです。各セットに対して多くの計算を行うアプリケーションの場合、これは便利です
rbennett485

1

注:ここでは、回転対称性ではなく、ミラー対称性についてのみ考えています。

それぞれがn単位の長さのd次元の(ハイパー)キューブがあるとします(ルービックキューブはd = 3、n = 3になります)。

単純なアルゴリズムは、ポイントのn ^ dの組み合わせを生成し、それぞれを他のすべてとの対称性の衝突についてチェックします。

ポイントの組み合わせをn ^ dビット長のビットベクトルとして表す場合、マップ(ビットベクトル->ブール)を使用して、ビットベクトルのすべての対称性をtrueでマークできます。マップで既にマークされている場合は、組み合わせをスキップできます。

このアプローチはスペース効率が非常に悪いです。2^(n ^ d)のエントリを持つマップ、つまりこのビット数のビットマップをとります。(ルービックキューブの場合、2 ^ 27 = 128Mビット= 16Mバイトになります。)

n ^ dビットの符号なしワードとして表される場合、正規表現、つまり最小の整数値を持つビットベクトルのみを覚えることができます。ポイントの新しい順列を生成するとき、そのすべての対称性を生成し、最小の数値で対称性を見た場合にのみチェックします。これにより、2 ^ dの対称性があるため、2 ^ nビット(ルービックキューブの場合は1バイトのみ)でマップを格納できます。ただし、各ステップでこれらの2 ^ d対称性を生成するため、O(2 ^(d ^ n + d))= O(2 ^(d ^ n)* 2 ^ d)時間を費やします。まだ貧しい。

前の段落のアイデアを1次元のケースに適用できます。長さdのベクトルですべての組み合わせを生成するには、すべてのs から始めて、dビット長の2進数をインクリメントします0。ベクトルを2つの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))時間必要です。

1次元ベクトルの次元に沿って立方体を見ると、この次元に沿って対称性を確認する必要がないことがわかります。立方体を生成する際に、関係する各ベクトルの対称性を排除します。

私たちが見れば今渡って、このディメンション、我々は同じトリックを再利用することができます。

全体を見渡すと、たとえば特定の平面を構成するベクトルの最初のビットを調べます。これらのビットは、1次元のビットベクトルを表します。上記のように、対称性の理由からビットのほとんどの組み合わせを排除できます。したがって、立方体の特定の1次元ベクトル(たとえば、一番左の一番上)を選択すると、特定のビットの値に基づいて、同じ平面(たとえば、一番上)の多くのベクトルを削除できます。したがって、平面上の鏡面対称の位置にあるベクトルの場合、すべての組み合わせの生成を回避して、そのビットが設定(または設定解除)され、特定の平面に対して生成する必要のあるベクトルの数を大幅に削減できます。除去された各ビットは、ミラー反射位置で可能なベクトルの数を半分にします。これにより、各次元に沿って対称的な対応物がない一連の平面が得られます。

このトリックを適用して、3番目の次元に沿って続く平面の順列の生成をさらに制限することができます。

完全なアルゴリズムではありませんが、これが役立つことを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.