Apa cara terbaik untuk menentukan jumlah bukan nol dalam perkalian matriks jarang?

17

Saya bertanya-tanya apakah ada metode cepat dan efisien untuk menemukan jumlah bukan nol di muka untuk operasi perkalian matriks jarang dengan asumsi kedua matriks dalam format CSC atau CSR.

Saya tahu ada satu dalam paket smmp tapi saya butuh sesuatu yang sudah diimplementasikan dalam C atau C ++.

Bantuan apa pun akan dihargai. Terima kasih sebelumnya.

Recker
sumber
apakah matriks Anda memiliki simetri, atau struktur ke lokasi entri yang tidak nol?
Godric Seer
@GodricSeer ... tidak, saya hanya berbicara tentang matriks jarang umum. Matlab memiliki nnz (A) di mana A adalah metode matriks jarang untuk mengetahui jumlah bukan nol. Saya bertanya-tanya apakah ada metode seperti itu.
Recker
Saya pribadi tidak bisa memikirkan cara apa pun untuk menghitung angka yang akan menjadi urutan yang lebih rendah daripada hanya melakukan perkalian matriks yang sebenarnya tanpa mengeksploitasi beberapa simetri atau struktur. Saya berasumsi Anda ingin ini untuk alokasi memori sebelum melakukan perkalian?
Godric Seer
Juga, saya menemukan makalah ini yang menjelaskan cara memperkirakan angka pada produk matriks boolean (yang identik dengan menghitung unsur-unsur dalam setiap produk matriks).
Godric Seer
@ GodricSeer..Ya Anda benar, saya perlu nomor yang tepat hanya untuk alokasi memori dari matriks yang dihasilkan. Terima kasih untuk tautan ke kertas. Itu mungkin membuat saya memulai beberapa arah untuk sementara waktu.
Recker

Jawaban:

14

Anda bisa mensimulasikan produk matriks-matriks dengan membentuk produk dari dua pola sparsity - yaitu, Anda menganggap pola sparsity (yang disimpan dalam array terpisah dalam format CSR) sebagai matriks yang berisi nol atau satu di setiap entri. Melakukan produk simulasi ini hanya mengharuskan Anda untuk membentuk danoperasi pada nol dan satu ini dan dengan demikian jauh lebih cepat daripada produk matriks-matriks yang sebenarnya - pada kenyataannya, yang harus Anda lakukan adalah melalui baris dan kolom dari dua matriks dan memverifikasi bahwa setidaknya ada satu entri dalam baris dan kolom yang Anda kalikan dengan di mana kedua matriks tidak nol. Ini adalah operasi yang murah - jauh lebih murah dalam hal apa pun daripada benar-benar harus melakukan perkalian floating point dalam produk aktual yang tidak hanya mengharuskan Anda untuk melakukan aritmatika floating point (mahal) tetapi juga membaca dalam angka floating point aktual dari memori ( bahkan lebih mahal, tetapi Anda tidak perlu itu ketika mengalikan pola sparsity karena nilai-nilai non-nol dari matriks disimpan secara terpisah dalam CSR).

Wolfgang Bangerth
sumber
6
Ini disebut perkalian simbolik. Ini tidak selalu lebih murah daripada perkalian numerik, terutama secara paralel, tetapi itu hanya perlu dilakukan sekali per pola sparsity. Banyak algoritma akan melakukan operasi beberapa kali dengan nilai numerik yang berbeda tetapi pola sparsity yang sama, di mana perkalian simbolik dapat digunakan kembali.
Jed Brown
Itu ide yang bagus, tetapi mengingat jutaan transistor yang melakukan float * float secara paralel, kita hanya berbicara tentang penghematan kecepatan 50% atau sekitar sini.
Evgeni Sergeev
1
@ EvgeniSergeev - intinya bukanlah penghematan dalam perhitungan, tetapi penghematan dalam transfer memori. Karena Anda menghabiskan 80% atau lebih banyak waktu hari ini untuk transfer memori untuk perkalian matriks yang jarang, Anda kemungkinan akan memperoleh secara signifikan jika Anda tidak perlu membaca / menulis data floating point dari / ke memori.
Wolfgang Bangerth
CmkHAI(mk)
HAI(mk)halm=kHAI(mhalcatatanhal)HAI(m2)
13

Saya benar-benar menulis kode asli di Matlab untuk A * B, baik A dan B jarang. Pra-alokasi ruang untuk hasilnya memang bagian yang menarik. Kami mengamati apa yang Godric tunjukkan - bahwa mengetahui jumlah nonzeros di AB sama mahalnya dengan menghitung AB.

Kami melakukan implementasi awal Matlab yang jarang sekitar tahun 1990, sebelum makalah Edith Cohen yang memberikan cara praktis dan cepat pertama untuk memperkirakan ukuran AB secara akurat. Kami mengumpulkan estimator ukuran lebih rendah, dan jika kami kehabisan ruang di pertengahan perhitungan, menggandakan alokasi dan menyalin hasil yang dihitung sebagian.

