Tugasnya adalah untuk menghitung jumlah substring panjang k yang berbeda, untuk k = 1,2,3,4, .....
Keluaran
Anda harus output satu baris per k
Anda berhasil menyelesaikan dengan satu nomor per baris output. Output Anda harus dalam urutan meningkat k
hingga Anda kehabisan waktu.
Skor
Skor Anda adalah k tertinggi yang dapat Anda peroleh di komputer saya dalam waktu kurang dari 1 menit.
Anda harus menggunakan http://hgdownload.cse.ucsc.edu/goldenPath/hg38/chromosomes/chr2.fa.gz sebagai masukan dan abaikan baris baru. Namun, kode Anda harus peka terhadap huruf besar-kecil.
Anda dapat mendekompresi input sebelum memulai timing.
Kode berikut (tidak efisien) menghitung jumlah 4-mers yang berbeda.
awk -v substr_length=4 '(len=length($0))>=substr_length{for (i=1; (i-substr_length)<len; i++) substrs[substr($0,i,substr_length)]++}; END{for (i in substrs) print substrs[i], i}' file.txt|wc
Batas memori
Untuk membuat kode Anda berperilaku baik di komputer saya dan untuk membuat tugas lebih menantang, saya akan membatasi RAM yang dapat Anda gunakan hingga 2GB dengan menggunakan
ulimit -v 2000000
sebelum menjalankan kode Anda. Saya sadar ini bukan cara solid untuk membatasi penggunaan RAM, jadi jangan gunakan cara imajinatif untuk mengatasi batasan ini dengan, misalnya, memunculkan proses baru. Tentu saja Anda dapat menulis kode multi-utas tetapi jika seseorang melakukannya, saya harus belajar cara membatasi total RAM yang digunakan untuk itu.
Tie Breaker
Dalam kasus dasi untuk beberapa maksimum k
saya akan menghitung berapa lama waktu yang dibutuhkan untuk memberikan hasil k+1
dan yang tercepat menang. Jika mereka berjalan dalam waktu yang sama hingga dalam satu detik hingga k+1
, pengiriman pertama menang.
Bahasa dan perpustakaan
Anda dapat menggunakan bahasa apa pun yang memiliki kompiler / juru bahasa / dll yang tersedia secara bebas. untuk Linux dan semua perpustakaan yang juga tersedia secara bebas untuk Linux.
Mesin saya Pengaturan waktu akan dijalankan di mesin saya. Ini adalah instalasi ubuntu standar pada Prosesor Delapan Core AMD FX-8350 pada Motherboard Asus M5A78L-M / USB3 (Socket AM3 +, 8GB DDR3). Ini juga berarti saya harus dapat menjalankan kode Anda. Sebagai konsekuensinya, hanya gunakan perangkat lunak gratis yang mudah tersedia dan harap sertakan instruksi lengkap cara menyusun dan menjalankan kode Anda.
Uji keluaran
Kode FUZxxl menampilkan yang berikut (tetapi tidak semua dalam 1 menit) yang saya yakini benar.
14
92
520
2923
15714
71330
265861
890895
2482912
5509765
12324706
29759234
tabel liga
- k> = 4000 FUZxxl (C)
- k = 16 oleh Keith Randall (C ++)
- k = 10 oleh FUZxxl (C)
Seberapa banyak Anda dapat mengkhususkan kode Anda untuk input?
- Jelas itu akan merusak kompetisi jika Anda hanya menghitung jawaban dan kode Anda menghasilkannya. Jangan lakukan itu.
- Idealnya, apa pun yang perlu dipelajari kode Anda tentang data yang akan digunakan untuk berjalan lebih cepat, hal itu dapat dipelajari saat dijalankan.
- Namun Anda dapat mengasumsikan input akan terlihat seperti data dalam file * .fa di http://hgdownload.cse.ucsc.edu/goldenPath/hg38/chromosomes/ .
J
, solusi naif hanya akan menjadi `[: ~.]` Tetapi tebak itu tidak akan memotongnya.Jawaban:
C (≥ 4000)
Kode ini tidak menggunakan kurang dari 2 GB RAM (menggunakan sedikit lebih) atau menghasilkan setiap output dalam menit pertama. Tetapi jika Anda menunggu sekitar enam menit, ia mencetak semua jumlah k -mer sekaligus.
Opsi disertakan untuk membatasi k tertinggi yang kami hitung k -mers. Ketika k terbatas pada rentang yang masuk akal, kode berakhir dalam waktu kurang dari satu menit dan menggunakan kurang dari 2 GiB RAM. OP telah memberi peringkat solusi ini dan berakhir dalam waktu kurang dari satu menit untuk batas yang tidak lebih tinggi dari 4000.
Bagaimana cara kerjanya?
Algoritma ini memiliki empat langkah.
Akhiran-urutkan array indeks ke buffer input. Misalnya, sufiks string
mississippi
adalah:String ini diurutkan dalam urutan leksikografis adalah:
Sangat mudah untuk melihat bahwa semua substring yang sama dengan panjang k untuk semua k ditemukan dalam entri yang berdekatan dari array yang diurutkan akhiran.
Array integer diisi di mana kami menyimpan di setiap indeks k jumlah k -mers yang berbeda . Ini dilakukan dengan cara yang sedikit berbelit-belit untuk mempercepat proses. Pertimbangkan dua entri yang berdekatan dengan susunan suffix sort.
p menunjukkan panjang awalan umum terpanjang dari dua entri, l menunjukkan panjang entri kedua. Untuk pasangan seperti itu, kami menemukan substring panjang k yang berbeda untuk p < k ≤ l . Karena p ≪ l sering berlaku, tidak praktis untuk menambah sejumlah besar entri array untuk setiap pasangan. Sebagai gantinya kita menyimpan array sebagai array perbedaan, di mana setiap entri k menunjukkan perbedaan dengan jumlah k -mers ke jumlah ( k - 1) -mers. Ini mengubah pembaruan formulir
menjadi pembaruan formulir yang jauh lebih cepat
Dengan mengamati dengan cermat bahwa l selalu berbeda dan pada kenyataannya setiap 0 < l < n akan muncul tepat satu kali, kita dapat menghilangkan pengurangan dan bukannya mengurangi 1 dari setiap perbedaan ketika mengkonversi dari perbedaan menjadi jumlah.
Kode sumber
Sumber ini menggunakan libdivsufsort untuk mengurutkan array sufiks. Kode menghasilkan output sesuai dengan spesifikasi saat dikompilasi dengan doa ini.
alternatifnya kode dapat menghasilkan output biner ketika dikompilasi dengan doa berikut.
Untuk membatasi k tertinggi di mana k -mers dihitung, supply -DICAP = k di mana k adalah batasnya:
Kompilasi dengan
-O3
jika kompiler Anda menyediakan opsi ini.Format file biner dapat dikonversi ke format output yang dapat dibaca manusia dengan program berikut:
output sampel
Contoh output dalam format biner untuk file
chr22.fa
dapat ditemukan di sini . Silakan dekompresibzip2 -d
terlebih dahulu. Output disediakan dalam format biner hanya karena kompresnya jauh lebih baik (3,5 kB vs 260 MB) daripada output dalam format yang dapat dibaca manusia. Berhati-hatilah meskipun keluaran referensi memiliki ukuran 924 MB saat tidak dikompresi. Anda mungkin ingin menggunakan pipa seperti ini:sumber
cat
. Gunakan pengalihan shell seperti di./dsskmer <~/Downloads/chr2.fs
. Kode perlu tahu berapa lama file input dan itu tidak mungkin dengan pipa.C ++, k = 16, 37 detik
Menghitung semua 16-mers dalam input. Setiap 16-mer dikemas 4 bit ke simbol menjadi kata 64-bit (dengan pola satu bit dicadangkan untuk EOF). Kata-kata 64-bit kemudian disortir. Jawaban untuk setiap k dapat dibaca dengan melihat seberapa sering bit top 4 * k dari kata yang diurutkan berubah.
Untuk input tes saya menggunakan sekitar 1.8GB, tepat di bawah kawat.
Saya yakin kecepatan membaca dapat ditingkatkan.
Keluaran:
Program:
Kompilasi dengan
g++ -O3 kmer.cc -o kmer
dan jalankan./kmer chr2.fa
.sumber
C ++ - peningkatan dari solusi FUZxxl
Saya sama sekali tidak layak kredit untuk metode perhitungan itu sendiri, dan jika tidak ada pendekatan yang lebih baik muncul pada saat itu, karunia harus pergi ke FUZxxl dengan benar.
Saya hanya menggunakan Kasai et al. algoritma untuk menghitung LCP di O (n).
Sisanya hanyalah adaptasi dari kode FUZxxl, menggunakan fitur C ++ yang lebih ringkas di sana-sini.
Saya meninggalkan kode perhitungan asli untuk memungkinkan perbandingan.
Karena proses yang paling lambat adalah konstruksi SA dan jumlah LCP, saya menghapus sebagian besar optimasi lainnya untuk menghindari kekacauan kode untuk mendapatkan keuntungan yang dapat diabaikan.
Saya memperpanjang tabel SA untuk menyertakan awalan nol panjang. Itu membuat perhitungan LCP lebih mudah.
Saya tidak memberikan opsi batasan panjang, proses paling lambat saat ini adalah perhitungan SA yang tidak dapat dirampingkan (atau setidaknya saya tidak melihat bagaimana itu bisa dilakukan).
Saya juga menghapus opsi output biner dan tampilan terbatas pada 10 nilai pertama.
Saya menganggap kode ini hanya bukti konsep, jadi tidak perlu mengacaukan tampilan atau jenuh disk.
Membangun executable
Saya harus mengkompilasi seluruh proyek (termasuk versi lite
divsufsort
) untuk x64 untuk mengatasi batas alokasi Win32 2Gb.divsufsort
kode melempar banyak peringatan karena penggunaanint
s, bukansize_t
s, tetapi itu tidak akan menjadi masalah untuk input di bawah 2Gb (yang tetap membutuhkan 26Gb RAM: D).Linux membangun
kompilasi
main.cpp
dandivsufsort.c
gunakan perintah:Saya menganggap
divsufsort
perpustakaan biasa harus bekerja dengan baik di Linux asli, selama Anda dapat mengalokasikan sedikit lebih dari 3Gb.Pertunjukan
Algoritma Kasai membutuhkan tabel SA terbalik, yang memakan hingga 4 byte lebih per karakter untuk total 13 (bukan 9 dengan metode FUZxxl).
Konsumsi memori untuk input referensi dengan demikian di atas 3Gb.
Di sisi lain, waktu perhitungan ditingkatkan secara dramatis, dan keseluruhan algoritma sekarang dalam O (n):
Perbaikan lebih lanjut
Konstruksi SA sekarang merupakan proses paling lambat.
Beberapa bit dari
divsufsort
algoritma dimaksudkan untuk diparalelkan dengan fitur bawaan apa pun dari kompiler yang tidak saya ketahui, tetapi jika perlu kodenya harus mudah beradaptasi dengan multithreading yang lebih klasik ( à la C ++ 11, misalnya).Lib juga memiliki satu truk penuh parameter, termasuk berbagai ukuran ember dan jumlah simbol yang berbeda dalam string input. Saya hanya melihat sekilas pada mereka, tapi saya curiga mengompresi alfabet mungkin patut dicoba jika string Anda adalah permutasi ACTG yang tak ada habisnya ( dan Anda sangat membutuhkan pertunjukan).
Ada beberapa metode yang dapat diparalelkan untuk menghitung LCP dari SA juga, tetapi karena kode harus berjalan di bawah satu menit pada prosesor yang sedikit lebih kuat daripada [email protected] saya yang kecil dan seluruh algoritme dalam O (n), saya ragu ini akan sepadan dengan usaha.
sumber
C (dapat menyelesaikan hingga 10 dalam satu menit di mesin saya)
Ini adalah solusi yang sangat sederhana. Itu membangun pohon k -mers yang ditemukan dan menghitungnya. Untuk menghemat memori, karakter terlebih dahulu dikonversi menjadi bilangan bulat dari 0 ke n - 1 dengan n adalah jumlah karakter yang berbeda dalam input, jadi kami tidak perlu menyediakan ruang untuk karakter yang tidak pernah muncul. Selain itu, lebih sedikit memori yang dialokasikan untuk daun daripada untuk node lain untuk menghemat memori lebih lanjut. Solusi ini menggunakan sekitar 200 MiB RAM saat runtime di komputer saya. Saya masih memperbaikinya, jadi mungkin dalam iterasi mungkin lebih cepat!
Untuk mengkompilasi, simpan kode di bawah ini dalam file bernama
kmers.c
dan kemudian jalankan pada sistem operasi seperti POSIX:Anda mungkin ingin mengganti
-O3
untuk-O
jika dukungan compiler Anda yang. Untuk menjalankan, pertama buka paketchr2.fa.gz
kechr2.fa
dan kemudian jalankan:Ini menghasilkan langkah demi langkah keluaran. Anda mungkin ingin membatasi waktu dan ruang. Gunakan sesuatu seperti
untuk mengurangi sumber daya sesuai kebutuhan.
Perbaikan
sumber
timeout 60s
berfungsi OK untuk saya sehingga tidak perlu membangun cara untuk membunuh kode setelah 1 menit.ulimit -t 60
.