Haruskah satu tes untuk kompleksitas algoritmik? Jika ya, bagaimana caranya?

14

Katakanlah saya mengimplementasikan sesuatu yang sederhana seperti mencari daftar / array yang diurutkan. Fungsi (dalam c #) akan terlihat mirip dengan:

static int FindIndex(int[] sortedList, int i);

Saya bisa menerapkan dan menguji ini dalam hal fungsionalitas, tetapi untuk alasan yang jelas saya biasanya lebih suka pencarian biner daripada pencarian linear atau sesuatu yang sengaja bodoh.

Jadi pertanyaan saya adalah: Haruskah kita berusaha menulis tes yang menjamin kinerja dalam hal kompleksitas algoritmik dan jika demikian, bagaimana?

Saya sudah mulai membuat argumen di kedua sisi bagian "haruskah Anda" dari pertanyaan ini, tetapi saya ingin melihat apa yang dikatakan orang tanpa argumen saya untuk mendorong mereka.

Dalam hal "bagaimana", itu menjadi sangat menarik :) Anda bisa melihat parameterisasi operator perbandingan dan melakukan tes yang operator perbandingannya menghitung perbandingan atau sesuatu seperti itu. Tetapi hanya karena Anda tidak dapat berarti Anda harus ...

Adakah orang lain yang mempertimbangkan hal ini (mungkin)? Terima kasih.

SirPentor
sumber
@ steenhulthin - Saya akan membiarkan ini dididih di sini dan periksa Saya belum pernah ke sana.
SirPentor
btw, pertanyaan bagus. +1
Rafael Colucci

Jawaban:

13

Kompleksitas algoritma adalah konstruksi teoretis dan oleh karena itu yang terbaik "diuji" dengan pensil dan kertas. Itu tidak dapat diuji secara mekanis.

Kinerja absolut dapat diuji secara mekanis dan dapat membuat unit test yang berguna. Jika kinerja penting, maka Anda dapat menentukan ambang: "kueri ini seharusnya tidak lebih dari 50 ms untuk dijalankan pada 10 6 angka, dan tidak lebih dari 60 ms pada 10 7 angka." Anda bisa membuat unit test.

Pengguna akhir tidak peduli apakah algoritme Anda linear atau logaritmik; mereka peduli apakah UI mereka masih merespons secara instan bahkan ketika mereka memiliki data setahun dalam aplikasi.

Crashworks
sumber
Ini juga insting saya. Tapi apa yang membuat saya berpikir tentang hal itu adalah ketika jaminan kinerja pada kerangka kerja. Contoh: jika saya ingat dengan benar, stl memiliki beberapa jaminan di sekitar kompleksitas algoritme (bisa di sini).
SirPentor
Hanya karena perpustakaan menyediakan beberapa jaminan tidak berarti mereka harus dapat diuji unit.
svick
@Tobias Brick: Menguji sesuatu dan mendefinisikan sesuatu adalah dua hal yang berbeda.
DeadMG
Menunjukkan kinerja itu sulit. Ini melibatkan banyak titik sampel untuk berbagai parameter. Lebih mudah ketika fungsi-fungsi individual sepele, tetapi di luar itu ... Beban Anda, RAM Anda, kecepatan bus depan, CPU, jumlah core, agresivitas kompiler, tingkat polusi registri semua akan mempengaruhi jangka waktu tertentu Sampel.
Pekerjaan
3

Walaupun saya tidak yakin apakah alat ini akan sangat berguna untuk pengujian unit, makalah "Kompleksitas Komputasi Empiris" oleh Goldsmith, Aiken, dan Wilkerson menjelaskan metode untuk menginstruksikan kode dan mengamati perilaku dinamisnya pada serangkaian input berbeda untuk secara empiris menurunkan kompleksitas asimptotiknya. Program yang dijelaskan dalam makalah ini bersifat open-source dan tersedia di sini .

Semoga ini membantu!

templatetypedef
sumber
0

Yang utama adalah coba dengan data besar dan lihat apakah terlalu lama.

Dalam pengalaman penyesuaian kinerja saya, seperti dalam contoh ini , apa yang terjadi adalah jika beberapa algoritma (misalnya) O (n ^ 2) mungkin baik-baik saja selama persentase waktu yang dibutuhkan tidak pernah sampai ke radar.

Namun, ketika diberikan dataset dengan ukuran yang mungkin tidak terlihat tetapi setahun sekali, sebagian kecil dari total waktu yang dihisap oleh algoritma tersebut dapat menjadi dominan secara dahsyat.

Jika Anda dapat mewujudkannya dalam pengujian, itu adalah hal yang sangat baik, karena sangat mudah untuk menemukan masalahnya, sama seperti jika itu adalah loop tak terbatas yang sebenarnya.

Mike Dunlavey
sumber
0

Saya tidak berpikir apa yang ingin Anda lakukan adalah Pengujian Unit.

AFAIK, pengujian unit hanya untuk memastikan kode melakukan apa yang seharusnya dilakukan dan tidak fokus pada kinerja.

Dari Wikipedia : Pengujian tidak dapat diharapkan untuk menangkap setiap kesalahan dalam program: tidak mungkin untuk mengevaluasi setiap jalur eksekusi di semua kecuali program yang paling sepele. Hal yang sama berlaku untuk pengujian unit. Selain itu, pengujian unit menurut definisi hanya menguji fungsionalitas unit itu sendiri. Oleh karena itu, itu tidak akan menangkap kesalahan integrasi atau kesalahan tingkat sistem yang lebih luas (seperti fungsi yang dilakukan di beberapa unit, atau area uji non-fungsional seperti kinerja). Pengujian unit harus dilakukan bersamaan dengan aktivitas pengujian perangkat lunak lainnya. Seperti semua bentuk pengujian perangkat lunak, pengujian unit hanya dapat menunjukkan adanya kesalahan; mereka tidak dapat menunjukkan tidak adanya kesalahan.

Ada jenis alat dan pola lain untuk mengukur kinerja. Salah satu yang bisa saya ingat sekarang adalah pengujian Penerimaan berfokus pada persyaratan non fungsional.

Ada beberapa yang lain seperti pengujian kinerja (yang menggunakan pengujian stres, pengujian beban, dll).

Anda juga dapat menggunakan beberapa alat stres bersama-sama dengan alat build (semut, studio build otomatis) sebagai bagian dari langkah penerapan Anda (itulah yang saya lakukan).

Jadi jawaban singkatnya adalah tidak, Anda tidak perlu khawatir tentang hal itu saat unit menguji kode.

Rafael Colucci
sumber
0

Melewati pembanding dan memiliki yang melacak berapa kali disebut akan bekerja untuk tujuan sederhana seperti memeriksa bahwa jumlah perbandingan ketika melakukan pencarian dalam input tetap (katakanlah new int[] { 1,2,3, ... , 1024 }) tetap di bawah 10. Itu setidaknya akan memperjelas niat Anda tentang bagaimana algoritma seharusnya berperilaku.

Saya tidak berpikir unit test adalah cara yang tepat untuk memverifikasi bahwa algoritma Anda adalah O (log n); yang akan membutuhkan banyak pembuatan data acak, beberapa penyesuaian kurva, dan mungkin statistik secara kasar untuk menentukan apakah sekelompok titik data cocok dengan runtime yang diharapkan. (Untuk algoritme ini mungkin dapat dilakukan, tetapi jika Anda mulai menyortir dll akan menjadi sulit untuk berulang kali menekan skenario terburuk).

yatima2975
sumber