เวียนบังเกิดและความสัมพันธ์ ตัวอย่าง ลำดับ S ถูกกำหนดอย่างวนซ้ำโดย 1. S(1) = 2 2. S(n) = 2S(n-1) สำหรับ n2 ในข้อความที่ 1 หรือ S(1) เป็นวัตถุชิ้นแรกในลำดับ S คือ 2 ส่วนข้อความที่ 2 เป็นวัตถุชิ้นที่ 2 ใน S คือ S(2) = 2S(2-1) = 2(2) = 4 และโดยข้อความที่ 2 เช่นกัน S(3) = 2S(3-1) = 2S(2) = 2(4) = 8 ส่วนวัตถุในลำดับถัดไปก็สามารถคำนวณได้ในลักษณะเดียวกัน เราจะเห็นว่าลำดับ S คือ 2, 4, 8, 16, 32, ... จากตัวอย่างเป็นการกำหนดค่าของลำดับด้วยเทอมหรือพจน์ก่อนหน้า ซึ่งถูกเรียกว่า “ความสัมพันธ์เวียนบังเกิด (Recurrence relation)”
ความสัมพันธ์เวียนบังเกิด นิยาม ความสัมพันธ์เวียนบังเกิดของลำดับ a0, a1, a2, ... คือสมการที่แสดงความสัมพันธ์พจน์ที่ n กับพจน์ที่อยู่ข้างหน้า จากตัวอย่าง S(n) = 2S(n-1) เมื่อกล่าวถึงผลเฉลยของความสัมพันธ์นี้จะหมายถึงฟังก์ชันที่อยู่ในรูป an = g(n) ซึ่งเป็นฟังก์ชันของ n และสอดคล้องกับความสัมพันธ์เวียนบังเกิดนั้นๆ
ฟังก์ชันเวียนบังเกิด จากนิยามฟังก์ชันเวียนบังเกิดมีสองขั้นตอน โดยฟังก์ชันนี้จะกำหนดบนเซตของจำนวนเต็มที่ไม่เป็นลบและโดเมนของฟังก์ชันคือ เงื่อนไขเบื้องต้น: กำหนดค่าของฟังก์ชันไว้ที่ศูนย์ การเวียนบังเกิด: เตรียมกฎสำหรับหาค่าของฟังก์ชันที่จำนวนเต็มใดๆจากค่าของฟังก์ชันด้วยจำนวนเต็มที่น้อยกว่า จะเห็นว่านิยามของฟังก์ชันเวียนบังเกิดมีรูปแบบเดียวกับการอุปนัย ตัวอย่างให้หาจำนวนฟิโบนักซี f2, f3, f4, และ f5 เมื่อ เงื่อนไขเบื้องต้น: f1=0 และ f1=1 การเวียนบังเกิด: fn = fn-1 + fn-2
เซตเวียนบังเกิด เซตก็สามารถกำหนดการเวียนบังเกิดได้เช่นเดียวกับฟังก์ชันและลำดับนั่นคือ เงื่อนไขเบื้องต้น: กำหนดกลุ่มเริ่มต้นของสมาชิก การเวียนบังเกิด: กฎของการสร้างสมาชิกใหม่ของเซตจากสมาชิกเดิม ในขั้นตอนของการเวียนบังเกิดที่ใช้สร้างสมาชิกใหม่ ในบางครั้งอาจจะต้องใช้กฎของการตัดออกตามความเหมาะสมของเงื่อนไข ตัวอย่าง พิจารณาเซตย่อย S ที่เป็นเซตของจำนวนเต็มที่กำหนดโดย เงื่อนไขเบื้องต้น: 3S การเวียนบังเกิด: if xS and yS, then x+yS สมาชิกใหม่ที่สร้างจากเงื่อนไขเบื้องต้นคือ 3+3=6 ตัวถัดไป 3+6=9ตัวถัดไป 3+9=6+6=12 และตัวอื่นๆ ก็กำหนดได้ตามขั้นของการเวียนบังเกิด
อัลกอริทึมเวียนบังเกิด การหาผลเฉลยของพจน์ที่ n ของลำดับ S(n) จากตัวอย่างที่แล้วสามารถหาได้สองวิธี การวนซ้ำในรูปแบบของคำสั่งลูปหรือวงวน (Loop) คำนวณ S(n) โดยใช้นิยามการเวียนบังเกิดของลำดับ S โดยตรง อัลกอริทึม 1 การแทนลำดับด้วยการวนซ้ำ int S(int n) /* เป็นการคำนวณแบบซ้ำๆของจำนวนเต็ม S(n) สำหรับลำดับ S ในตัวอย่างที่ 19 */ { int j; /* ดัชนีของวงวน */ int CurrentValue; /* ค่าปัจจุบัน */ if (n==1) S = 2; else { j = 2; CurrentValue = 2; while (j <= n) { CurrentValue = 2*CurrentValue; j = j + 1; } } S = CurrentValue; return S; เงื่อนไขเบื้องต้น วงวน while แทนการสมมุติฐาน อุปนัย
การแทนลำดับด้วยนิยามการเวียนบังเกิด นิยาม อัลกอริทึมที่ถูกเรียกว่าเป็นอัลกอริทึมเวียนบังเกิดถ้า อัลกอริทึมนั้นแก้ปัญหาโดยการลดขนาดของปัญหาให้เล็กลงด้วยอินพุตที่น้อยลงกว่าเดิม อัลกอริทึม 2 การแทนลำดับด้วยนิยามการเวียนบังเกิด int S_recursive(int n) { if (n == 1) S = 2; else S = 2*S_recursive(n-1); return S; }
อัลกอริทึมที่ 3 นิยามการคูณแบบเวียนบังเกิด int Product(int m, int n) { if (n==1) p = m; else p = Product(m, n-1) + m; return p; }
ศักยภาพของอัลกอริทึมการเวียนบังเกิด ความซับซ้อนของอัลกอริทึมเวียนบังเกิดเชิงเวลาส่วนใหญ่จะขึ้นอยู่กับจำนวนการเรียกซ้ำ (ซึ่งจะขึ้นอยู่กับจำนวนข้อมูล) อัลกอริทึมเวียนบังเกิดอ่านเข้าใจได้ง่ายกว่าการวนซ้ำด้วยการใช้วงวน อย่างไรก็ตาม จากการที่อัลกอริทึมเวียนบังเกิดขึ้นอยู่กับจำนวนข้อมูล เมื่อข้อมูลมีเป็นจำนวนมาก อัลกอริทึมนี้ก็จะใช้หน่วยความจำจำนวนมากตามข้อมูล เนื่องจากการเรียกตัวเองแต่ละครั้งก็จะมีการเก็บไว้ใน stack แต่ถ้ามีการออกแบบให้เหมาะสมอย่างอัลกอริทึมการค้นหาข้อมูลแบบทวิภาคต่อไปนี้ ก็จะช่วยเพิ่มศักยภาพของการเวียนบังเกิดได้
การแก้ปัญหาความสัมพันธ์เวียนบังเกิด เทคนิคอย่างหนึ่งที่ใช้ในการแก้ปัญหาความสัมพันธ์เวียนบังเกิดคือ การขยาย การคาดเดา และการตรวจสอบ วิธีที่ใช้เพื่อขยายพจน์ความสัมพันธ์เวียนบังเกิดอย่างซ้ำๆ จนสามารถคาดเดารูปแบบของพจน์ที่ n ได้ และสุดท้ายการคาดเดาก็จะถูกตรวจสอบความถูกต้องโดยอุปนัยทางคณิตศาสตร์ ตัวอย่าง การหาสูตรสำเร็จ (Closed-form solution) ของความสัมพันธ์เวียนบังเกิดต่อไปนี้
ตัวอย่างการหา Closed-Form Solution จากนิยามของความสัมพันธ์เวียนบังเกิดคือ ลำดับ S ของค่าใดๆ สามารถแทนได้โดยการคูณ S(n) กับ S(n-1) และเราใช้นิยามนี้กับค่า n, n-1, n-2,… นั่นคือ เมื่อพิจารณารูปแบบที่เกิดขึ้นจากการลองเปลี่ยนค่า n เราคาดเดาหลังจากขยายค่าไป k พจน์ ก็จะได้สมการที่อยู่ในรูป
ตัวอย่าง ...ต่อถึงการตรวจสอบ เมื่อการขยายพจน์นี้ไปเรื่อยๆ จนกระทั่งจำนวนพจน์ k มากพอที่จะทำให้ n–k = 1 นั่นคือ k = n – 1 ที่จุดนี้เราจะได้ว่า เราจะต้องยืนยันสูตรสำเร็จของเราโดยการอุปนัยในค่าของ n สำหรับเงื่อนไขเบื้องต้น S(1)=21 ซึ่งเป็นจริงด้วยสมการที่ (1) แล้วตั้งข้อสมมุติฐานว่า S(k)=2k ดังนั้น
รูปแบบทั่วไปของฟังก์ชันเวียนบังเกิด ความสัมพันธ์เวียนบังเกิดสำหรับลำดับ S(n) ที่เป็นเชิงเส้น ถ้าสัมประสิทธิ์ของ S ในนิยามมีเพียงตัวยกกำลังตัวแรก ความสัมพันธ์เวียนบังเกิดเชิงเส้นในรูปแบบทั่วไปจะอยู่ในรูป โดยที่ fi และ g เป็นพจน์ที่เกี่ยวข้องกับ n ความสัมพันธ์เวียนบังเกิดมีสัมประสิทธิ์เป็นค่าคงที่ถ้า fi ทุกเทอมเป็นค่าคงที่ และจะเป็นอันดับที่หนึ่งถ้าพจน์ที่ n มีเพียงพจน์ที่ n–1 ความสัมพันธ์เวียนบังเกิดอันดับที่หนึ่งที่เป็นเชิงเส้นและมีสัมประสิทธิ์เป็นค่าคงที่ก็จะลดรูปเหลือเพียง สุดท้ายความสัมพันธ์เวียนบังเกิดจะเป็นเอกพันธ์ (Homogeneous) ถ้า g(n) = 0 สำหรับ n ทุกตัว
Program Correctness What is Correctness? Correctness: partial correctness + termination Partial correctness: Program implements its specification
Proving Partial Correctness Goal: prove that program is partially correct Approach: model computation with predicates – Predicates are boolean functions over program state Simple example – {odd(x)} a = x {odd(a)} Generally: {P} S {Q}, where – P is a precondition – Q is a postcondition – S is a set of programming language statements
การตรวจสอบความถูกต้องของโปรแกรม นิยาม โปรแกรมหรือส่วนของโปรแกรม S ที่กล่าวได้ว่า “มีความถูกต้องเป็นบางส่วนเมื่อเทียบกับ (Partially Correct with respect to” ข้ออ้างเบื้องต้น (Initial Assertion: p) และข้ออ้างสุดท้าย (Final Assertion: q) เมื่อไร p เป็นจริงสำหรับค่าต่างๆ ของอินพุตที่จะประมวลเข้ากับข้อความ S จนสิ้นสุด จะทำให้ q เป็นจริงด้วย สัญลักษณ์ p{S}q จะแสดงว่าโปรแกรมหรือส่วนของโปรแกรม S มีความถูกต้องบางส่วนเมื่อเทียบกับข้ออ้างเบื้องต้น p กับข้ออ้างสุดท้าย q
ตัวอย่างการตรวจสอบความถูกต้อง ตัวอย่าง จงแสดงส่วนของโปรแกรม S y := 2 z := x + y มีความถูกต้องเมื่อเทียบกับข้ออ้างเบื้องต้น p:x=1 และข้ออ้างสุดท้าย q:z=3 วิธีทำ สมมุติว่า p เป็นจริงนั่นคือ x=1 (ค่าเริ่มต้น) เมื่อส่วนของโปรแกรม S เริ่มทำงาน y จะถูกกำหนดค่าให้เท่ากับ 2 และ z จะถูกกำหนดโดยผลรวมของ x และ y ซึ่งทำให้ z=3 เพราะฉะนั้นส่วนของโปรแกรม S จะมีความถูกต้องเมื่อเทียบกับข้ออ้างเบื้องต้นและข้ออ้างสุดท้ายที่อยู่ในรูป p{S}q เป็นจริง
กฎการอนุมาน เมื่อโปรแกรม S ถูกแบ่งออกเป็นโปรแกรมย่อย S1 และ S2 ที่เขียนอยู่ในรูป S = S1; S2 เพื่อแสดงว่า S ประกอบด้วยโปรแกรมย่อย S1 และตามด้วยโปรแกรมย่อย S2 สมมุติว่าความถูกต้องของ S1 เมื่อเทียบกับข้ออ้างเบื้องต้น p และข้ออ้างสุดท้าย q ส่วนความถูกต้องของ S2 เมื่อเทียบกับข้ออ้างเบื้องต้น q และข้ออ้างสุดท้าย r เมื่อเป็นเช่นนี้ถ้า p เป็นจริงและ S1 ถูกประมวลผลจนจบแล้ว q เป็นจริง และ q ที่เป็นจริงนี้ถูกส่งต่อให้ S2 ประมวลผลจนจบแล้ว r เป็นจริง การดำเนินการทั้งหมดนี้ถูกเรียกว่า “Composition Rule ที่เขียนอยู่ในรูป p{S1}q q{S2}r p{S1 ; S2}r
if Axiom Rule: P If B then S Q
ข้อความที่มีเงื่อนไข IF if condition then S ที่นำไปสู่กฎการอนุมานที่อยู่ในรูป (p condition){S}q (p condition ) q p { if condition then S} q ตัวอย่าง จงตรวจสอบ if x>y then y := x ว่ามีความถูกต้องเมื่อเทียบกับข้ออ้างเบื้องต้น T และข้ออ้างสุดท้าย y x
IF-ELSE if condition then S1 else S2 ที่นำไปสู่กฎการอนุมานที่อยู่ในรูป (P condition){S1}Q (P condition ) {S2} Q P { if condition then S1 else S2} Q
IF-ELES ตัวอย่าง จงตรวจสอบ if x<0 then abs := -x else abs := x ว่ามีความถูกต้องเมื่อเทียบกับข้ออ้างเบื้องต้น T และข้ออ้างสุดท้าย abs = |x|
If-else (ต่อ) Then part: need to show Example: Else part: need to show {P ∧ (x<0)} x=-x;y=x {y = |x|} {x = |x|} y = x {y = |x|} {-x = |x|} x = -x {x = |x|} ( P ∧ x <0) ⇒ -x = |x| Else part: need to show {P ∧ ¬ (x<0)} y=x {y = |x|} {x =|x|} y=x {y=|x|} ( P ∧ ¬(x < 0)) ⇒ x = |x| P ≡ true Example: 1. if x < 0 then { 2. x = -x; 3. y = x 4. } else { 5. y = x 6. } {y = |x|}
Loop Invariants while condition S ที่มีกฎการอนุมานอยู่ในรูป (p condition){S}p p { while condition S} (condition p)
ตัวอย่าง i:=1 factorial := 1 while i<n i := i+1 factorial := factorial*i end จบด้วย factorial = n! เมื่อ n เป็นจำนวนเต็มบวก
ตัวอย่าง ให้ตรวจสอบความถูกต้องของโปรแกรม S ที่ใช้คำนวณผลคูณของจำนวนเต็มบวก จุดประสงค์คือเพื่อพิสูจน์ว่าหลังจากโปรแกรม S ถูกประมวลผลแล้วจะได้ product มีค่าเป็น mn การพิสูจน์ความถูกต้องทำได้โดยการแบ่งโปรแกรม S ออกเป็น S = S1; S2; S3; S4