Apa itu invarian loop?

268

Saya membaca "Pengantar Algoritma" oleh CLRS. Dalam bab 2, penulis menyebutkan "loop invariants". Apa itu invarian loop?

Attilah
sumber
4
Ini sepertinya cukup bagus dalam menjelaskan: cs.miami.edu/~burt/learning/Math120.1/Notes/LoopInvar.html
Tom Gullen
periksa tautan ini programmer.stackexchange.com/questions/183815/…
Adil Abbasi
Untuk berjaga-jaga jika seseorang ingin menyelesaikan masalah pengkodean algoritmik aktual berdasarkan konsep loop invariant, silakan merujuk ke masalah ini di HackerRank. Mereka juga merujuk masalah penyisipan hanya untuk merinci konsep.
RBT
Kita juga bisa merujuk catatan di sini untuk pemahaman teoretis.
RBT

Jawaban:

345

Dengan kata sederhana, invarian loop adalah beberapa predikat (kondisi) yang berlaku untuk setiap iterasi loop. Sebagai contoh, mari kita lihat forloop sederhana yang terlihat seperti ini:

int j = 9;
for(int i=0; i<10; i++)  
  j--;

Dalam contoh ini benar (untuk setiap iterasi) itu i + j == 9. Invarian lemah yang juga benar adalah itu i >= 0 && i <= 10.

Tomas Petricek
sumber
29
Ini adalah contoh yang bagus. Sering kali ketika saya mendengar seorang instruktur menggambarkan loop invarian, itu hanyalah 'kondisi loop', atau sesuatu yang serupa. Contoh Anda menunjukkan bahwa yang invarian bisa jauh lebih banyak.
Brian S
77
Saya tidak melihat ini contoh yang baik karena loop invarian harus menjadi tujuan dari loop ... CLRS menggunakannya untuk membuktikan kebenaran dari algoritma penyortiran. Untuk jenis penyisipan, seandainya loop berulang dengan i, pada akhir setiap loop, array dipesan sampai elemen ke-i.
Clash
5
ya, contoh ini tidak salah, tetapi tidak cukup. Saya mendukung @Clash, karena loop invarian harus menyajikan tujuan, bukan hanya untuk dirinya sendiri.
Jack
7
@ Thomas Petricek - ketika loop berakhir, i = 10 dan j = -1; jadi contoh invarian yang lebih lemah yang Anda berikan mungkin tidak benar (?)
Raja
7
Meskipun saya setuju dengan komentar di atas, saya telah mengangkat jawaban ini karena ... tujuannya tidak ditentukan di sini. Tetapkan tujuan apa pun yang cocok, dan contohnya bagus.
Flavius
119

Saya suka definisi yang sangat sederhana ini: ( sumber )

Loop invarian adalah suatu kondisi [di antara variabel-variabel program] yang harus benar segera sebelum dan segera setelah setiap iterasi loop. (Perhatikan bahwa ini tidak mengatakan apa-apa tentang kebenaran atau kepalsuan sebagian jalan melalui iterasi.)

Dengan sendirinya, loop invarian tidak banyak membantu. Namun, diberikan invarian yang sesuai, dapat digunakan untuk membantu membuktikan kebenaran suatu algoritma. Contoh sederhana dalam CLRS mungkin ada hubungannya dengan pengurutan. Sebagai contoh, biarkan invarian loop Anda menjadi sesuatu seperti, pada awal loop, ientri pertama array ini diurutkan. Jika Anda dapat membuktikan bahwa ini memang invarian loop (yaitu bahwa ia berlaku sebelum dan sesudah setiap iterasi loop), Anda dapat menggunakan ini untuk membuktikan kebenaran dari algoritma pengurutan: pada penghentian loop, loop invarian masih puas , dan penghitung iadalah panjang dari array. Oleh karena itu, ientri pertama diurutkan berarti seluruh array diurutkan.

Contoh yang lebih sederhana: Loops Invariants, Correctness, dan Derivation Program .

Cara saya memahami invarian loop adalah sebagai alat formal, sistematis untuk alasan tentang program. Kami membuat satu pernyataan yang kami fokuskan untuk membuktikan kebenaran, dan kami menyebutnya loop invariant. Ini mengatur logika kita. Meskipun kita dapat berdebat secara informal tentang kebenaran beberapa algoritma, menggunakan loop invarian memaksa kita untuk berpikir dengan sangat hati-hati dan memastikan alasan kita kedap udara.