Saya tidak tahu apa yang ada di Matlab sekarang.

Kemungkinan lain adalah menghitung AB satu kolom pada satu waktu. Setiap kolom dapat disimpan sementara dalam akumulator jarang (lihat kertas Matlab jarang untuk penjelasannya), dan ruang yang dialokasikan untuk menampung ukuran kolom hasil yang diketahui dengan tepat. Hasilnya akan dalam bentuk kolom terkompresi jarang tersebar - setiap kolom dalam CSC tetapi tidak ada persentuhan antar kolom - menggunakan 2 vektor numcol panjang (mulai col, panjang col), bukan satu, sebagai meta-data. Ini adalah bentuk penyimpanan yang layak untuk dilihat; ia memiliki kekuatan lain - Anda dapat menumbuhkan kolom tanpa merealokasi seluruh matriks.

Rob Schreiber
sumber
Baik untuk implementasi GPU saya, saya akhirnya menemukan struktur bukan nol terlebih dahulu dan kemudian menemukan matriks yang sebenarnya. Performa mengerikan seperti yang diharapkan. Saya pikir mereka menggunakan metode yang dijelaskan dalam buku ini untuk secara efisien mengalikan dua matriks jarang pada MATLAB.
Recker
2
Sangat keren, terima kasih atas perspektif sejarahnya, dan selamat datang di scicomp :)
Aron Ahmadia
4

Makalah ini menjelaskan suatu algoritma untuk memperkirakan ukuran resultan dari produk matriks dua matriks jarang.

Masalah dengan menemukan jumlah entri non-nol yang tepat dalam perkalian matriks jarang adalah bahwa setiap elemen dalam resultan bergantung pada interaksi dua vektor, yang keduanya kemungkinan mengandung setidaknya beberapa elemen bukan nol. Oleh karena itu, untuk menghitung angka Anda perlu mengevaluasi operasi logis pada sepasang vektor untuk setiap elemen dalam resultan. Masalahnya adalah ini membutuhkan sejumlah operasi yang mirip dengan jumlah operasi yang diperlukan untuk menghitung produk matriks itu sendiri. Dalam komentar saya, saya menyebutkan kemungkinan untuk mengeksploitasi struktur tertentu dalam elemen non-nol dari matriks asli, namun eksploitasi yang sama dapat digunakan untuk mengurangi pekerjaan yang dilakukan dalam perkalian matriks juga.

Anda mungkin akan lebih baik menggunakan kertas di atas untuk memperkirakan kebutuhan memori secara berlebihan, melakukan penggandaan dan kemudian memotong memori yang dialokasikan, atau memindahkan matriks yang dihasilkan ke array yang berukuran lebih tepat. Juga, produk matriks jarang bukan kejadian langka, dan saya hampir menjamin bahwa masalah ini telah dipecahkan sebelumnya. Sedikit menggali ke dalam beberapa sumber terbuka, perpustakaan matriks jarang akan mengarahkan Anda ke algoritma yang mereka gunakan untuk mengalokasikan memori.

Pelihat Godric
sumber
0

Untuk CSR atau CSC, apakah Anda dijamin bahwa array elemen matriks Anda sudah tidak memiliki nol? Dalam hal ini mudah untuk mengetahui berapa banyak elemen yang tidak nol, dengan menggunakan sesuatu yang mirip dengan:

int nnz = sizeof(My_Array)/sizeof(long int);

Namun jika ini bukan masalahnya (sepertinya agak terlalu mudah) yang bisa Anda coba adalah pengurangan . Jika susunan elemen matriks Anda sangat besar, ini mungkin cara yang paling efisien untuk menghitung jumlah elemen bukan nol. Banyak pustaka C / C ++ paralel seperti Thrust (pustaka CUDA) atau OpenCL (yang Anda tidak perlu menggunakan GPU) memiliki dukungan untuk pengurangan bersyarat - untuk setiap elemen, tambahkan hasilnya Condition(Element). Jika Anda mengatur kondisi ke Element != 0maka Anda akan menambahkan jumlah elemen bukan nol. Anda juga mungkin ingin menghapus elemen bernilai nol dari array elemen Anda, array indeks baris / kolom, dan menyesuaikan kolom / pointer baris Anda.

jeruk nipis
sumber
terima kasih atas balasan Anda ... tapi saya mengacu pada nol nol di A * B di mana A dan B adalah matriks jarang. Saya perlu jumlah bukan nol di muka sehingga saya dapat mengalokasikan jumlah memori yang tepat untuk menyimpan matriks yang dihasilkan.
Recker
0

Cara paling sederhana untuk mengimplementasikan CSR adalah dengan mencoba

std::vector< std::map<int, complex<float>> > 

untuk mewakili matriks Anda. Dalam hal ini Anda tidak akan benar-benar khawatir tentang jumlah elemen yang tidak nol, semua diakses melalui

std::map< int, complex<float> >::iterator

di setiap baris. Terbaik ..


sumber
2
STL, karena ketika Anda berpikir rutin matriks jarang Anda tidak dapat dibuat lebih lambat.
Jed Brown