Saya mencoba menunjukkan kepada anak saya bagaimana pengkodean dapat digunakan untuk memecahkan masalah yang ditimbulkan oleh sebuah permainan serta melihat bagaimana R menangani data besar. Game yang dimaksud disebut "Lucky 26". Dalam game ini angka (1-12 tanpa duplikat) diposisikan pada 12 poin pada bintang david (6 vertex, 6 persimpangan) dan 6 baris 4 angka semuanya harus menambah 26. Dari sekitar 479 juta kemungkinan (12P12 ) rupanya ada 144 solusi. Saya mencoba kode ini dalam R sebagai berikut tetapi tampaknya masalah memori. Saya akan sangat menghargai saran untuk memajukan jawaban jika anggota punya waktu. Berterima kasih kepada anggota sebelumnya.
library(gtools)
x=c()
elements <- 12
for (i in 1:elements)
{
x[i]<-i
}
soln=c()
y<-permutations(n=elements,r=elements,v=x)
j<-nrow(y)
for (i in 1:j)
{
L1 <- y[i,1] + y[i,3] + y[i,6] + y[i,8]
L2 <- y[i,1] + y[i,4] + y[i,7] + y[i,11]
L3 <- y[i,8] + y[i,9] + y[i,10] + y[i,11]
L4 <- y[i,2] + y[i,3] + y[i,4] + y[i,5]
L5 <- y[i,2] + y[i,6] + y[i,9] + y[i,12]
L6 <- y[i,5] + y[i,7] + y[i,10] + y[i,12]
soln[i] <- (L1 == 26)&(L2 == 26)&(L3 == 26)&(L4 == 26)&(L5 == 26)&(L6 == 26)
}
z<-which(soln)
z
r
bigdata
permutation
Proyek Gurun
sumber
sumber
x<- 1:elements
dan yang lebih pentingL1 <- y[,1] + y[,3] + y[,6] + y[,8]
. Ini tidak akan membantu masalah memori Anda sehingga Anda selalu dapat melihat ke rcpprm(list=ls())
MRE Anda. Jika seseorang menyalin-paste ke sesi aktif mereka bisa kehilangan data mereka sendiri.Jawaban:
Ini pendekatan lain. Ini didasarkan pada posting blog MathWorks oleh Cleve Moler , penulis MATLAB pertama.
Dalam posting blog, untuk menghemat memori penulis hanya mengijinkan 10 elemen, menjaga elemen pertama sebagai elemen puncak dan yang ke 7 sebagai elemen dasar. Oleh karena itu, hanya
10! == 3628800
permutasi yang perlu diuji.Dalam kode di bawah ini,
1
ke10
. Ada total10! == 3628800
dari mereka.11
sebagai elemen puncak dan pertahankan. Tidak masalah dari mana tugas dimulai, elemen lainnya akan berada di posisi relatif yang tepat .for
lingkaran.Ini harus menghasilkan sebagian besar solusi, memberi atau mengambil rotasi dan refleksi. Tetapi itu tidak menjamin bahwa solusinya unik. Ini juga cukup cepat.
sumber
Sebenarnya ada 960 solusi. Di bawah ini kami menggunakan
Rcpp
,RcppAlgos
* , danparallel
paket untuk mendapatkan solusinya hanya dalam waktu singkat6 seconds
menggunakan 4 core. Bahkan jika Anda memilih untuk menggunakan pendekatan berulir tunggal dengan basis Rlapply
, solusinya dikembalikan dalam waktu sekitar 25 detik.Pertama, kami menulis algoritma sederhana
C++
yang memeriksa permutasi tertentu. Anda akan perhatikan bahwa kami menggunakan satu array untuk menyimpan semua enam baris. Ini untuk kinerja karena kami menggunakan memori cache lebih efektif daripada menggunakan 6 array individual. Anda juga harus ingat bahwaC++
menggunakan pengindeksan berbasis nol.Sekarang, dengan menggunakan
lower
danupper
argumen dipermuteGeneral
, kita dapat menghasilkan potongan permutasi dan mengujinya secara terpisah untuk menjaga memori tetap terkendali. Di bawah ini, saya telah memilih untuk menguji sekitar 4,7 juta permutasi sekaligus. Outputnya memberikan indeks leksikografis dari permutasi 12! sehingga kondisi Lucky 26 puas.Sekarang, kami memverifikasi menggunakan
permuteSample
dan argumensampleVec
yang memungkinkan Anda untuk menghasilkan permutasi spesifik (misalnya jika Anda melewati 1, itu akan memberi Anda permutasi pertama (yaitu1:12
)).Akhirnya, kami memverifikasi solusi kami dengan basis R
rowSums
:* Saya adalah penulis
RcppAlgos
sumber
Untuk permutasi, rcppalgos bagus. Sayangnya, ada 479 juta kemungkinan dengan 12 bidang yang berarti terlalu banyak memori untuk kebanyakan orang:
Ada beberapa alternatif.
Ambil sampel permutasi. Artinya, lakukan hanya 1 juta bukan 479 juta. Untuk melakukan ini, Anda dapat menggunakan
permuteSample(12, 12, n = 1e6)
. Lihat @ JosephWood's jawaban untuk pendekatan yang agak mirip kecuali dia sampel 479 juta permutasi;)Buat loop di rcpp untuk mengevaluasi permutasi pada kreasi. Ini menghemat memori karena pada akhirnya Anda akan membangun fungsi hanya untuk mengembalikan hasil yang benar.
Dekati masalah dengan algoritma yang berbeda. Saya akan fokus pada opsi ini.
Algoritma baru dengan kendala
Segmen harus 26
Kita tahu bahwa setiap segmen baris dalam bintang di atas perlu menambahkan hingga 26. Kita dapat menambahkan kendala itu untuk menghasilkan permutasi kami - beri kami hanya kombinasi yang menambahkan hingga 26:
Kelompok ABCD dan EFGH
Pada bintang di atas, saya telah mewarnai tiga grup secara berbeda: ABCD , EFGH , dan IJLK . Dua kelompok pertama juga tidak memiliki kesamaan poin dan juga memiliki segmen bunga yang sama. Oleh karena itu, kita dapat menambahkan batasan lain: untuk kombinasi yang menambahkan hingga 26, kita perlu memastikan ABCD dan EFGH tidak memiliki angka yang tumpang tindih. IJLK akan diberi 4 angka sisanya.
Permutasi melalui grup
Kita perlu menemukan semua permutasi dari setiap grup. Artinya, kami hanya memiliki kombinasi yang menambahkan hingga 26. Misalnya, kami perlu mengambil
1, 2, 11, 12
dan membuat1, 2, 12, 11; 1, 12, 2, 11; ...
.Perhitungan Akhir
Langkah terakhir adalah melakukan perhitungan. Saya menggunakan
lapply()
dan diReduce()
sini untuk melakukan pemrograman yang lebih fungsional - jika tidak, banyak kode akan diketik enam kali. Lihat solusi asli untuk penjelasan yang lebih menyeluruh tentang kode matematika.Swapping ABCD dan EFGH
Pada akhir kode di atas, saya mengambil keuntungan bahwa kita dapat bertukar
ABCD
danEFGH
mendapatkan permutasi yang tersisa. Berikut adalah kode untuk mengonfirmasi bahwa ya, kami dapat menukar kedua grup dan menjadi benar:Performa
Pada akhirnya, kami mengevaluasi hanya 1,3 juta dari 479 permutasi dan hanya mengocok hingga 550 MB RAM. Dibutuhkan sekitar 0,7 untuk menjalankan
sumber
Inilah solusi untuk kawan kecil:
sumber