TNi
sumber
10
Harus ditunjukkan bahwa "segera setelah setiap iterasi" termasuk setelah loop berakhir - terlepas dari bagaimana itu berakhir.
Robert S. Barnes
Terima kasih banyak atas jawaban ini! Pengambilan terbesar dari itu adalah tujuan memiliki loop invarian ini adalah untuk membantu membuktikan kebenaran dari algoritma. Jawaban lain hanya fokus pada apa yang disebut loop invarian!
Neekey
39

Ada satu hal yang banyak orang tidak sadari ketika berhadapan dengan loop dan invarian. Mereka menjadi bingung antara loop invarian, dan loop kondisional (kondisi yang mengontrol terminasi loop).

Seperti yang ditunjukkan orang, loop invarian harus benar

  1. sebelum loop dimulai
  2. sebelum setiap iterasi dari loop
  3. setelah loop berakhir

(meskipun sementara itu bisa salah selama tubuh loop). Di sisi lain loop kondisional harus salah setelah loop berakhir, jika loop tidak akan pernah berakhir.

Jadi loop invarian dan kondisi loop harus kondisi yang berbeda.

Contoh yang bagus dari invarian loop kompleks adalah untuk pencarian biner.

bsearch(type A[], type a) {
start = 1, end = length(A)

    while ( start <= end ) {
        mid = floor(start + end / 2)

        if ( A[mid] == a ) return mid
        if ( A[mid] > a ) end = mid - 1
        if ( A[mid] < a ) start = mid + 1

    }
    return -1

}

Jadi pengulangan loop sepertinya cukup lurus ke depan - ketika mulai> mengakhiri pengakhiran berakhir. Tetapi mengapa loop itu benar? Apa loop invarian yang membuktikan kebenarannya?

Yang invarian adalah pernyataan logis:

if ( A[mid] == a ) then ( start <= mid <= end )

Pernyataan ini adalah tautologi logis - selalu benar dalam konteks loop / algoritma spesifik yang kami coba buktikan . Dan itu memberikan informasi berguna tentang kebenaran loop setelah itu berakhir.

Jika kita kembali karena kita menemukan elemen dalam array maka pernyataannya benar, karena jika A[mid] == akemudian aada dalam array dan midharus antara awal dan akhir. Dan jika loop berakhir karena start > endtidak ada angka seperti itu start <= mid dan mid <= end dan karena itu kita tahu bahwa pernyataan itu A[mid] == apasti salah. Namun, sebagai akibatnya pernyataan logis keseluruhan masih benar dalam arti nol. (Dalam logika pernyataan if (false) then (something) selalu benar.)

Sekarang bagaimana dengan apa yang saya katakan tentang loop kondisional selalu salah ketika loop berakhir? Sepertinya ketika elemen ditemukan dalam array maka loop kondisional benar ketika loop berakhir !? Sebenarnya tidak, karena kondisi loop tersirat benar-benar while ( A[mid] != a && start <= end )tetapi kami mempersingkat tes yang sebenarnya sejak bagian pertama tersirat. Persyaratan ini jelas salah setelah loop terlepas dari bagaimana loop berakhir.

Robert S. Barnes
sumber
Sangat aneh untuk menggunakan pernyataan logis sebagai loop invarian, karena semua pernyataan logis selalu benar, tidak peduli apa pun kondisinya.
Acgtyrant
Tidak jadi saya aneh harus berpikir, karena tidak ada jaminan bahwa ahadir dalam A. Secara informal, "jika kunci aada dalam array, itu harus terjadi di antara startdan endinklusif". Maka itu berarti bahwa jika A[start..end]kosong, itu atidak ada dalam A.
scanny
33

Jawaban sebelumnya telah mendefinisikan loop invarian dengan cara yang sangat baik.

Berikut ini adalah cara penulis CLRS menggunakan invarian loop untuk membuktikan kebenaran Penyisipan Sortir.

Algoritma Penyisipan Sortir (seperti yang diberikan dalam Buku):

