Kapan saya harus menggunakan templat ekspresi C ++ dalam ilmu komputasi, dan kapan saya * tidak * menggunakannya?

24

Misalkan saya sedang mengerjakan kode ilmiah dalam C ++. Dalam diskusi baru-baru ini dengan seorang kolega, dikemukakan bahwa templat ekspresi bisa menjadi hal yang sangat buruk, berpotensi membuat perangkat lunak hanya dapat dikompilasi pada versi gcc tertentu. Seharusnya, masalah ini telah mempengaruhi beberapa kode ilmiah, seperti yang disinggung dalam subtitle dari parodi Downfall ini . (Ini adalah satu-satunya contoh yang saya tahu, maka tautannya.)

Namun, orang lain berpendapat bahwa templat ekspresi berguna karena mereka dapat menghasilkan keuntungan kinerja, seperti dalam makalah ini dalam SIAM Journal of Scientific Computing , dengan menghindari penyimpanan hasil antara dalam variabel sementara.

Saya tidak tahu banyak tentang template metaprogramming di C ++, tapi saya tahu itu adalah salah satu pendekatan yang digunakan dalam diferensiasi otomatis dan dalam aritmatika interval, yang merupakan cara saya terlibat dalam diskusi tentang template ekspresi. Mengingat potensi keuntungan dalam kinerja dan potensi kerugian dalam pemeliharaan (jika itu kata yang tepat), kapan saya harus menggunakan templat ekspresi C ++ dalam ilmu komputasi, dan kapan saya harus menghindarinya?

Geoff Oxberry
sumber
Ah, videonya terlalu lucu. Saya tidak tahu itu ada. Siapa yang membuatnya, tahukah Anda?
Wolfgang Bangerth
Tidak ada ide; beberapa orang PETSc mengirimi saya tautan pada satu titik. Saya pikir pengembang FEniCS berhasil.
Geoff Oxberry
Tautan video rusak dan saya sekarat karena penasaran. Tautan baru?
Praxeolitic
Ya ampun, sudahlah, saya melihat youtube telah datang untuk video Hitler kami.
Praxeolitic

Jawaban:

17

Masalah saya dengan templat ekspresi adalah mereka abstraksi yang sangat bocor. Anda menghabiskan banyak pekerjaan menulis kode yang sangat rumit untuk melakukan tugas sederhana dengan sintaks yang lebih bagus. Tetapi jika Anda ingin mengubah algoritma, Anda harus mengacaukan dengan kode kotor dan jika Anda tergelincir dengan jenis atau sintaksis, Anda mendapatkan pesan kesalahan yang benar-benar tidak dapat dipahami. Jika aplikasi Anda memetakan dengan sempurna ke pustaka berdasarkan templat ekspresi, maka mungkin layak dipertimbangkan, tetapi jika Anda tidak yakin, saya akan merekomendasikan hanya menulis kode normal. Tentu, kode tingkat tinggi kurang cantik, tetapi Anda bisa melakukan apa yang perlu dilakukan. Sebagai manfaat, waktu kompilasi dan ukuran biner akan turun dan Anda tidak perlu menghadapi perbedaan besar dalam kinerja karena pilihan kompiler dan bendera kompilasi.

Jed Brown
sumber
Ya, saya telah melihat beberapa pesan kesalahan yang panjang secara langsung ketika saya harus mem-porting kode dari gcc 2.95 ke gcc 4.x, dan kompilator melempar segala macam kesalahan tentang templat. Lab-mate saya sedang mengembangkan perpustakaan templated untuk aritmatika interval dalam C ++ (menambahkan fitur baru yang tidak ada dalam Boost :: Interval untuk menyelesaikan penelitian lebih lanjut), dan saya tidak ingin melihat kode menjadi mimpi buruk untuk mengkompilasi.
Geoff Oxberry
12

Yang lain mengomentari masalah betapa sulitnya menulis program ET serta kompleksitas memahami pesan kesalahan. Izinkan saya mengomentari masalah kompiler: Memang benar bahwa beberapa waktu lalu salah satu masalah besar adalah menemukan kompiler yang cukup sesuai dengan standar C ++ untuk membuat semuanya berfungsi dan membuatnya bekerja dengan baik. Akibatnya, kami menemukan banyak bug - Saya memiliki 2-300 laporan bug dalam nama saya, didistribusikan melalui gcc, Intel icc, IBM xlC, dan pgicc Portland. Akibatnya, skrip konfigurasi deal.II adalah repositori dari sejumlah besar tes bug kompiler, terutama di bidang templat, deklarasi teman, ruang nama, dll.

