整数の組み合わせを効率的に選択


8

0で満たされた5x5の行列があるとしましょう。

myMatrix <- matrix(rep(0, 25), ncol = 5)

それでは、1から5までの整数のトリプレットを選びましょう。

triplet <- c(1,2,3)

このトリプレットのすべての組み合わせについて、次の関数を使用して、マトリックスに1を追加します。

addCombinationsToMatrix <- function(.matrix, .triplet){
    indexesToChange <- as.matrix(expand.grid(.triplet, .triplet))
    .matrix[indexesToChange] <- .matrix[indexesToChange] + 1
    .matrix
}

関数を使用して、

myMatrix

     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0    0    0    0
[3,]    0    0    0    0    0
[4,]    0    0    0    0    0
[5,]    0    0    0    0    0

myMatrix <- addCombinationsToMatrix(myMatrix, triplet)
myMatrix

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    0    0
[2,]    1    1    1    0    0
[3,]    1    1    1    0    0
[4,]    0    0    0    0    0
[5,]    0    0    0    0    0

別のトリプレットを選択した場合は、次に進みます

nextTriplet <- 2:4
myMatrix <- addCombinationsToMatrix(myMatrix, nextTriplet)
myMatrix

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    0    0
[2,]    1    2    2    1    0
[3,]    1    2    2    1    0
[4,]    0    1    1    1    0
[5,]    0    0    0    0    0

したがって、行と列の組み合わせは、2つの整数がトリプレットで一緒に表示される頻度を表します。3と4が1回一緒に表示され、2と3が2回一緒に表示されています。

質問:すべての組み合わせ(1-2、1-3、1-4 ...)が少なくとも1回選択され、トリプレットの数が最小化されるように、トリプレットを選択するにはどうすればよいですか。

次のトリプレットを選択するアルゴリズムを探しています。

理想的には、

  • 任意の大きな行列(10x10、100x100 ...)
  • 任意の大きなベクトル(4つ組、5つ組、nつ組)
  • 少なくとも組み合わせが選択されている必要がある回数

例:

myMatrix
myMatrix <- addCombinationsToMatrix(myMatrix, 1:3)
myMatrix
myMatrix <- addCombinationsToMatrix(myMatrix, 3:5)
myMatrix
myMatrix <- addCombinationsToMatrix(myMatrix, c(1,4,5))
myMatrix
myMatrix <- addCombinationsToMatrix(myMatrix, c(2,4,5))
myMatrix

編集:念のため:答えはRコードである必要はありません。他の言語でも、疑似コードでもかまいません。

編集2:効率を測定するにはさまざまな方法があることに気づきました。私が実際に言ったのは、アルゴリズムはできるだけ少ない反復をとるべきだということです。アルゴリズムが高速であることも非常に優れていますが、ここでは主な目標ではありません。

回答:


6

すばらしい質問です。これは調査のデザインに現れます。調査のいくつかのバージョンにそれぞれ質問のサブセットのみが含まれている必要がありますが、質問のすべてのペア(またはtタプル)が少なくとも1回は質問されている必要があります。

これはカバーデザインと呼ばれ、古典的なセットカバー問題の変形です。このトピックに関する優れた数学スタック交換の投稿を読むことができるので、人々は、vから描画する必要があるk要素のサブセットの最小数(この場合はk = 3)を示す表記C(v、k、t)を使用します-要素セット(この場合はv = 5)。セット全体(この場合はt = 2)のすべてのt要素サブセットが、選択したサブセットの1つに含まれます。人々はこの関数をさまざまな(v、k、t)タプルについて評価しました。たとえば、https://ljcr.dmgordon.org/cover/table.htmlを参照してください。そのテーブルから、C(5、3、2)= 4であることがわかります。可能な設計の1つは次のとおりです。

  1  2  3
  1  4  5
  2  3  4
  2  3  5

何よりもまず、この問題はNP困難であるため、すべての既知の正確なアルゴリズムは、入力v、k、およびtで指数関数的にスケーリングします。したがって、小さなインスタンスを列挙または正確な方法(整数プログラミングなど)で正確に解決できる場合がありますが、問題のサイズが非常に大きくなるため、ヒューリスティックな方法に頼る必要があります。

この方向性の1つの可能性は、https://arxiv.org/pdf/math/9502238.pdfで提案されているように、辞書編集カバリングです(上記のサイトにあるソリューションの多くは、建設)。基本的に、可能なすべてのkタプルを辞書式順序でリストします。

123
124
125
134
135
145
234
235
245
345

次に、最も以前にカバーされていないTタプルをカバーするkタプルを貪欲に追加し、辞書式順序を使用して関係を解除します。

この場合のアルゴリズムの動作は次のとおりです。

  1. 最初に、3タプルごとに3つの異なる2タプルがカバーされるため、 123辞書順で最も古います。

  2. これを実行した後、2タプルの1213、および23すべての残りの2つの要素がカバーされていない一方で、カバーされています。いくつかの3タプルは、さらに3つの2タプルをカバー145245ます。私たちは選ぶ145ことが覆って、最初の辞書順であることから、1445、および15

  3. -今、私たちは4、残りの覆われていない2つの要素を持っている242534、と35。3タプルはこれらの3つをカバーしていませんが、いくつかは2をカバー234してい345ます。234辞書順で最も古いものとして選択します。

  4. カバーされていない2つのタプルが2つ残っています- 2535。選ぶ235両方をカバーする唯一の3タプルとして。