INSERTION-SORT(A)
    for j ← 2 to length[A]
        do key ← A[j]
        // Insert A[j] into the sorted sequence A[1..j-1].
        i ← j - 1
        while i > 0 and A[i] > key
            do A[i + 1] ← A[i]
            i ← i - 1
        A[i + 1] ← key

Loop Invariant dalam hal ini: Sub-array [1 ke j-1] selalu diurutkan.

Sekarang mari kita periksa ini dan buktikan algoritma itu benar.

Inisialisasi : Sebelum iterasi pertama j = 2. Jadi sub-array [1: 1] adalah array yang akan diuji. Karena hanya memiliki satu elemen sehingga diurutkan. Dengan demikian invarian puas.

Pemeliharaan : Ini dapat dengan mudah diverifikasi dengan memeriksa invarian setelah setiap iterasi. Dalam hal ini puas.

Pengakhiran : Ini adalah langkah di mana kami akan membuktikan kebenaran dari algoritma.

Ketika loop berakhir maka nilai j = n + 1. Lagi-lagi loop invarian puas. Ini berarti Sub-array [1 ke n] harus disortir.

Inilah yang ingin kami lakukan dengan algoritma kami. Jadi algoritma kami benar.

Tushar Kathuria
sumber
1
Setuju ... pernyataan pengakhiran sangat penting di sini.
Gaurav Aradhye
18

Di samping semua jawaban yang baik, saya kira contoh yang bagus dari How to Think About Algorithms, oleh Jeff Edmonds dapat menggambarkan konsep dengan sangat baik:

CONTOH 1.2.1 "Algoritma Dua Jari Find-Max"

1) Spesifikasi: Sebuah instance input terdiri dari daftar L (1..n) elemen. Output terdiri dari indeks i sedemikian rupa sehingga L (i) memiliki nilai maksimum. Jika ada beberapa entri dengan nilai yang sama, maka salah satu dari mereka dikembalikan.

2) Langkah-langkah Dasar: Anda memutuskan metode dua jari. Jari kanan Anda berada di bawah daftar.

3) Ukuran Kemajuan: Ukuran kemajuan adalah seberapa jauh sepanjang daftar jari kanan Anda.

4) Loop Invariant: Loop invariant menyatakan bahwa jari kiri Anda menunjuk ke salah satu entri terbesar yang sejauh ini ditemui oleh jari kanan Anda.

5) Langkah Utama: Setiap iterasi, Anda gerakkan jari kanan Anda ke bawah satu entri dalam daftar. Jika jari kanan Anda sekarang menunjuk pada entri yang lebih besar dari entri jari kiri, maka gerakkan jari kiri Anda untuk berada dengan jari kanan Anda.

6) Lakukan Kemajuan: Anda membuat kemajuan karena jari kanan Anda bergerak satu entri.

7) Pertahankan Loop Invariant: Anda tahu bahwa loop invarian telah dipertahankan sebagai berikut. Untuk setiap langkah, elemen jari kiri baru adalah Max (elemen jari kiri lama, elemen baru). Dengan loop invarian, ini adalah Max (Max (daftar pendek), elemen baru). Secara matematis, ini Max (daftar lagi).

8) Membuat Loop Invariant: Anda awalnya membuat loop invarian dengan mengarahkan kedua jari ke elemen pertama.

9) Kondisi Keluar: Anda selesai ketika jari kanan Anda selesai melintasi daftar.

10) Berakhir: Pada akhirnya, kita tahu masalahnya diselesaikan sebagai berikut. Dengan kondisi keluar, jari kanan Anda telah menjumpai semua entri. Dengan loop invarian, jari kiri Anda menunjuk pada maksimumnya. Kembalikan entri ini.

11) Pemutusan dan Waktu Berlari: Waktu yang diperlukan adalah beberapa kali konstan dari panjang daftar.

12) Kasus Khusus: Periksa apa yang terjadi ketika ada beberapa entri dengan nilai yang sama atau ketika n = 0 atau n = 1.

13) Detail Pengkodean dan Implementasi: ...

14) Bukti Resmi: Kebenaran algoritma mengikuti dari langkah-langkah di atas.

Vahid Rafiei
sumber
Saya pikir jawaban ini benar-benar "meletakkan jarinya" pada intuisi intuisi dari seorang invarian :).
scanny
6