Tapi, ternyata pembuat kompiler benar-benar mendapatkan aksi mereka bersama: hari ini, gcc dan icc hari ini lulus semua tes kami dan mudah untuk menulis kode yang portabel di antara mereka berdua. Saya akan mengatakan PGI tidak jauh di belakang tetapi memiliki sejumlah kebiasaan yang tampaknya tidak hilang selama bertahun-tahun. xlC, di sisi lain, adalah cerita yang sama sekali berbeda - mereka memperbaiki bug setiap 6 bulan, tetapi meskipun mengajukan laporan bug dengan mereka selama bertahun-tahun, kemajuan sangat lambat dan xlC tidak pernah dapat mengkompilasi kesepakatan. Saya berhasil.

Apa ini semua artinya adalah ini: jika Anda tetap menggunakan dua kompiler besar, Anda dapat berharap bahwa mereka hanya bekerja hari ini. Karena kebanyakan komputer dan OS saat ini biasanya memiliki setidaknya satu dari mereka, itu sudah cukup. Satu-satunya platform di mana hal-hal lebih sulit adalah BlueGene, di mana kompiler sistem biasanya xlC, dengan semua bug-nya.

Wolfgang Bangerth
sumber
Hanya karena penasaran, apakah Anda mencoba mengkompilasi terhadap kompiler xlc baru di / Q?
Aron Ahmadia
Tidak, saya akan mengakui bahwa saya sudah menyerah pada xlC.
Wolfgang Bangerth
5

Saya telah bereksperimen sedikit dengan ET dulu ketika, seperti yang Anda sebutkan, kompiler masih berjuang dengan mereka. Saya telah menggunakan perpustakaan blitz untuk aljabar linier dalam beberapa kode saya. Masalahnya kemudian adalah mendapatkan kompiler yang baik dan karena saya bukan programmer C ++ yang sempurna, menafsirkan pesan kesalahan kompiler. Yang terakhir tidak bisa diatur. Kompiler rata-rata akan menghasilkan sekitar 1000 baris pesan kesalahan. Tidak mungkin saya dapat dengan cepat menemukan kesalahan pemrograman saya.

Anda dapat menemukan informasi lebih lanjut tentang halaman web oonumerik (ada dua lokakarya ET).

Tetapi saya akan tinggal jauh dari mereka ....

GertVdE
sumber
Pesan-pesan kesalahan kompiler memang salah satu perhatian saya. Dengan beberapa kode C ++ templated yang saya kompilasi untuk membangun perpustakaan untuk proyek-proyek saya, kompiler dapat menghasilkan ratusan baris pesan peringatan. Namun, itu bukan kode saya, saya tidak memahaminya, dan secara umum, ini berfungsi, jadi saya tinggalkan saja. Pesan kesalahan panjang dan samar tidak menjadi pertanda baik untuk debugging.
Geoff Oxberry
4

Masalahnya sudah dimulai dengan istilah 'templat ekspresi (ET)'. Saya tidak tahu apakah ada definisi yang tepat untuk itu. Tetapi dalam penggunaan umum itu entah bagaimana pasangan 'bagaimana Anda kode ekspresi aljabar linier' dan 'bagaimana hal itu dihitung'. Sebagai contoh:

Anda mengkode operasi vektor

v = 2*x + 3*y + 4*z;                    // (1)

Dan itu akan dihitung oleh satu lingkaran

for (int i=0; i<n; ++i)                 // (2)
    v(i) = 2*x(i) + 3*y(i) + 4*z(i);

Menurut pendapat saya ini adalah dua hal yang berbeda dan perlu dipisahkan: (1) adalah antarmuka dan (2) satu kemungkinan implementasi. Maksud saya ini adalah praktik umum dalam pemrograman. Tentu (2) mungkin merupakan implementasi standar yang baik, tetapi secara umum saya ingin dapat memanfaatkan implementasi khusus dan berdedikasi. Sebagai contoh, saya ingin fungsi seperti itu

myGreatVecSum(alpha, x, beta, y, gamma, z, result);    // (3)

dipanggil ketika saya coding (1). Mungkin (3) hanya menggunakan loop internal seperti pada (2). Tetapi tergantung pada ukuran vektor implementasi lain mungkin lebih efisien. Bagaimanapun, beberapa ahli dalam kinerja tinggi dapat mengimplementasikan dan menyetel (3) sebanyak mungkin. Jadi jika (1) tidak dapat dipetakan ke panggilan (3) maka saya lebih suka menghindari gula sintaksis (1) dan langsung menelepon (3) segera.