上記の正確なソリューションが得られます。重要なのは、これは単なるヒューリスティックな方法です。4が5つの要素を持つセットのすべてのペアをカバーするために必要な3タプルの最小数であるという保証はありません。この場合、Schönheimによる下限(上記のリンクされた記事で参照が提供されています)により、実際にはC(5、3、2)は4より小さくすることはできません。実際には最適です。

各tタプルを特定の回数rカバーするには、微調整が必​​要です。1つの明らかな方法は、各タプルを「r」回カバーするように繰り返し、次に通常どおりlexカバーリングを実行することです(たとえば、上記の最初のステップで、各3タプルは、r = 3で9つの2タプルをカバーします)。もちろん、これはlexカバーの使用による全体的な問題のヒューリスティックのままです。


2
誰、これは驚くほど良い答えです。どうもありがとうございます。それは基本的に質問自体が行ったよりも質問をよりよく説明します。これは本当に啓発的です。
ジョージリー

2

以下は、data.table行列の数を追跡しRcppAlgos、組み合わせを生成するために使用するオプションです。

library(RcppAlgos)
library(data.table)

M <- 100 #5 #10 #100
sz <- 5 #3 #4 5 
minpick <- 3 #1 #2
d <- integer(M)

system.time({
    universe <- as.data.table(comboGeneral(M, 2L, nThreads=4L))[, count := 0L]
    ntuples <- 0
    while (universe[, any(count < minpick)]) {
        v <- universe[order(count), head(unique(c(V1[1L:2L], V2[1L:2L])), sz)]
        universe[as.data.table(comboGeneral(v, 2L, nThreads=4L)), on=.NATURAL, count := count + 1L]
        ntuples = ntuples + 1L
    }
    ntuples
})
#   user  system elapsed 
#  26.82    9.81   28.75 

m <- matrix(0L, nrow=M, ncol=M)
m[as.matrix(universe[, V1:V2])] <- universe$count
m + t(m) + diag(d)

これは貪欲なアルゴリズムであるため、これが最小数のタプルになるかどうかはわかりません。


うーん、それは私にはうまくいきません。私はこのエラーを受け取ります: Error in eval(onsub, parent.frame(2L), parent.frame(2L)) : object '.NATURAL' not found
ジョージリー

data.tableバージョン> = 1.12.4が必要です。github.com/ Rdatatable / data.table
blob /

2

この質問は設計をカバーするためのアルゴリズム的アプローチを求めているので、Rの整数プログラミングを使用して正確な答え(別名、最良の設計)を提供するものを提供します。検討しているすべての単一のkタプル(k = 3トリプレットを選択しているため)、設計に含める場合は値1、含まない場合は0となる決定変数を定義します。したがって、あなたのケースでは、タプル(1,2,3)が選択されているかどうかを示すx_123、(3,4,5)のx_345などを定義します。

最適化モデルの目的は、選択されたタプルの数、つまりすべての決定変数の合計を最小限に抑えることです。ただし、すべてのtタプル(この場合はt = 2)について、そのtタプルを含む決定変数を含める必要があります。これにより、すべてのtタプルに制約が生じます。例として、選択されたタプルにx_123+x_124+x_125 >= 1ペアが存在12することを要求する制約があります。

これにより、次の最適化モデルが生成されます。

min  x_123+x_124+...+x_345
s.t. x_123+x_124+x_125 >= 1  # constraint for 12
     x_123+x_134+x_135 >= 1  # constraint for 13
     ...
     x_145+x_245+x_345 >= 1  # constraint for 45
     x_ijk binary for all i, j, k

これを拡張して、すべての不等式の右側を "r"に変更し、すべての変数をバイナリではなく整数にすることで、すべてのtタプルのr回の繰り返しを要求できます。

これはlpSolve、Rのようなパッケージで簡単に解決できます。

library(lpSolve)
C <- function(v, k, tt, r) {
  k.tuples <- combn(v, k)
  t.tuples <- combn(v, tt)
  mod <- lp(direction="min",
            objective.in=rep(1, ncol(k.tuples)),
            const.mat=t(apply(t.tuples, 2, function(x) {
              apply(k.tuples, 2, function(y) as.numeric(sum(x %in% y) == tt))
            })),
            const.dir=rep(">=", ncol(t.tuples)),
            const.rhs=rep(r, ncol(t.tuples)),
            all.int=TRUE)
  k.tuples[,rep(seq_len(ncol(k.tuples)), round(mod$solution))]
}
C(5, 3, 2, 1)
#      [,1] [,2] [,3] [,4]
# [1,]    1    1    1    3
# [2,]    2    2    2    4
# [3,]    3    4    5    5
C(5, 3, 2, 3)
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]    1    1    1    1    1    1    2    2    2     3
# [2,]    2    2    2    3    3    4    3    3    4     4
# [3,]    3    4    5    4    5    5    4    5    5     5

これは問題を正確に解決しますが、大きな問題の規模にうまく対応できません。これは、問題がNP困難であるためです。既知の正確なアルゴリズムで適切にスケーリングできません。大きな問題のインスタンスを解決する必要がある場合は、ここで他の回答で推奨されているヒューリスティックが最善の策です。または、整数プログラミング(ここで行うように)で解決し、タイムアウトを設定することもできます。次に、タイムアウトによって検出された最適なソリューションを使用します。これは、問題全体のヒューリスティックなソリューションです。

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