Perlu dicatat bahwa Loop Invariant dapat membantu dalam desain algoritma iteratif ketika dianggap sebagai pernyataan yang menyatakan hubungan penting antara variabel yang harus benar pada awal setiap iterasi dan ketika loop berakhir. Jika ini berlaku, perhitungan sedang menuju ke efektifitas. Jika salah, maka algoritme telah gagal.

Eric Steen
sumber
5

Invarian dalam hal ini berarti suatu kondisi yang harus benar pada titik tertentu dalam setiap iterasi loop.

Dalam pemrograman kontrak, invarian adalah suatu kondisi yang harus benar (berdasarkan kontrak) sebelum dan sesudah metode publik apa pun dipanggil.

Mark Rushakoff
sumber
4

Arti invarian tidak pernah berubah

Di sini loop invarian berarti "Perubahan yang terjadi pada variabel dalam loop (increment atau decrement) tidak mengubah kondisi loop yaitu kondisinya memuaskan" sehingga konsep loop invarian telah muncul

sasidhar
sumber
2

Properti Loop Invariant adalah kondisi yang berlaku untuk setiap langkah dari eksekusi loop (mis. Untuk loop, saat loop, dll.)

Ini sangat penting untuk Bukti Loop Invarian, di mana orang dapat menunjukkan bahwa suatu algoritma dieksekusi dengan benar jika pada setiap langkah pelaksanaannya properti invarian loop ini berlaku.

Agar suatu algoritma menjadi benar, Loop Invariant harus berlaku di:

Inisialisasi (awal)

Pemeliharaan (setiap langkah setelah)

Pengakhiran (saat selesai)

Ini digunakan untuk mengevaluasi banyak hal, tetapi contoh terbaik adalah algoritma serakah untuk grafik traversal berbobot. Untuk algoritma serakah untuk menghasilkan solusi optimal (jalur melintasi grafik), ia harus mencapai menghubungkan semua node di jalur bobot terendah yang mungkin.

Dengan demikian, properti loop invarian adalah bahwa jalur yang diambil memiliki bobot paling sedikit. Pada awalnya kami belum menambahkan tepi, jadi properti ini benar (dalam hal ini tidak salah). Pada setiap langkah , kita mengikuti batas bobot terendah (langkah serakah), jadi sekali lagi kita mengambil jalur bobot terendah. Pada akhirnya , kami telah menemukan jalur berbobot terendah, jadi properti kami juga benar.

Jika suatu algoritma tidak melakukan ini, kami dapat membuktikan bahwa itu tidak optimal.

Alex Mapley
sumber
1

Sulit untuk melacak apa yang terjadi dengan loop. Loop yang tidak berakhir atau berakhir tanpa mencapai perilaku tujuan mereka adalah masalah umum dalam pemrograman komputer. Loop invarian membantu. Loop invarian adalah pernyataan formal tentang hubungan antara variabel dalam program Anda yang berlaku tepat sebelum loop dijalankan (membuat invarian) dan benar lagi di bagian bawah loop, setiap kali melalui loop (mempertahankan invarian) ). Berikut adalah pola umum penggunaan Loop Invariants dalam kode Anda:

... // Loop Invariant harus benar di sini
while (TEST CONDITION) {
// bagian atas loop
...
// bagian bawah loop
// Loop Invariant harus benar di sini
}
// Termination + Loop Invariant = Sasaran
...
Di antara bagian atas dan bawah loop, kemungkinan headway dibuat untuk mencapai tujuan loop. Ini mungkin mengganggu (membuat salah) yang invarian. Inti dari Loop Invariants adalah janji bahwa invarian akan dipulihkan sebelum mengulangi loop body setiap kali. Ada dua keuntungan untuk ini:

Pekerjaan tidak diteruskan ke langkah selanjutnya dengan cara yang rumit dan tergantung data. Masing-masing melewati loop secara independen dari semua yang lain, dengan invarian melayani untuk mengikat pass bersama menjadi satu kesatuan yang berfungsi. Alasan bahwa loop Anda berfungsi dikurangi menjadi alasan bahwa loop invarian dikembalikan dengan setiap melewati loop. Ini memecah perilaku keseluruhan yang rumit dari loop menjadi langkah-langkah kecil yang sederhana, masing-masing yang dapat dianggap secara terpisah. Kondisi pengujian loop bukan bagian dari invarian. Inilah yang membuat loop berakhir. Anda mempertimbangkan secara terpisah dua hal: mengapa loop harus diakhiri, dan mengapa loop mencapai tujuannya ketika itu berakhir. Loop akan berakhir jika setiap kali melalui loop Anda bergerak lebih dekat untuk memenuhi kondisi terminasi. Seringkali mudah untuk memastikan ini: misalnya melangkah variabel counter dengan satu sampai mencapai batas atas yang tetap. Terkadang alasan di balik pemutusan hubungan kerja lebih sulit.