Apa yang saya jelaskan bukanlah hal baru. Sebaliknya, itu adalah ide di balik BLAS / LPACK:

  • Semua operasi kritis kinerja di LAPACK dilakukan dengan memanggil fungsi BLAS.
  • BLAS hanya mendefinisikan antarmuka untuk ekspresi aljabar linier yang biasanya diperlukan.
  • Untuk BLAS terdapat berbagai implementasi yang dioptimalkan.

Jika ruang lingkup BLAS tidak mencukupi (misalnya tidak menyediakan fungsi seperti (3)) maka seseorang dapat memperluas ruang lingkup BLAS. Jadi dinosaurus ini dari tahun 60an dan 70an menyadari dengan alat zaman batu pemisahan yang bersih dan ortogonal dari antarmuka dan implementasi. Agak lucu bahwa (sebagian besar) perpustakaan C ++ numerik tidak mencapai tingkat kualitas perangkat lunak ini. Meskipun bahasa pemrogramannya sendiri jauh lebih canggih. Jadi tidak mengherankan bahwa BLAS / LAPACK masih hidup dan dikembangkan secara aktif.

Jadi, menurut saya, ET bukanlah kejahatan. Tetapi bagaimana mereka biasanya digunakan dalam perpustakaan C ++ numerik membuatnya mendapatkan reputasi yang sangat buruk di kalangan komputasi ilmiah.

Michael Lehn
sumber
Michael, saya pikir Anda kehilangan salah satu templat ekspresi. Contoh kode Anda (1) sebenarnya tidak memetakan ke panggilan BLAS yang dioptimalkan. Bahkan, bahkan ketika rutin BLAS ada, overhead panggilan fungsi BLAS membuatnya cukup buruk untuk vektor dan matriks kecil. Perpustakaan templat ekspresi yang canggih seperti Blaze dan Eigen dapat menggunakan evaluasi ekspresi yang ditangguhkan untuk menghindari penggunaan sementara, tetapi saya yakin bahwa hampir tidak ada bahasa domain yang spesifik yang dapat mengalahkan aljabar linear linting tangan.
Aron Ahmadia
Tidak, saya pikir Anda tidak mengerti intinya. Anda harus membedakan antara (a) BLAS sebagai spesifikasi dari beberapa operasi aljabar linier yang sering dibutuhkan (b) implementasi BLAS seperti ATLAS, GotoBLAS, dll. BTW bahwa cara kerjanya di FLENS: Secara default ekspresi seperti (1) akan dievaluasi dengan memanggil axpy dari BLAS tiga kali. Tetapi tanpa memodifikasi (1) saya juga bisa mengevaluasinya seperti pada (2). Jadi apa yang terjadi secara logis adalah sebagai berikut: jika operasi seperti pada (1) penting maka rangkaian operasi BLAS yang ditentukan (a) dapat diperpanjang.
Michael Lehn
Jadi intinya adalah: Notasi seperti 'v = x + y + z' dan bagaimana akhirnya akhirnya dihitung harus dipisahkan. Eigen, MTL, BLITZ, blaze-lib sepenuhnya gagal dalam hal ini.
Michael Lehn
1
Benar, tetapi jumlah operasi aljabar linier yang sering dibutuhkan adalah kombinatorik. Jika Anda akan menggunakan bahasa seperti C ++, Anda memiliki pilihan untuk mengimplementasikan yang dibutuhkan menggunakan templat ekspresi (ini adalah pendekatan Eigen / Blaze) dengan menggabungkan sub-blok dan algoritma secara cerdas menggunakan evaluasi yang ditangguhkan, atau menerapkan sejumlah besar perpustakaan setiap kemungkinan rutin. Saya tidak menganjurkan pendekatan mana pun, karena karya terbaru di Numba dan Cython menunjukkan kita bisa mendapatkan kinerja yang sama atau lebih baik dari bahasa skrip tingkat tinggi seperti Python.
Aron Ahmadia
Tetapi sekali lagi, yang saya keluhkan adalah fakta bahwa perpustakaan yang canggih (dalam arti rumit tetapi tidak fleksibel) seperti Eigen secara ketat memadukan notasi dan mekanisme evaluasi dan bahkan berpikir itu adalah hal yang baik. Jika saya menggunakan alat seperti Matlab, saya hanya ingin kode hal-hal dan mengandalkan bahwa Matlab melakukan hal terbaik. Jika saya menggunakan bahasa seperti C ++ maka saya ingin memegang kendali. Jadi hargai jika ada mekanisme evaluasi standar tetapi harus dimungkinkan untuk mengubahnya. Kalau tidak, saya kembali dan memanggil fungsi dalam C ++ secara langsung.
Michael Lehn