Loop invarian harus dibuat sehingga ketika kondisi terminasi tercapai, dan invarian benar, maka tujuannya tercapai:

invarian + termination => goal
Dibutuhkan latihan untuk membuat invarian yang sederhana dan berhubungan yang menangkap semua pencapaian tujuan kecuali untuk terminasi. Cara terbaik adalah menggunakan simbol matematika untuk mengekspresikan invarian loop, tetapi ketika ini mengarah pada situasi yang terlalu rumit, kita mengandalkan prosa yang jelas dan akal sehat.


sumber
1

Maaf saya tidak punya izin komentar.

@ Thomas Petricek seperti yang Anda sebutkan

Invarian lemah yang juga benar adalah bahwa i> = 0 && i <10 (karena ini adalah kondisi kelanjutan!) "

Bagaimana itu invarian loop?

Saya harap saya tidak salah, sejauh yang saya mengerti [1] , Loop invarian akan benar pada awal loop (Inisialisasi), itu akan benar sebelum dan setelah setiap iterasi (Pemeliharaan) dan itu juga akan menjadi benar setelah terminasi loop (Pengakhiran) . Tetapi setelah iterasi terakhir saya menjadi 10. Jadi, kondisi i> = 0 && i <10 menjadi salah dan mengakhiri loop. Itu melanggar properti ketiga (Pemutusan) dari invarian loop.

[1] http://www.win.tue.nl/~kbuchin/teaching/JBP030/notebooks/loop-invariants.html

Mahmudul Haque
sumber
Dugaan saya adalah bahwa ini benar karena loop tidak benar-benar mengeksekusi dalam kondisi tersebut.
muiiu
0

Loop invarian adalah rumus matematika seperti (x=y+1). Dalam contoh itu, xdan ymewakili dua variabel dalam satu lingkaran. Mempertimbangkan perubahan perilaku variabel-variabel tersebut selama eksekusi kode, hampir tidak mungkin untuk menguji semua kemungkinan xdan ynilai-nilai dan melihat apakah mereka menghasilkan bug. Katakanlah xadalah bilangan bulat. Integer dapat menampung ruang 32 bit dalam memori. Jika jumlah itu melebihi, terjadi buffer overflow. Jadi kita perlu memastikan bahwa selama eksekusi kode, tidak pernah melebihi ruang itu. untuk itu, kita perlu memahami formula umum yang menunjukkan hubungan antar variabel. Bagaimanapun, kami hanya mencoba memahami perilaku program.

Mehmet YILMAZ
sumber
0

Dengan kata sederhana, itu adalah kondisi LOOP yang benar dalam setiap iterasi loop:

for(int i=0; i<10; i++)
{ }

Dalam hal ini kita dapat mengatakan keadaan saya adalah i<10 and i>=0

i.maddy
sumber
0

Loop invarian adalah pernyataan yang benar sebelum dan sesudah eksekusi loop.

Timothy Makobu
sumber
-1

Dalam Pencarian Linier (sesuai dengan latihan yang diberikan dalam buku), kita perlu menemukan nilai V dalam array yang diberikan.

Ini sederhana seperti memindai array dari 0 <= k <panjang dan membandingkan setiap elemen. Jika V ditemukan, atau jika pemindaian mencapai panjang array, hentikan saja loopnya.

Sesuai pemahaman saya dalam masalah di atas-

Loop Invariants (Inisialisasi): V tidak ditemukan dalam iterasi k - 1. Iterasi pertama, ini adalah -1 maka kita dapat mengatakan V tidak ditemukan pada posisi -1

Maintainance: Dalam iterasi berikutnya, V tidak ditemukan dalam k-1 berlaku

Pengakhiran: Jika V ditemukan dalam posisi k atau k mencapai panjang array, akhiri loop.

AndroDev
sumber