על כדורים שטוחים וחצאי הרים

יש אנשים שאם מביאים להם כדור, נאמר כדור הארץ, מייד מתחילים להגיד שלא! זה שטוח! זה מישור! כי הנה, תראו, אני עומד על הכדור, ואני מסתכל לכל הכיוונים, ולכל אשר אני מסתכל, הכל שטוח! אז זה מישור! לא כדור!

לאנשים הללו קוראים "מתמטיקאים" ומה שהם מתארים פה הוא את המושג של יריעה שהוא אחד המושגים החשובים במתמטיקה. יריעה היא מרחב שיכול להיות מאוד מסובך מבחינת המבנה הגאומטרי שלו (למשל – כדור), אבל באופן מקומי, כשאני נעמד באיזו שהיא נקודה של המרחב ומסתכל מסביבי (אחרי שוידאתי שאני מוריד משקפיים והראייה שלי ממש לא משהו) מה שמסביב נראה לי פחות או יותר כמו מישור (באופן כללי יותר – כמו מרחב אוקלידי, אבל נעזוב את זה).

יריעה היא מושג מגניב מכיוון ש… אה, רגע, רגע, מודיעים לי שעוד לא הגיע הזמן לפוסט על יריעות והכוונה בפוסט הזה היא בכלל לדבר על אנשים שמביאים להם את כדור הארץ והם אומרים שלא! זה שטוח! זה מישור! אבל שמתכוונים לזה בשיא הרצינות ולא בצורה מתמטית. ולא בגלל שהם חובבי טרי פראצ'ט.

על פניו, זה עשוי להישמע לכם מוזר. הרי את העובדה שהארץ אינה שטוחה ידעו עוד משחר ההיסטוריה. ידוע במיוחד ארטוסתנס היווני שחישב את רדיוס כדור הארץ ברמת דיוק יפה מאוד לזמנו בדרך מחוכמת ויפה שראויה לפוסט בבלוג, מתישהו. הנימוקים לכך שהארץ אינה שטוחה הם רבים ומגוונים, אבל הטובים ביותר נוגעים בכלל לשמש ולירח – הצל שהארץ מטילה על הירח, למשל, או העובדה שאם הארץ הייתה שטוחה השמש הייתה צריכה להאיר את כל היבשות בו זמנית, וכדומה. בימינו המודרניים גם יש לנו תמונות לווין של הארץ שלא ממש משאירות מקום לספק באשר לצורתה. הנה מאמר נחמד שמסכם כמה מהגישות אם אתם סקרנים.

ועדיין, אנשים שמאמינים בכל ליבם שהארץ שטוחה ושכל העדויות הן שקרים וטעויות קיימים ופעילים וכנראה יהיו פעילים לעד. הנה, ממש עכשיו העניין קפץ שוב לכותרות עם איזה ראפר שהתחיל להפיץ בטוויטר שלל שטויות הקשורות לנושא. והטריגר לפוסט הוא אחת מהן. הנה היא:

CZkrOKqUAAA8wSH

אז מה יש לנו פה? תמונה יפה שבה אנחנו רואים את ההר הגבוה באמריקה הצפונית – הר דנאלי (שבעבר נקרא גם הר מקינלי) כפי שהוא נראה מהעיר אנקורג' באלסקה, ועוד כמה נתונים מספריים, ועוד טענה שיש כאן סתירה כלשהי. הסתירה נובעת לכאורה מכך שאם כדור הארץ הוא עגול, אז עצמים מרוחקים אמורים להיות מוסתרים בחלקם התחתון. זו הסיבה, למשל, לכך שאם אנחנו רואים ספינה מגיעה מהאופק, קודם כל נראה את התורן שלה ורק אחרי שתתקרב קצת נראה את כולה (זו הייתה אחת האבחנות עוד מימי קדם).

האם אכן יש כאן בעיה? אני לא יודע. אני בקושי מצליח להבין מה רואים בתמונה. רואים הר, אבל האם רואים את כל ההר? אין לי מושג, לי אישית לא נראה שרואים את כולו. ונניח שרואים את כולו, האם זו בעיה? החישוב שהם ביצעו שם ומניב את ה-9,220 מתבסס על ההנחה שכדור הארץ הוא, ובכן, כדור, אבל במציאות הוא לא כדור – הצורה שלו פחוסה יותר באיזורי הקטבים (אלסקה קרובה לקוטב הצפוני) ופרט לכך הוא כמובן מלא שקעים ובליטות, ושקע בכדור הארץ מאפשר לנו לראות יותר כי אין מה שיסתיר. בקיצור, אין לי משהו מעניין לומר על התמונה הזו מלבד זאת שאני לא הייתי ממהר לחשוב עליה בתור "הפרכה" לטענה שכדור הארץ אינו שטוח. אז למה התמונה מעניינת אותי? כי היא עשתה לי חשק לחשב בעצמי כמה מההר אמור להיות מוסתר (כמובן שיש מחשבוני אינטרנט שעושים זאת, אבל גיליתי אותם רק אחר כך). מה שנחמד בחישוב הזה הוא שגם תלמיד תיכון שלמד טריגונומטריה יכול לעשות אותו – כלומר, אנחנו רואים פה שימוש אמיתי למתמטיקה תיכונית!

כמובן, אני לא רוצה שתתלהבו יותר מדי – כמו רוב מה שאנחנו עושים במתמטיקה, החישוב הזה יניח את ההנחה האידאלית והלא נכונה שכדור הארץ הוא כדור מושלם. כפי שאמרתי קודם, זה לא המצב בפועל, ולכן תוצאת החישוב שלי לא תהיה נכונה. היא ככל הנראה תהיה קירוב טוב למה שנכון, אבל אין לי יכולת להעריך את גודל השגיאה. לכן מה שאני אעשה מכאן והלאה יהיה יותר משחק מתמטי מאשר טענה עובדתית רצינית.

ראשית כל, בואו נצייר תמונה של מה שאנחנו מנסים לתאר פה. כדור הארץ הוא אמנם אובייקט תלת ממדי, אבל כל עוד אני מתעניין רק במיקום שלי ובמיקום של אובייקט אחר על כדור הארץ מספיק לחשוב רק על מישור דו ממדי – זה שבו נמצא הישר שמחבר ביני ובין האובייקט הזה. לכן אני אצייר את כדור הארץ בתור מעגל:

flat_earth1

מה הולך כאן? הנקודה האדומה זה אני, הצופה, שנמצא בגובה כלשהו שנסמן \(a\) מעל פני כדור הארץ. אני מביט אל "הר" שמתואר כאן בתור קו זהוב, וציירתי שתי קרניים – את זו שנעה בכיוון מאוזן (מבחינתי) ואת זו שפוגשת את האופק, דהיינו משיקה למעגל שהוא כדור הארץ. כל קטן נמוכה יותר ממנה "תתקע" בכדור הארץ ולא תעבור אותו. הציור הזה מעלה מספר שאלות: ראשית, מה המרחק עד האופק? המרחק הזה יהיה מן הסתם תלוי בגובה שלי, והנה למדנו משהו – ככל שאנחנו גבוהים יותר מעל פני השטח של כדור הארץ, כך אנחנו רואים רחוק יותר. ולא בגלל שחפצים על הקרקע הסתירו לנו או שיש לנו עיניים לא משהו – ככל שאנחנו גבוהים יותר, כך קרני אור שמתקדמות בקו ישר מגיעות אלינו מעוד מקומות על פני כדור הארץ.

אבל השאלה המעניינת באמת היא מה קורה מעבר לאופק. אני כבר לא יכול לראות את פני כדור הארץ, אבל עצם כמו הר, שמתנשא מעל פני כדור הארץ, אני אראה, חלקית – והשאלה היא איזה חלק יוסתר. התשובה לשאלה הזו תלויה במרחק שלי מהעצם, כמו שמתואר עם הר דנאלי; אבל מה זה בעצם ה"מרחק" כאן? אפשר למדוד את המרחק על פני כדור הארץ – את אורך הקשת שמפרידה בין הנקודה על פני הכדור שמתחתי ובין הבסיס של ההר; ואפשר גם למדוד מרחק אווירי ממני עד להר בכיוון שהוא מבחינתי המאוזן. לדעתי הכוונה המתבקשת היא להגדרה הראשונה, ובה אטפל בפוסט הזה; אבל אפשר לטפל בשתיהן.

flat_earth2

בואו נתחיל עם שאלת המרחק מהאופק. לצורך כך אני אשתמש במה שידוע לנו על גאומטריה אוקלידית של מעגלים, ובבניית עזר פשוטה: אני אעביר שני רדיוסים של המעגל מתוך מרכזו – האחד אל הנקודה על פני השטח שאני נמצא מעליה, והשניה אל הנקודה שבה הקו המשיק לאופק שלי נוגע בכדור הארץ. הגאומטריה האוקלידית יודעת ש"רדיוס מאונך למשיק בנקודת ההשקה", ולכן קיבלנו משולש ישר זווית שאורך היתר שלו הוא \(R+a\) ואילו אורכי הניצבים הם \(R\) ו-\(x\), כאשר \(x\) הוא המרחק אל האופק שאני מחפש. עכשיו נכנס לתמונה משפט פיתגורס שאומר שריבוע היתר במשולש ישר זווית שווה לסכום ריבועי הניצבים, ואומר לנו ש-\(\left(R+a\right)^{2}=R^{2}+x^{2}\), ולכן קיבלנו ש-\(x=\sqrt{a^{2}+2Ra}\).

בואו נחשב מה זה אומר על הר דנאלי, כלומר נציב את הנתונים בתמונה שלהם. אצלם \(a=102\), אבל 102 מה? כאן צריך להתחשב ביחידות האורך שלהם. ואלו, באופן מצער, יחידות מדידה אמריקאיות מופרעות. לא נורא – גיגול קצר נותן לנו את הקבועים שבהם צריך לכפול את המספרים כדי לקבל אורך בקילומטרים. עכשיו נשאר רק לפתוח מחשבון, או במקרה שלי, את Sage:

sage: f_to_k = 0.0003048
sage: m_to_k = 1.60934<br />sage: a = 102*f_to_k
sage: S = 25000 * m_to_k
sage: S 40233.5000000000<br />sage: R = S / (2*pi)
sage: x= sqrt(a^2+2*R*a)
sage: x.n()
19.9538666359798

קיבלנו שמהגובה של אנקורג', שהוא בערך 30 מטרים מעל פני הים, קו האופק הוא במרחק 20 ק"מ, בזמן שההר הוא במרחק 210 ק"מ, כך שכמובן שלא יוכלו לראות את כולו אלא אם הארץ שטוחה (דם דם דם דם דרמטי!). בואו נשווה את זה עם משהו שאני מכיר – הר טללים בחיפה, שעליו נמצאת אוניברסיטת חיפה, כולל נקודת תצפית יפה שממנה ניתן לראות בקלות את עכו (השטוחה) ואת החרמון (שהוא הר) ובימים טובים גם את ראש הנקרה (שהיא הנקודה הצפונית ביותר במישור החוף בישראל והרחוקה ביותר שאני עוד מצליח לזהות בעין). מה המרחקים כאן? ראשית, הר טללים הוא בגובה 470 מטרים מעל גובה פני הים, ולכן אם נחזור על החישוב של קודם נקבל:

sage: a = 0.47 
sage: x = sqrt(a^2+2*R*a) 
sage: x.n() 
77.5846613623756

כלומר, אפשר לראות כמעט למרחק של 78 ק"מ. המרחק מהאוניברסיטה לעכו הוא בקושי 18 ק"מ. המרחק עד ראש הנקרה הוא 55.6 ק"מ, אז בכך שאני מסוגל לראות עד לשם אין קסם. ניסוי מעניין יותר יהיה לרדת באופן הדרגתי בגובה נקודות התצפית שלנו בחיפה ולראות מתי אנחנו כבר לא מצליחים לראות את ראש הנקרה יותר. למעשה, באופן תיאורטי היה אפשר לראות אפילו עד הכנרת (67 ק"מ), אבל יש הרים שמסתירים. תל אביב (בערך 80 ק"מ) כבר בלתי נראית, וטוב שכך!

בואו נעבור לחישוב המעניין יותר – כמה מההר מוסתר. לשם כך אשתמש בבניית עזר של עוד רדיוס – הפעם כזה שממשיך את ההר "פנימה" לתוך כדור הארץ:

flat_earth3

סימנתי ב-\(b\) רק את החלק מההר שמוסתר. קיבלנו משולש שמורכב משני הרדיוסים וההמשכים שלהם, ועוד הקו המשיק. המשולש הזה מחולק לשני משולשים קטנים יותר, ישרי זווית, עם אורכי יתר שהם \(R+a\) ו-\(R+b\), וניצב אחד שהוא באורך \(R\). זה נותן לנו את הזהויות הבאות, עבור הזוויות \(\alpha,\beta\) שמופיעות שם:

\(\cos\alpha=\frac{R}{R+a}\)

\(\cos\beta=\frac{R}{R+b}\)

עכשיו, את \(a\) אנחנו יודעים, ולכן את \(\alpha\); אבל את \(b\) אנחנו מחפשים, ולכן אנחנו רוצים לקבל את \(\beta\) בדרך אחרת ואז להשתמש בכך ש-\(b=\frac{R}{\cos\beta}-R\). למזלנו, אנחנו יודעים מהו \(\alpha+\beta\) כי ידוע לנו מה המרחק בין אנקורג' להר דנאלי. בואו נסמן את המרחק הזה ב-\(d\). זה אורך קשת כלשהו של המעגל, כשאורך הקשת כולה הוא \(S\). זה אומר שהחלק היחסי שהקשת הזו תופסת מכלל המעגל הוא \(\frac{d}{S}\). הזווית שתיווצר על ידי הקשת הזו תהיה, אם כן, בעלת אותו יחס אל הזווית הכוללת של המעגל, שהיא \(2\pi\) (אנחנו מודדים זוויות ברדיאנים כאן). במילים אחרות, \(\frac{\alpha+\beta}{2\pi}=\frac{d}{S}\), או \(\beta=\frac{2\pi d}{S}-\alpha\). בואו נבצע כעת את החישובים:

sage: d = 130*m_to_k 
sage: alpha = acos(R / (R+a)) 
sage: beta = ((2*pi*d) / S) - alpha 
sage: b = (R / cos(beta)) - R 
sage: b.n() 
2.79794815830519

קיבלנו גובה של 2.8 ק"מ. כמה זה ברגליים? 9180 רגל בערך. שזה… אה… קצת שונה מה-9,220 שלהם. לא בצורה משמעותית, אבל זה גורם לי לתהות מה הם עשו שונה. אני מניח שהם השתמשו במחשבון רשת כלשהו, אבל חשבתי שכולם פועלים בדיוק על פי אותם עקרונות. יש לכם רעיונות?

מכל מקום, האם הגענו לסתירה כלשהי בכדור הארץ או ביקום בכלל? כאמור, לא. גם בגלל שתוצאות החישוב לאו דווקא תקפות עבור הטופוגרפיה של האיזור הזה באלסקה, וגם בגלל שמי בכלל מבין מה רואים בתמונה הזו וכמה מההר מוסתר. אז בשביל מה זה היה טוב? כדי להראות שטריגונומטריה יכולה להיות מגניבה לפעמים, כמובן.

החלפת משתנים בחשבון דיפרנציאלי ואינטגרלי ("שיטת ההצבה")

היעד הנוכחי של סדרת הפוסטים שלי על אנליזה וקטורית הוא משפט כבד למדי – משפט החלפת המשתנים. אבל לפני שנצלול למעמקים הטכניים שלו, בואו נחזור לרגע לחדו"א של משתנה יחיד ונדבר על איך משפט החלפת המשתנים נראה שם, גם כי זה נותן לנו נקודת אחיזה למשפט הכללי והמסובך יותר, וגם כי מעולם לא כתבתי על המשפט הבסיסי פוסט והגיע הזמן. במשתנה יחיד הניסוח של המשפט פשוט וההוכחה פשוטה (יחסית) גם כן, כך שזהו מבוא מוצלח.

אבל לפני שנדבר על חדו"א, בואו ננסה להבין מה זו בכלל "החלפת משתנים" עם דוגמה יותר פשוטה – משוואות פולינומיות. בואו נסתכל במשוואה \(x^{4}-5x^{2}+4=0\) – מה הפתרונות שלה? איך מוצאים אותם? ובכן, יש נוסחה לפתרון משוואות ממעלה ארבע, אבל היא מסובכת מאוד. האם יש דרך יותר פשוטה? ובכן, שימו לב שבמשוואה הזו מופיעות רק חזקות זוגיות של \(x\) – החזקות 4, 2 ו-0. זה אומר לנו שבעצם יש פה משוואה ריבועית ב"תחפושת". כדי להוריד את התחפושת, אנחנו מבצעים החלפת משתנים: מגדירים משתנה חדש, \(t\), כך ש-\(t=x^{2}\), ואז המשוואה לעיל הופכת להיות המשוואה \(t^{2}-5t+4=0\) שקל לפתור בדרכים סטנדרטיות לפתרון משוואה ריבועית (נוסחת השורשים או טרינום). מקבלים שהפתרונות הם \(t=1,4\). מכאן קל לקבל פתרונות למשוואה המקורית: מכיוון ש-\(t=x^{2}\) קיבלנו שהמשוואות \(x^{2}=1\) ו- \(x^{2}=4\) נותנות פתרונות למשוואה המקורית, ובסך הכל נקבל שלמשוואה המקורית יש ארבעה פתרונות: \(x=1,-1,2,-2\).

אם כן, מהי בעצם החלפת משתנים? אנחנו מנסים לפשט ביטוי כלשהו על ידי כך שאנחנו מגדירים משתנה חדש, שהוא פונקציה של המשתנה הישן. בואו נחדד את זה על ידי כך שנעבור לטרמינולוגיה של חדו"א, שמשתמשת בפונקציות. ראשית כל הייתה לנו פונקציה \(h\left(x\right)=x^{4}-5x^{2}+4\) וביקשו מאיתנו לפתור את המשוואה \(h\left(x\right)=0\). זה היה קשה, אבל אז שמנו לב לכך שאפשר לחשוב על \(h\) בתור הרכבה של שתי פונקציות פשוטות יותר: \(f\left(t\right)=t^{2}-5t+4\) ו-\(g\left(x\right)=x^{2}\). דהיינו, קיבלנו ש-\(h\left(x\right)=f\left(g\left(x\right)\right)\), או בסימון מקובל אחר, \(h=f\circ g\). כעת השתמשנו בכך שיותר קל לנו לפתור משוואות שמערבות את \(f,g\) בנפרד כדי לפתור את המשוואה המקורית עבור \(h\).

בואו נעבור עכשיו לדוגמה שקשורה לאינטגרלים לא מסויימים. ראשית כל נזכיר לכם אינטגרל אחד נחמד שאנחנו יודעים לפתור יפה: \(\int\frac{1}{x}dx\). האינטגרל הזה שווה ל-\(\ln x+C\) (לא ניכנס עכשיו להסבר מדוע). עכשיו בואו נסתכל על אינטגרל דומה: \(\int\frac{1}{1-x}dx\). למה הוא שווה? האינטואיציה היא שאפשר לבצע פה החלפת משתנים: להגדיר משתנה חדש \(y=1-x\) ואז לקבל את האינטגרל \(\int\frac{1}{y}dy\), לבצע את האינטגרציה ולקבל \(\ln y+C\), ואז להציב מחדש את המשתנה ולקבל \(\ln\left(1-x\right)+C\). ואיך נבדוק את עצמנו? נגזור: אחרי גזירה מקבלים \(\frac{1}{1-x}\cdot\left(1-x\right)^{\prime}=\frac{1}{1-x}\cdot\left(-1\right)=-\frac{1}{1-x}\). אוקיי, משהו לא עבד פה. קיבלנו מינוס של התוצאה הנכונה.

עוד לא השתכנעתם שיש פה בעיה? אז שימו לב שאפשר היה לנקוט באותו תעלול גם עבור \(\int\frac{1}{1+x^{2}}dx\) ולקבל את ה"פתרון" \(\ln\left(1+x^{2}\right)+C\). אבל הפתרון הזה בבירור לא נכון, כי הנגזרת יוצאת בכלל \(\frac{2x}{1+x^{2}}\), ואם אתם זוכרים קצת אינטגרציה אתם זוכרים ש-\(\int\frac{1}{1+x^{2}}dx=\arctan x+C\). וזו פונקציה שונה לגמרי. בקיצור, משהו פה משתבש (וזה לא מפתיע; הרי לא הוכחתי עד עכשיו כלום, אני סתם הולך לפי אינטואיציה עיוורת). התחושה היא שמה שמשתבש הוא שחסר לי בביטוי המקורי את הנגזרת של הביטוי שאני מחליף – זה מסביר את המינוס 1 במקרה הראשון (הנגזרת של \(1-x\)) ואת ה-\(2x\) במקרה השני (הנגזרת של \(1+x^{2}\)). משפט החלפת המשתנים בחדו"א הוא בדיוק מה שמקבלים כשמתחשבים גם בעניין הזה.

הנה דוגמת צעצוע שבה הנגזרת של הביטוי הפנימי יוצאת 1 ולכן אין צורך בתיקון: \(\int\frac{1}{2+x}dx\). במקרה הזה נגדיר \(y=2+x\) ואכן נקבל בסופו של דבר \(\ln\left(2+x\right)+C\) בתור הפתרון. אבל גם במקרה הזה עדיין יש בעיה אחרת שצריך להתחשב בה וצצה כשאנחנו מנסים לחשב אינטגרל מסויים (כלומר, אינטגרל שבו יש גבולות אינטגרציה ואנחנו מחפשים את ערך האינטגרל ביניהם, ולא אינטגרל שבו אנחנו מחפשים פונקציה קדומה). נניח שאנחנו מחשבים את \(\int_{-1}^{1}\frac{1}{2+x}dx\). בבירור אין שום בעיה עם האינטגרל הזה, כי כאשר \(x\) רץ ממינוס 1 אל 1, הביטוי \(2+x\) רץ מ-1 אל 3, ולכן \(\frac{1}{2+x}\) מוגדר בכל הקטע \(\left[-1,1\right]\). לעומת זאת, אם נבצע "סתם" החלפת משתנה \(y=2+x\) נקבל את האינטגרל \(\int_{-1}^{1}\frac{1}{y}dy\) שהוא כמובן בעייתי כי עבור \(y=0\) שממש באמצע הקטע \(\left[-1,1\right]\) נקבל ביטוי לא מוגדר (וזו לא בעיה נקודתית; האינגטרל "מתפוצץ" סביב הנקודה הזו). אם כן, כשמבצעים החלפת משתנים באינטגרל מסויים, גם גבולות האינטגרציה צריכים להשתנות בהתאם.

עכשיו משברור לנו מה שני ה"תיקונים" שצריך לעשות (כפל בנגזרת של מה שמחליפים, ותיקון גבולות אינטגרציה בהתאם) אפשר ממש לנסות ולחפש את הניסוח המדויק של משפט החלפת המשתנים באופן עצמאי, אבל זה קצת מעייף, אז אני פשוט אביא את הניסוח הנקי:

בהינתן פונקציה \(g:\left[a,b\right]\to\mathbb{R}\) (זו הפונקציה שמבצעת את "החלפת המשתנים") שהיא ב-\(C^{1}\) (כלומר – גזירה, והנגזרת רציפה) ו-\(g^{\prime}\left(x\right)\ne0\) לכל \(x\in\left(a,b\right)\), ובהינתן פונקציה \(f\) רציפה שמוגדרת על התמונה של \(g\), מתקיים:

\(\int_{g\left(a\right)}^{g\left(b\right)}f\left(y\right)dy=\int_{a}^{b}\left(f\circ g\right)\left(x\right)g^{\prime}\left(x\right)dx\)

בכתיב טיפה יותר חסכוני:

\(\int_{g\left(a\right)}^{g\left(b\right)}fdy=\int_{a}^{b}\left(f\circ g\right)g^{\prime}dx\)

ואם נסמן \(I=\left[a,b\right]\) ו-\(J=g\left(I\right)\) ונוותר על ה-\(dx\)-ים, כפי שעשינו עם הגדרת האינטגרל הכללי באנליזה וקטורית, אפילו אפשר לכתוב

\(\int_{J}f=\int_{I}\left(f\circ g\right)\left|g^{\prime}\right|\)

כאשר הערך המוחלט צץ לו כדי לקזז את העובדה שעכשיו אין לנו גבולות אינטגרציה עליונים ותחתונים אלא פשוט אינטגרציה על קטע; אסביר את זה עוד מעט. ראשית כל בואו נוכיח את המשפט הזה.

זה שעשוע נחמד לחשוב מאיפה צצו כל ההנחות המוזרות של המשפט, עם ה-\(C^{1}\) וכאלה (טוב, יש עוד שעשועים נחמדים כמו לנסוע ברכבת הרים וכדומה, אבל אני מניח שאם שרדתם עד פה גם מבחינתכם זה שעשוע נחמד). אין כאן משהו מסובך במיוחד – ראשית, אנחנו רוצים ש-\(g\) תהיה מונוטונית עולה או יורדת בכל \(I=\left[a,b\right]\), כך שהיא בפרט תהיה חד חד ערכית על הקטע הזה. מכיוון ש-\(g^{\prime}\left(x\right)\ne0\) בתוך הקטע, בשילוב עם העובדה ש-\(g^{\prime}\) רציפה, נקבל שלא ייתכן ש-\(g^{\prime}\) מחליפה סימן בתוך הקטע (אם הייתה מחליפה סימן, אז על פי משפט ערך הביניים היא הייתה מתאפסת בתוך הקטע). עכשיו, אם \(g\) היא פונקציה יורדת, זה אומר ש-\(g\left(a\right)>g\left(b\right)\), אז בואו ניזכר מה זה אומר מבחינת הסימון \(\int_{g\left(a\right)}^{g\left(b\right)}f\); המוסכמה היא שאם באינטגרל הגבול העליון קטן מהגבול התחתון, הוא שווה למינוס האינטגרל עם הגבולות "בסדר הנכון", כלומר \(\int_{g\left(a\right)}^{g\left(b\right)}f=-\int_{g\left(b\right)}^{g\left(a\right)}f\). זו בסך הכל מוסכמת סימון, לא יותר מכך. בלעדיה הייתי צריך להגיד יותר פעמים "נפריד למקרים". זה גם מסביר את הערך המוחלט בניסוח השני של המשפט – \(\int_{J}f\) מניח תמיד שהגבולות ב-\(J\) הם "בסדר הנכון" ולכן אם \(g\) יורדת, כלומר אם \(g^{\prime}\) שלילית, מקזזים את המינוס החסר באגף שמאל על ידי כך שמוחקים אותו גם מאגף ימין – זו המשמעות היחידה של הערך המוחלט על \(g^{\prime}\).

טוב ויפה, אבל איך מוכיחים את המשפט? ובכן, משתמשים בתותח כבד – במשפט היסודי של החדו"א. בואו ניזכר מה המשפט אומר (בגרסה קצת פחות כללית ממה שאפשר לסחוט): אם \(f\) היא פונקציה רציפה על הקטע \(\left[ c,d\right]\) אז ניתן להגדיר פונקציה \(F\left(x\right)=\int_{c}^{x}f\left(t\right)dt\), ונקבל ש-\(F\) גזירה ומתקיים \(F^{\prime}\left(x\right)=f\left(x\right)\) לכל \(x\in\left[ c,d\right]\). אם תזכרו, נובע מכך די בקלות ש-\(\int_{c}^{d}f\left(x\right)dx=F\left(d\right)-F\left(c\right)\).

עכשיו נשתמש בטריק שאפשר להמציא עם קצת הינדוס לאחור: נגדיר \(H\left(x\right)=F\left(g\left(x\right)\right)\), ונגזור באמצעות כלל השרשרת. נקבל ש-\(H^{\prime}\left(x\right)=F^{\prime}\left(g\left(x\right)\right)g^{\prime}\left(x\right)=f\left(g\left(x\right)\right)g^{\prime}\left(x\right)\). דהיינו, מצאנו את הפונקציה הקדומה של כל הביטוי \(\left(f\circ g\right)g^{\prime}\), מה שמאפשר לנו להשתמש במשפט היסודי של החדו"א פעמיים כדי לקבל את השוויון שרצינו:

\(\int_{a}^{b}\left(f\circ g\right)\left(x\right)g^{\prime}\left(x\right)dx=\int_{a}^{b}H^{\prime}\left(x\right)dx=H\left(b\right)-H\left(a\right)=F\left(g\left(b\right)\right)-F\left(g\left(a\right)\right)=\int_{g\left(a\right)}^{g\left(b\right)}f\left(y\right)dy\)

זה מסיים את ההוכחה, אבל לפני שנסיים את הפוסט, בואו נראה כמה שימושים של העסק הזה כדי שלא נהיה לחלוטין באוויר. מה שכדאי לזכור כשבאים להשתמש בהחלפת משתנים בפועל הוא שאפשר להשתמש במשפט בשני הכיוונים שלו. באחד מהם אנחנו לוקחים ביטוי מסובך שמופיע בתוך האינטגרל ומחליפים אותו במשתנה חדש, אבל כדי שהקסם הזה יעבוד אנחנו חייבים שהביטוי הזה יכלול גם את הנגזרת של מה שהמשתנה בא לייצג לבסוף – כלומר, צריך לזהות תבניות מאוד ספציפיות. בכיוון השני אנחנו פשוט מחליפים את \(x\) בביטוי מורכב יותר וה"עונש" שאנחנו משלמים על כך הוא שאנחנו צריכים לכפול בנגזרת של הביטוי המורכב הזה.

אני אתחיל דווקא עם דוגמה עבור הכיוון השני, כי טרם ראינו אותו בפעולה. בואו נחשב את האינטגרל \(\int_{0}^{1}\sqrt{1-x^{2}}dx\). זה נראה כמו אינטגרל מזעזע כי יש שם שורש ועניינים. אז משתמשים בתעלול מהסוג שכולנו אוהבים במתמטיקה – מכניסים מושג מתחום לכאורה לא קשור, שמפשט לנו את הבעיה. במקרה שלנו, טריגונומטריה. הזהות הבסיסית ביותר בטריגונומטריה היא \(\sin^{2}\alpha+\cos^{2}\alpha=1\) (זה נובע ישירות ממשפט פיתגורס), ודרך אחרת לחשוב על זה היא בתור \(\sin\alpha=\pm\sqrt{1-\cos^{2}\alpha}\), שכבר נראה כמו הביטוי שאצלנו. אז נשתמש בהצבה שמחליפה את \(x\) בפונקציה טריגונומטרית; לטכניקה הזו קוראים "הצבה טריגונומטרית" והיא יעילה למדי בחישוב כל מני אינטגרלים שנראים אבודים.

במקרה הזה, \(f\left(x\right)=\sqrt{1-x^{2}}\) ואנחנו משתמשים ב-\(g\left(y\right)=\cos y\) כדי לעבור מ-\(\int f\left(x\right)dx\) אל \(\int f\left(g\left(y\right)\right)g^{\prime}\left(y\right)dy\). יש דרך ציורית לזכור את מה שמבצעים כאן – הביטו בביטוי \(\int\sqrt{1-x^{2}}dx\). כשאנחנו מבצעים את ההחלפה, אנחנו מחליפים את \(x\) ב-\(\cos y\), ואפשר לשחק ב"נדמה לי" שאנחנו מחליפים את \(dx\) בנגזרת של הביטוי בהחלפה, כלומר ב-\(d\left(\cos y\right)\). למה "נדמה לי"? כי ה-\(dx\) הזה, זכרו, הוא לא אובייקט פורמלי כלשהו, אלא רק צורת כתיב (יש דרך לתת לו משמעות פורמלית אבל אנחנו ממש לא שם כרגע). האינטואיציה היא ש-\(d\left(\cos y\right)=-\sin ydy\), כשה-\(dy\) הנוסף הגיע מכך שאנחנו "גוזרים את ה-\(y\) שבתוך ה-\(\cos\)". עכשיו צריך לטפל גם בגבולות האינטגרציה; במקרה שלנו ה-\(\int_{0}^{1}\) שהתחלנו ממנו הוא כבר במשמעות של \(\int_{g\left(a\right)}^{g\left(b\right)}\) ולכן צריך להתאמץ קצת כדי למצוא את ה-\(a,b\): \(0=\cos a\) ו-\(1=\cos b\) מובילים אותנו לבחור \(a=\frac{\pi}{2}\) ו-\(b=0\). נקבל, אם כן:

\(\int_{0}^{1}\sqrt{1-x^{2}}dx=\int_{\pi/2}^{0}-\sqrt{1-\cos^{2}y}\sin ydy=\int_{0}^{\pi/2}\sin^{2}ydy\)

אינטגרל של סינוס בריבוע נראה כמו עניין כואב, אבל למזלנו יש לנו את הזהות הטריגונומטרית \(\sin^{2}y=\frac{1-\cos2y}{2}\), כך שבעצם קיבלנו פה שני אינטגרלים קלים יחסית:

\(\int_{0}^{\pi/2}\sin^{2}ydy=\int_{0}^{\pi/2}\frac{dy}{2}-\frac{1}{2}\int_{0}^{\pi/2}\cos2ydy=\)

\(=\left[\frac{y}{2}\right]_{0}^{\pi/2}-\frac{1}{2}\left[\frac{\sin2y}{2}\right]_{0}^{\pi/2}=\frac{\pi}{4}\)

כשכל החלק ה"טריגונומטרי" (המחובר הימני) מתאפס.

שימו לב לתוצאה המעניינת שקיבלנו – באינטגרל המקורי לא היה זכר לטריגונומטריה, אבל התוצאה המספרית שלנו יצאה \(\frac{\pi}{4}\). כנראה שהבחירה ללכת בדרך הטריגונומטריה אכן הייתה מוצדקת במובן כלשהו (פרט למובן של "היי, תראו, זה פתר את זה!")

בואו נעבור עכשיו לדוגמה מהסוג השני. נניח שאנחנו רוצים לחשב את \(\int_{0}^{1}\left(x^{3}+2\right)^{2}x^{2}dx\). הביטוי נראה מזעזע, אבל אנחנו חדי עין ורואים שה-\(x^{2}\) שמחוץ לסוגריים נראה בערך כמו הנגזרת של הביטוי בתוך הסוגריים. זה נותן לנו אינטואיציה לגבי הצבה שכדאי להשתמש כאן כדי לפשט את המפלצת הזו – הצבה שתעלים לנו את ה-\(x^{2}\) שבחוץ ותהפוך את מה שבסוגריים לפשוט: \(t=x^{3}+2\).

שימו לב להבדל. כאן אני מגדיר משתנה חדש \(t\) בתור פונקציה של \(x\), ואילו קודם כתבתי את \(x\) בתור פונקציה של משתנה חדש. זו הסיבה שקודם אני כפלתי ב-\(g^{\prime}\) ואילו עכשיו אני "בולע" את ה-\(g^{\prime}\). אצלי כל הביטוי \(\left(x^{3}+2\right)^{2}x^{2}dx\) הופך להיות \(\frac{1}{3}t^{2}dt\). שימו לב ל-\(\frac{1}{3}\) הזה; הוא לא צץ משום מקום. אם \(t=x^{3}+2\) אז (שוב, זה סימון נוח, אין פה משמעות פורמלית מעבר לכך) \(dt=3x^{2}dx\) ולכן \(x^{2}dx=\frac{1}{3}dt\). ואיך משתנים הגבולות? הפעם אני פשוט מציב את הגבולות בנוסחה \(t=x^{3}+2\):

\(\int_{0}^{1}\left(x^{3}+2\right)^{2}x^{2}dx=\frac{1}{3}\int_{2}^{3}t^{2}dt=\frac{1}{3}\left[\frac{t^{3}}{3}\right]_{2}^{3}=\frac{27-8}{9}=\frac{19}{9}\)

זהו זה עם הדוגמאות. אבל לפני שנסיים, אני בטוח שכולכם מצפים בכליון עיניים לראות את משפט החלפת המשתנים הכללי עבור אינטגרלים מעל \(\mathbb{R}^{n}\). אז הנה הניסוח, כדי שנוכל להתרשם כמה הוא דומה לניסוח של המשפט הבסיסי: אם \(g:A\to B\) היא דיפאומורפיזם של קבוצות פתוחות ב-\(\mathbb{R}^{n}\) ו-\(f:B\to\mathbb{R}\) רציפה, אז \(f\) אינטגרבילית מעל \(B\) אם ורק אם \(\left(f\circ g\right)\left|\det Dg\right|\) אינטגרבילית מעל \(A\) ובמקרה זה מתקיים:

\(\int_{B}f=\int_{A}\left(f\circ g\right)\left|\det Dg\right|\)

מה השתנה, בעצם? ראשית, במקום שיהיה כתוב \(\left|g^{\prime}\right|\) כתוב \(\left|\det Dg\right|\), אבל היינו יכולים להשתמש באותו כתיב גם במקרה החד-ממדי; במקרה החד-ממדי המספר הנגזר בנקודה מסויימת הוא בדיוק הדטרמיננטה של הנגזרת (במובן הרב-ממדי של הנגזרת – קירוב לינארי) באותה נקודה. הדבר השני שהשתנה הוא שבמקום כל מני הנחות על \(g\) אנחנו אומרים שהיא "דיפאומורפיזם", שזה מושג שבכלל לא הגדרתי, אבל אין בו משהו מיוחד – זו פונקציה \(g:A\to B\) שהיא חד-חד-ערכית ועל, כך שגם \(g\) וגם \(g^{-1}\) שייכות ל-\(C^{r}\) עבור \(r\ge1\) כלשהו. כפי שניתן לנחש מכך שיש להן שם מיוחד, פונקציות שהן דיפאומורפיזמים הן בעלות חשיבות כללית באנליזה וקטורית, לא רק עבור משפט החלפת המשתנים.

אם כן, זה המשפט בגרסתו הכללית, אבל איך מוכיחים אותו בגרסה הזו? או, טוב ששאלתם. זה ידרוש עוד לא מעט עבודה.

אינטגרלים כפולים, משולשים ו-d-ממדיים

בסדרת הפוסטים שלי על אנליזה וקטורית סיימנו לעת עתה לדבר על נגזרות, ואנחנו עוברים אל עמוד התווך השני של האנליזה – אינטגרלים. הדיון באינטגרלים מתחלק לשלושה שלבים: בשלב הראשון, שהוא מה שנעשה הפעם, אנחנו לוקחים את אינטגרל רימן התמים והנחמד מחדו"א בסיסית ורואים איך ההגדרות שלו מוכללות באופן טבעי ל-\(\mathbb{R}^{d}\) לכל \(d\) טבעי. בשלב השני אנחנו רואים שדרך ההתבוננות הזו היא צרה מדי ובעצם צריך לדבר על עוד סוגים של אינטגרלים שרלוונטיים למרחבים רב-ממדיים, ואז מתחיל לצוץ ערב-רב של משפטים שמחברים את סוגי האינטגרלים השונים (משפטי גרין, גאוס, וסטוקס). בשלב השלישי, המטורלל ביותר, אנחנו מרחיבים מאוד את נקודת המבט שלנו ומגיעים מכך למשפט כללי מאוד (משפט סטוקס הכללי) שמכליל את כל המשפטים הללו, ובאופן כללי אנחנו מצליחים לראות שכל סוגי האינטגרלים השונים הם בעצם היבטים שונים של אותו דבר. זה היעד שאני חותר אליו, אבל הרבה לפני שנגיע לשם, בואו נתחיל מלדבר על ההכללה הפשוטה של אינטגרל רימן, שאנחנו מקבלים על ידי כך שאנחנו לוקחים את ההגדרה הרגילה של אינטגרל רימן ומנסים להפעיל אותה ב-\(d\) ממדים. אנחנו נראה שההגדרות הן פשוטות למדי – אין כאן סיבוך רציני ביחס למה שקורה במימד אחד – אבל שהחישוב של אינטגרל כזה הוא מן הסתם מסובך יותר, ובדרך כלל מסתמך על היכולת שלנו לבצע רדוקציה לאינטגרלים במימד אחד.

אני מניח כאן שאתם כבר מכירים אינטגרלים במימד אחד ואין צורך לתת שיחת מוטיבציה מיוחדת או לחזור על ההגדרות במימד אחד. מי שמעוניין יכול לקרוא את הפוסט שלי בנושא. אז בואו נעבור ישר לאקשן – איך מגדירים את זה?

במימד אחד אינטגרל מוגדר על קטע \(\left[a,b\right]\). ב-\(d\)-מימדים הוא מוגדר מעל קוביה \(d\)-ממדית, שהיא קבוצה מהצורה \(Q=\left[a_{1},b_{1}\right]\times\dots\times\left[a_{d},b_{d}\right]\). כלומר, יש לנו פונקציה חסומה \(f:Q\to\mathbb{R}\) ואנו רוצים להגדיר את האינטגרל שלה. לקטע מאורך 1 היה אורך, \(b-a\); לקוביה כזו יש נפח, \(v\left(Q\right)\triangleq\prod_{i=1}^{d}\left(b_{i}-a_{i}\right)\). במימד אחד הרעיון היה לחלק את הקטע \(\left[a,b\right]\) לחלקים קטנים, לכפול את אורך כל חלק כזה בערך המקסימלי/מינימלי בקטע של הפונקציה שמאנטגרלים, ולסכום. חלוקה של \(\left[a,b\right]\) מסומנת בתור \(P\) (מלשון Partition) והיא סדרה סופית של נקודות בקטע \(\left[a,b\right]\) שכוללת את הקצוות, כלומר \(P=\left(x_{1},x_{2},\dots,x_{t}\right)\) כך ש-\(x_{1}=a,x_{t}=b\) ו-\(x_{1}<x_{2}<\dots<x_{t}\). דרך אחת לחלק קוביה \(d\)-ממדית להרבה קוביות קטנות היא על ידי כך שלוקחים חלוקה של כל אחד מהקטעים שמגדירים את הקוביה, \(\left(P_{1},\dots,P_{d}\right)\), כלומר \(P_{i}\) היא חלוקה של הקטע \(\left[a_{i},b_{i}\right]\). תחשבו על איך אנחנו מציירים טבלה בדו מימד – קווים אנכיים ואופקיים שחוצים זה את זה ויוצרים ריבועים. כמובן, יש עוד דרכים לחלק קוביה \(d\)-ממדית לקוביות קטנות, אבל אנחנו פשוט לא נזקקים להן. העיקר מבחינתנו הוא שבדרך החלוקה שלנו אפשר לקבל חלקים שקטנים עד לאינסוף.

בחלוקה \(P=\left(P_{1},\dots,P_{d}\right)\) אנחנו מקבלים תת-קוביות שהן מהצורה \(I_{1}\times\dots\times I_{d}\) כאשר \(I_{i}\) הוא קטע שמוגדר על ידי החלוקה \(P_{i}\). נסמן תת-קוביה ב-\(R\). נסמן את הנפח של הקוביה ב-\(v\left(R\right)\). עכשיו, זכרו שיש לנו פונקציה \(f:Q\to\mathbb{R}\); נסמן ב-\(M_{R}\left(f\right)=\sup\left\{ f\left(x\right)\ |\ x\in R\right\} \) את החסם העליון על הערך של \(f\) במלבן \(R\) ובדומה ב-\(m_{R}\left(f\right)=\sup\left\{ f\left(x\right)\ |\ x\in R\right\} \) את האינפימום (כאן העובדה ש-\(f\) חסומה באה לידי ביטוי, אחרת הערכים הללו לאו דווקא היו מוגדרים והיינו בצרות). עכשיו אפשר לחקות את ההגדרה של סכומי דארבו מאינטגרלים חד ממדיים: להגדיר סכום תחתון של הפונקציה \(f\) ביחס לחלוקה \(P\) בתור הסכום \(L\left(f,P\right)=\sum_{R}m_{R}\left(f\right)v\left(R\right)\) ואת הסכום העליון בתור \(U\left(L,P\right)=\sum_{R}M_{R}\left(f\right)v\left(R\right)\) כאשר בשני המקרים הסכום נלקח על כל תת-הקוביות שמוגדרות על ידי \(P\) – קל לראות שהמספר שלהן הוא סופי ולכן הסכום בוודאי מוגדר היטב. השלב האחרון הוא הגדרה של אינטגרל תחתון ועליון: \(\underline{\int_{Q}}f=\sup_{P}L\left(f,P\right)\) ו-\(\overline{\int_{Q}}f=\inf_{P}U\left(f,P\right)\). אם \(\underline{\int_{Q}}f=\overline{\int_{Q}}f\) אומרים ש-\(f\) אינטגרבילית מעל \(Q\) ומסמנים את הערך המשותף הזה פשוט ב-\(\int_{Q}f\).

השלב האחרון, של האינטגרל העליון והתחתון, דורש עוד הבהרה מסויימת כדי שיהיה ברור למה "נכון" לנקוט בו. לא קשה לראות שאם ניקח חלוקה קיימת \(P\) ונחלק אותה עוד קצת על ידי הוספת נקודות עד לקבלת חלוקה \(P^{\prime}\), אנחנו יכולים רק להגדיל את הסכום התחתון ולהקטין את הסכום העליון, כלומר \(L\left(f,P\right)\le L\left(f,P^{\prime}\right)\) ו-\(U\left(f,P\right)\ge U\left(f,P^{\prime}\right)\). למה? כי השטח הכולל שעליו אנחנו סוכמים לא משתנה, אבל ה-\(M_{R}\left(f\right),m_{R}\left(f\right)\) שלנו עשויים להשתנות ולהיות יותר מדוייקים. לדוגמה, נאמר שבתת-קוביה עם נפח 10 יש לנו \(m_{R}\left(f\right)=3\), אז תת-הקוביה הזו תתרום לסכום 30; אבל עכשיו, אם נחלק אותה לשתי תת-קוביות שכל אחד מנפח 5, לא ייתכן שה-\(m_{R}\left(f\right)\) של אף אחד משתי תת-הקוביות הללו יהיה קטן יותר מ-3 (אחרת ה-\(m_{R}\left(f\right)\) המקורי היה נמוך יותר) ולכן ייתכן, למשל, שבאחת הקוביות הוא עדיין 3 אך בשניה הוא 4, ואז נקבל סכום כולל של \(3\cdot5+4\cdot5=35\), שגדול מ-30. עוד דבר שברור מייד הוא שעבור חלוקה \(P\) נתונה מתקיים \(L\left(f,P\right)\le U\left(f,P\right)\), פשוט כי \(\inf\) תמיד קטן או שווה ל-\(\sup\) שנלקח על אותה פונקציה ואותו תחום.

עכשיו, בואו ניקח שתי חלוקות \(P_{1},P_{2}\) כלשהן. אפשר לבנות מהן חלוקה חדשה שמתקבלת מאיחוד קבוצות הנקודות של שתיהן (חשבו על שתי טבלאות שונות שאנחנו שמים אחת על השניה תוך שימוש בנייר שקוף). נסמן את החלוקה שנקבל כך ב-\(P^{\prime}\). אז נקבל

\(L\left(f,P_{1}\right)\le L\left(f,P^{\prime}\right)\le U\left(f,P^{\prime}\right)\le U\left(f,P_{2}\right)\)

המסקנה: לכל שתי חלוקות, הסכום התחתון של האחת קטן מהסכום העליון של השניה. זה מצביע מייד על כך שהסכומים העליונים והתחתונים חסומים, ולכן האינטגרלים העליון והתחתון שהגדרתי אכן מוגדרים היטב, ושהאינטגרל העליון תמיד גדול או שווה מהאינטגרל התחתון, כלומר שניהם מהווים את הקירוב "הטוב ביותר" שאנחנו מסוגלים להשיג בשיטת האינטגרציה הנוכחית שלנו אל מה שאנחנו תופסים בתור האינטגרל של הפונקציה – קירוב אחד הוא מלמעלה והשניה מלמטה, ואם הם משתווים, מה טוב (ואם הם לא משתווים? יש שיטות אינטגרציה חכמות יותר – למשל, אינטגרל לבג – שהדיון בהן שייך לזמן אחר).

כדאי לתת עוד הערה קטנה על הסימון. אינטגרלים במימד אחד לרוב נכתבים בתור \(\int_{a}^{b}f\left(x\right)dx\). אנחנו שינינו שני דברים. הראשון הוא שאנחנו לא כותבים את הגבולות העליונים והתחתונים אלא סתם כותבים \(Q\); זה זהה לכך שבמימד אחד היינו כותבים \(\int_{\left[a,b\right]}f\). הדבר השני הוא שחיסלנו את ה-\(dx\) הזה שתקוע בתוך אינטגרלים במימד אחד. ליצור הזה יש במימד אחד שימוש פרקטי, של להגיד לנו מי משתנה האינטגרציה במקרה שבו ב-\(f\) יש גם פרמטרים; אבל יש לו גם משמעות מעבר לכך, שעדיין לא פירמלנו בהקשר שלנו ולכן בינתיים נוותר עליה לחלוטין.

עם זאת, יש כתיב מקובל לאינטגרלים עבור \(d=2\) ו-\(d=3\) שהכרחי להציג כי הוא מה שמשתמשים בו רוב הזמן בשימושים מעשיים. כאשר \(d=2\) האינטגרל שהגדרנו נקרא אינטגרל כפול ומסומן ב-\(\iint_{Q}f\left(x,y\right)dxdy\), וכאשר \(d=3\) הוא נקרא אינטגרל משולש ומסומן ב-\(\iiint_{Q}f\left(x,y,z\right)dxdydz\). זאת, כמובן, בנוסף לסימון ה"כללי" שכבר הצגתי.

עוד נקודה שכדאי להתייחס אליה כבר עכשיו היא ש-\(Q\) לא חייב להיות קוביה. אפשר להגדיר את האינטגרל על כל קבוצה חסומה \(S\), כאשר "חסומה" פירושו שקיימת קוביה \(Q\) שמכילה אותה. דהיינו, אם יש לנו פונקציה \(f:S\to\mathbb{R}\) יש משמעות לאינטגרל \(\int_{S}f\). בסיטואציה הזו אפשר להגדיר פונקציה \(f_{Q}:Q\to\mathbb{R}\) כאשר \(Q\) היא קוביה כלשהי שמכילה את \(S\), ומוגדרת על ידי \(f_{Q}\left(x\right)=\begin{cases}f\left(x\right) & x\in S\\0 & x\notin S\end{cases}\) ואז להגדיר \(\int_{S}f=\int_{Q}f_{Q}\). כמובן, נדרשת כאן הוכחה לכך שההגדרה הזו מוגדרת היטב – שעבור בחירות שונות של \(Q\) נקבל את אותו אינטגרל. אני קופץ על ההוכחה הזו כי אני מניח שהתוצאה אינטואיטיבית מספיק גם כך.

עכשיו עולות מאליהן שתי שאלות – הראשונה, באילו מצבים האינטגרל של \(f\) קיים? ראינו שהיות \(f\) חסומה היא תנאי הכרחי לכך שבכלל ננסה להגדיר את האינטגרל, אבל זה בוודאי לא תנאי מספיק. השאלה השניה היא – אם האינטגרל קיים, איך מחשבים אותו?

נתחיל מהשאלה הראשונה. הדוגמה הנגדית הקלאסית של פונקציה חסומה שאיננה אינטגרבילית היא פונקציית דיריכלה, שבמימד אחד מוגדרת להיות \(f\left(x\right)=\begin{cases}1 & x\in\mathbb{Q}\\0 & x\notin\mathbb{Q}\end{cases}\) – בניסוח אחר, זוהי הפונקציה המציינת של הרציונליים, \(\chi_{\mathbb{Q}}\). היא לא אינטגרבילית מכיוון שכל קטע לא מנוון מכיל גם רציונליים וגם אי רציונליים, ולכן \(m_{R}\) יוצא תמיד 0 ו-\(M_{R}\) יוצא תמיד 1 ולכן האינטגרל העליון יצא האורך של הקטע שעליו מבצעים את האינטגרציה והאינטגרל התחתון יצא תמיד 0; אותו דבר יקרה גם עבור גרסה \(d\)-ממדית של הפונקציה. עכשיו, אינטגרל לבג שהזכרתי למעלה פותר את הבעיה ויוצא שאינטגרל לבג של הפונקציה הזו הוא 0; האינטואיציה הוא ש-\(\mathbb{Q}\) היא קבוצה "קטנה" למדי מבחינת ה"נפח" (המידה שלה) ולכן היא לא משפיעה לנו על האינטגרל ואפשר לחשוב על האינטגרל כאילו הוא נלקח רק מעל האי-רציונליים, ומעליהם הפונקציה היא 0 (ברמה אינטואיטיבית יותר, אפשר לשנות כרצוננו את הערכים של הפונקציה על הרציונליים ועדיין לקבל את אותו אינטגרל, ולכן אם נשנה את ערכי הפונקציה ל-0 נקבל את הפונקציה הקבועה 0 ואין פלא שהאינטגרל יוצא 0).

מצד שני, די קל להוכיח שאם \(f\) היא רציפה, אז האינטגרל שלה קיים תמיד. ההוכחה מתבססת על כך שאם \(f\) היא רציפה בקבוצה סגורה וחסומה, אז היא רציפה בה במידה שווה. רציפות במידה שווה פירושה שאפשר לתת גודל כלשהו של תת-קוביות, כך שכל זוג נקודות בכל תת-מלבן מהגודל הזה יהיו בעלות התכונה שהתמונה של \(f\) עליהן היא יחסית קרובה. פורמלית, לכל \(\varepsilon>0\) קיים \(\delta>0\) כך שאם \(\left|x_{1}-x_{2}\right|<\delta\) אז \(\left|f\left(x_{1}\right)-f\left(x_{2}\right)\right|<\varepsilon\). המשמעות היא שככל ש-\(R\) נהיה קטן יותר ויותר, כך \(m_{R}\) ו-\(M_{R}\) הופכים לקרובים יותר ויותר, ולכן \(L\left(f,P\right)\) ו\(U\left(f,P\right)\) מתקרבים יותר ויותר וניתן להראות שהאינטגרלים העליון והתחתון ישתוו. בדרך כלל רואים את ההוכחה הזו עבור אינטגרל חד ממדי ואין טעם לחזור עליה כאן.

המשפט הכללי על אינטגרביליות רימן של \(f\) הוא מעין שילוב של שני הדברים שדיברנו עליהם לעיל: זה לא הכרחי שהפונקציה תהיה רציפה, אבל היא צריכה להיות כמעט רציפה. הניסוח הפורמלי הוא ש-\(f\) אינטגרבילית רימן ב-\(Q\) אם ורק אם קבוצת נקודות אי-הרציפות שלה ב-\(Q\) היא ממידה אפס. אני לא מוכיח את התוצאה הזו כאן כי לדעתי נכון לדבר עליה רק במסגרת דיון על מידת לבג (למרות שאפשר להגדיר את "מידה אפס" גם בלי להגדיר את מידת לבג הכללית, וזה מה שבדרך כלל עושים בספרי לימוד בנושא – קבוצה היא ממידה אפס אם לכל \(\varepsilon\) אפשר לכסות אותה על ידי סדרת קוביות שסכום נפחיה הכולל – וזה עשוי להיות סכום אינסופי – הוא קטן מ-\(\varepsilon\)). כל הדיון הזה מתבצע לרוב כבר עבור פונקציה חד ממדית; העניין הוא בכך ש-\(d\)-ממדים לא הופכים את הסיפור למסובך כמעט בכלל.

נעבור, אם כן, לשאלה של איך מחשבים אינטגרלים \(d\)-ממדים. וכאן זו כבר בעיה קשה בהרבה. התשובה הקצרה היא שלרוב עושים את זה על ידי רדוקציה למקרה החד-ממדי, כלומר מסתמכים בעיקר על כך שאנחנו יודעים לפתור אינטגרלים חד-ממדיים, אז כדאי להיזכר מה קורה במקרה החד-ממדי. גם במקרה החד-ממדי, חישוב אינטגרלים יכול להיות עניין קשה. עבור \(f\) שאינה רציפה, לרוב מפצלים את האינטגרל לסכום של כמה אינטגרלים שכל אחד מהם נוגע לתחום שבו \(f\) רציפה. כאשר \(f\) כן רציפה, יש לנו קסם, קסם מדהים לחלוטין, שנקרא המשפט היסודי של החדו"א. המשפט הזה אומר שאם \(f\) היא רציפה בקטע \(\left[a,b\right]\) ואם \(F\) היא פונקציה קדומה של \(f\), כלומר מתקיים \(F^{\prime}=f\) – הנגזרת של \(F\) היא \(f\) – אז \(\int_{a}^{b}f\left(x\right)dx=F\left(b\right)-F\left(a\right)\). בעיני זו תוצאה מדהימה לגמרי, וכבר מהפעם הראשונה שבה ראיתי אותה התקשיתי להאמין לה. ה"קסם" פה הוא שכדי לדעת מה האינטגרל של \(f\) על כל הקטע \(\left[a,b\right]\) אנחנו רק צריכים לדעת את הערכים של \(F\) בקצוות הקטע. איך זה אפשרי בכלל? האם \(f\) לא יכולה "להשתגע" בתוך הקטע? התשובה היא כמובן שהיא יכולה, אבל זה ישפיע על \(F\). איכשהו \(F\) "דוחסת" את כל המורכבות של \(f\) אל תוך קצוות הקטע. אחרי קצת מחשבה על הנושא המשפט נראה כמעט מובן מאליו – \(F\left(b\right)\) הוא בדיוק סכום כל השינויים שה"שיגועים" של \(f\) בתוך הקטע גרמו ל-\(F\), החל מהערך ההתחלתי \(F\left(a\right)\) – אבל זה שמבינים למה הקסם עובד לא מפחית מהמגניבות שלו, לטעמי.

למי שעדיין חושבים שהמשפט מגניב, הבשורה הטובה שלי היא שמשפט סטוקס – הדבר המאוד-כללי ומאוד-מאוד-מגניב שאני מבטיח שנגיע אליו כל הזמן – הוא בעצם הכללה אדירה של המשפט היסודי של החדו"א. דוגמה לכך היא במקרה פרטי פשוט במיוחד שלו, משפט גרין, שאומר שהאינטגרל הדו-ממדי של פונקציה בקטע שמוגדר על ידי עקום סגור במישור שווה לאינטגרל מסלולי על העקום הזה של משהו שהוא כמו פונקציה קדומה של הפונקציה הדו ממדית. נשמע מעורפל, נכון? כי אני מקדים את זמני ומדבר על הגדרות שעוד לא קיימות כמו "אינטגרל מסלולי". נעזוב את זה לבינתיים.

ה"קסם" שנותן לנו המשפט היסודי של החדו"א לא בא בלי מחיר. בהינתן \(f\), זה יכול להיות קשה מאוד למצוא לה פונקציה קדומה \(F\). יש פונקציות תמימות למראה, כמו \(e^{x^{2}}\), שאין להן פונקציה קדומה שניתנת להצגה בצורה "נחמדה" בכלל. אין אלגוריתם כללי שמאפשר לנו למצוא פונקציה קדומה של פונקציה נתונה (בעוד שעבור נגזרת כן יש אלגוריתם עבור מחלקה רחבה מאוד של פונקציות). יש שלל טריקים מגניבים שמאפשרים להקל על החיפוש, אבל לא אכנס אליהם כרגע.

אם כן, יש לנו פתרון שמבוסס על רדוקציה למקרה החד-ממדי. אני אחזור עוד רגע לשאלה איך עושים את זה, ועם השאלה הזו נסיים את הפוסט, אבל אני כבר רוצה לרמוז אל המקום הבא שאני הולך אליו. הרבה פעמים לפני שמבצעים רדוקציה למקרה החד ממדי אנחנו רוצים להביא את האינטגרל לצורה פשוטה יותר, על ידי שינוי של \(f\) לפונקציה שיותר קל לנו לבצע לה אינטגרציה חד-ממדית. התעלול הזה נקרא החלפת משתנים (קצת מוקדם מדי להציג דוגמה). המשפט הרלוונטי לעניין מגדיר לנו מה זו "החלפת משתנים" לגיטימית, ואיך האינטגרל הולך להשתנות עקב כך – ההבדל העיקרי הוא שצריך יהיה לכפול את \(f\) ב"תיקון" כלשהו שמחושב מתוך הפונקציה שמבצעת את החלפת המשתנים. התוצאה יוצאת אלגנטית למראה ושימושית בצורה מטורפת; לרוע המזל, ההוכחה של המשפט הזה היא אחת מהקשות ביותר שבהן ניתן להיתקל בקורסי המבוא לנושא. אני אקח על עצמי לנסות ולהציג את ההוכחה כאן, ובתקווה לחפף כמה שפחות, אבל זה באמת שייך כבר לפוסט (או סדרת פוסטים) אחר.

בואו נעבור לדוגמה. נניח שאנחנו רוצים לחשב את האינטגרל של \(f\left(x,y\right)=x+y\) על המלבן \(Q=\left[0,1\right]\times\left[0,1\right]\). חשבו על המלבן הזה כאילו הוא מורכב מאינסוף קווים אופקיים דקים באורך 1 – קו לכל ערך של \(y\) בין 0 ל-1. על כל קו כזה, \(f\left(x,y\right)\) היא פונקציה במשתנה יחיד \(y\), כאשר \(x\) הוא פרמטר – אינטגרל חד ממדי של הדבר הזה אנחנו בוודאי יודעים לחשב לכל \(x\): \(\int_{0}^{1}\left(x+y\right)dy=\left[xy+\frac{y^{2}}{2}\right]_{0}^{1}=\frac{1}{2}+x\). עכשיו, \(f\left(x,y\right)\) מתאר כמה הערך של הפונקציה \(f\) בקואורדינטה \(\left(x,y\right)\) תורם לסכום שהאינטגרל מהווה (כמובן, זה לא שהערך \(f\left(x,y\right)\) מתווסף לסכום כמות שהוא; אינטואיטיבית, הוא מתווסף כשהוא משוקלל על פי ה"גודל" של הנקודה \(\left(x,y\right)\), שהוא אינפיניטסימלי. זה שאפשר לפרמל את האינטואיציה הזו ומקבלים משהו שעובד, זה מה שמגניב באינטגרל). באופן דומה, האינטואיציה היא ש-\(\frac{1}{2}+x\) כאן מתאר מה כל הקו האנכי עם קו רוחב \(x\) תורם לסכום. לכן כדי לדעת מה הסכום הכולל צריך לבצע אינטגרציה על הערכים הללו – להגדיר פונקציה \(I\left(x\right)=\frac{1}{2}+x\) ולחשב את האינטגרל \(\int_{0}^{1}I\left(x\right)dx=\int_{0}^{1}\left(\frac{1}{2}+x\right)=\left[\frac{1}{2}x+\frac{1}{2}x^{2}\right]_{0}^{1}=1\).

את כל התהליך הזה אפשר לתאר אינטואיטיבית בעזרת המשוואה הבאה:

\(\iint_{Q}\left(x+y\right)dxdy=\int_{0}^{1}\left(\int_{0}^{1}\left(x+y\right)dy\right)dx\)

כלומר, אנחנו מפרקים את האינטגרל הכפול להפעלה כפולה של אינטגרל רגיל. הסימונים נבחרו בקפידה כדי שההפרדה הזו תיראה לנו טבעית ככל הניתן, אבל מן הסתם זו תוצאה לא טריוויאלית שצריך להוכיח. למרבה המזל, ההוכחה היא יחסית ישירה ולא יהיה לנו קושי לראות אותה כאן.

יש נקודה טכנית מעצבנת אחת שחייבים לתת עליה את הדעת לפני שאני מציג את הניסוח הכללי של המשפט, והיא שלפעמים פירוק לא יכול לעבוד בכלל. הנה דוגמה פשוטה: \(f\left(x,y\right)=\begin{cases}1 & x=0\wedge y\in\mathbb{Q}\\0 & \mbox{else}\end{cases}\). הפונקציה הזו היא 0 כמעט בכל מקום, למעט נקודות מהצורה \(\left(0,r\right)\) כאשר \(r\) הוא מספר רציונלי. אני רוצה להסתכל על האינטגרל שלה על \(\left[0,1\right]\times\left[0,1\right]\). בבירור הפונקציה אינטגרבילית; כל נקודות אי הרציפות שלה הן על הישר \(\left(0,y\right)\), ולכן הן ממידה אפס (לקו במישור יש מידה אפס, לא קשה להראות את זה). עם זאת, ה"חתך" \(f_{0}\left(y\right)=f\left(0,y\right)\) שמתקבל מהצבת \(x=0\) הוא פונקציית דיריכלה שהזכרתי קודם, והיא לא אינטגרבילית. אז אני לא יכול לרשום פירוק כמו \(\iint_{Q}f\left(x,y\right)dxdy=\int_{0}^{1}\left(\int_{0}^{1}f\left(x,y\right)dy\right)dx\) מהטעם הפשוט שה-\(\int_{0}^{1}f\left(x,y\right)dy\) שבפנים לא בהכרח מוגדר (הפונקציה \(I\left(x\right)=\int_{0}^{1}f\left(x,y\right)dy\) לא מוגדרת לכל \(x\)).

פתרון אחד הוא לעבור לדבר על אינטגרל לבג שבו דברים מעצבנים כאלו לא קורים, אבל אין בכך צורך, אפשר לתקן את הבעיה על ידי שימוש באינטגרלים שכן מוגדרים תמיד – האינטרלים העליונים והתחתונים. באיזה מהם להשתמש? לא משנה, שניהם יעבדו. אם כן, בואו נעבור לניסוח הגרסה הכללית של המשפט – משפט פוביני: אם \(f:Q\to\mathbb{R}\) היא פונקציה אינטגרבילית, ו-\(Q=A\times B\) כך ש-\(A\)קוביה ב-\(\mathbb{R}^{k}\) ו-\(B\) קוביה ב-\(\mathbb{R}^{n}\), אז נסמן \(f\left(x,y\right)\) בתור הפונקציה \(f\) כאשר חילקנו את המשתנים שלה לשתי קבוצות, ה-\(x\)-ים וה-\(y\)-ים, עבור \(x\in A\) ו-\(y\in B\). אז

\(\int_{Q}f=\int_{x\in A}\underline{\int_{y\in B}}f\left(x,y\right)=\int_{x\in A}\overline{\int_{y\in B}}f\left(x,y\right)\)

ההוכחה היא לא הרבה יותר מאשר משחק זהיר עם קוביות וסכומים עליונים ותחתונים וכל שאר המושגים שראינו בפוסט – הזדמנות טובה לתרגל אותם.

כדי להקל לעצמנו על החיים, בואו נשתמש בסימון המקוצר \(\underline{I}\left(x\right)=\underline{\int_{y\in B}}f\left(x,y\right)\) ו-\(\overline{I}\left(x\right)=\overline{\int_{y\in B}}f\left(x,y\right)\). דהיינו, משפט פוביני אומר ש-\(\int_{A\times B}f\left(x,y\right)=\int_{x\in A}\underline{I}\left(x\right)=\int_{x\in A}\overline{I}\left(x\right)\). שימו לב למה שנאמר כאן באופן מובלע – ש-\(\underline{I}\left(x\right)\) ו-\(\overline{I}\left(x\right)\) הם אינטגרביליים מעל \(A\). נוכיח את השוויון ואת האינטגרביליות בבת אחת – התעלול יהיה להראות שאפשר לחסום סכומים עליונים ותחתונים של ה-\(I\)-ים בין סכומים עליונים ותחתונים של \(f\); מכיוון ש-\(f\) אינטגרבילית, הסכומים הללו יכולים להיות קרובים ככל שנרצה, ולכן כך יהיו הסכומים עבור ה-\(I\)-ים.

עכשיו, סכומים עליונים ותחתונים הם תמיד ביחס לחלוקה \(P\) של \(Q\). חלוקה של קוביה רב-ממדית מורכבת מחלוקות של הצירים, ולכן כל חלוקה \(P\) "מתפרקת" לזוג \(\left(P_{A},P_{B}\right)\) של החלוקות של ההיטלים \(A,B\) של \(Q\). אם נסמן קוביה כלשהי בחלוקה של \(A\) בתור \(R_{A}\), ובדומה \(R_{B}\) תהיה קוביה בחלוקה של \(B\), אז \(R_{A}\times R_{B}\) תהיה קוביה בחלוקה של \(Q\). מה שאני ארצה להוכיח הוא

\(L\left(f,P\right)\le L\left(\underline{I}\left(x\right),P_{A}\right)\le U\left(\underline{I}\left(x\right),P_{A}\right)\le U\left(f,P\right)\)

ובאופן דומה גם עבור \(\overline{I}\left(x\right)\). כמובן, אי השוויון האמצעי כבר ידוע לנו. למה אי השוויון הזה מסיים את ההוכחה? כי לכל \(\varepsilon>0\) ניקח \(P\) כך ש-\(\left|U\left(f,P\right)-L\left(f,P\right)\right|<\varepsilon\) (קיים כזה \(P\) כי \(f\) אינטגרבילית). מאי השוויונים נקבל \(\left|U\left(\underline{I}\left(x\right),P_{A}\right)-L\left(\underline{I}\left(x\right),P_{A}\right)\right|<\varepsilon\) וזה מוכיח ש-\(\sup L\left(\underline{I}\left(x\right),P_{A}\right)=\inf U\left(\underline{I}\left(x\right),P_{A}\right)\).

אז בואו ננסה להבין למה \(L\left(f,P\right)\le L\left(\underline{I}\left(x\right),P_{A}\right)\). אם נבין את זה, גם אי השוויון האחר ינבע באותו האופן. בשביל זה נצטרך לרדת רמה אחת נוספת למטה, מרמת הסכום התחתון אל רמת הסכום על קוביה בודדת:

\(L\left(\underline{I}\left(x\right),P_{A}\right)=\sum_{R_{A}}m_{R_{A}}\left(\underline{I}\right)v\left(R_{A}\right)\)

\(L\left(f,P\right)=\sum_{R_{A}\times R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{A}\times R_{B}\right)=\sum_{R_{A}}\sum_{R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{A}\right)v\left(R_{B}\right)\)

לכן אי השוויון שאנחנו רוצים להוכיח הוא בעצם

\(\sum_{R_{A}}\sum_{R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{A}\right)v\left(R_{B}\right)\le\sum_{R_{A}}m_{R_{A}}\left(\underline{I}\right)v\left(R_{A}\right)\)

ואפשר לחלק ב-\(v\left(R_{A}\right)\) ולקבל

\(\sum_{R_{A}}\left[\sum_{R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{B}\right)\right]\le\sum_{R_{A}}m_{R_{A}}\left(\underline{I}\right)\)

מסקנה: מספיק אם נוכיח, עבור \(R_{A}\) כללי, ש-

\(\sum_{R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{B}\right)\le m_{R_{A}}\left(\underline{I}\right)\)

יפה. בואו נתמקד לרגע ב-\(m_{R_{A}\times R_{B}}\left(f\right)\). זהו האינפימום של ערכי \(f\) על הקוביה \(R_{A}\times R_{B}\). לכן הוא קטן או שווה לכל ערך של \(f\) על הקוביה הזו; בפרט, אם נקפיא את \(x\) לרגע (ונסמן אותו \(x_{0}\in R_{A}\) כדי שיהיה ברור, ועכשיו \(f\left(x_{0},y\right)\) היא הפונקציה של \(y\) שמתקבלת מהצבה ב-\(f\) כאשר \(x_{0}\) "מוקפא"), אנחנו יודעים ש-\(m_{R_{A}\times R_{B}}\left(f\right)\le f\left(x_{0},y\right)\) עבור כל \(y\in R_{B}\). לכן אם ניקח את האינפימום של אגף ימין, אי השוויון ישתמר: \(m_{R_{A}\times R_{B}}\left(f\right)\le m_{R_{B}}\left(f\left(x_{0},y\right)\right)\)

בהינתן \(x_{0}\) קבוע, אי השוויון הזה נכון לכל קוביה \(R_{B}\). לכן הוא ישתמר גם אם נכפול את שני האגפים ב-\(v\left(R_{B}\right)\) ונסכום על כלל ה-\(R_{B}\)-ים. קיבלנו:

\(\sum_{R_{B}}m_{R_{A}\times R_{B}}\left(f\right)v\left(R_{B}\right)\le\sum_{R_{B}}m_{R_{B}}\left(f\left(x_{0},y\right)\right)v\left(R_{B}\right)=L\left(f\left(x_{0},y\right),P_{B}\right)\le\underline{\int_{y\in B}}f\left(x_{0},y\right)=\underline{I}\left(x_{0}\right)\)

האם סיימנו? כמעט. אגף ימין הוא מה שרצינו לקבל, אבל באגף שמאל צריך להיות \(m_{R_{A}}\left(\underline{I}\right)\). אבל זה מיידי: ראינו שאגף ימין קטן או שווה מכל ערך של \(\underline{I}\) על \(x\) ב-\(R_{A}\), ולכן אגף ימין יהיה קטן או שווה לאינפימום – וסיימנו.

כאן גם סיימנו עם ההוכחות הפשוטות. האתגר הבא שלי הוא להוכיח את משפט החלפת המשתנים, מה שידרוש לא מעט הכנה מוקדמת ועבודה טכנית. יהיה כיף.

רקורסיה

escher_hands

הבדיחה הידועה אומרת שבמילון ההגדרה של רקורסיה היא "עיין ערך רקורסיה". אבל כנראה שזה לא מספיק טוב, כי ביקשו ממני פוסט על רקורסיות, וספציפית על רקורסיות במדעי המחשב. כך שהפוסט הזה הולך להיות עם מבוא כללי לא טכני, ואחר כך עם גלישה לפסים טכניים שיכולים להיות מאוד מעניינים עבור מי שמתעניין בדברים הללו ועוד לא מכיר.

אין הגדרה כללית למה זו בדיוק רקורסיה, אבל הרעיון הוא תמיד זהה – משהו שמתואר/מוגדר/מחושב איכשהו באמצעות עצמו. לרוב באמצעות גרסה קצת יותר פשוטה של עצמו, וכמעט תמיד עם בסיס כלשהו לתיאור/הגדרה/חישוב שהוא ישיר ולא דורש את ההפניה העצמית הזו. דוגמה נפוצה בארץ היא ההגדרה (הפשטנית במתכוון) ליהודי – "יהודי הוא מי שנולד לאם יהודיה". כאן הבירור האם פלוני הוא יהודי מתבצע על ידי הפעלת אותו בירור על אמו של הפלוני. באיזה מובן האם היא "גרסה קצת יותר פשוטה"? התשובה היא שעץ המשפחה שלה קצר יותר. אם נמשיך ונעלה בעץ המשפחה נגיע בסופו של דבר למקרה קצה – מישהו שהיה יהודי למרות שאמו לא הייתה יהודיה – זה מקרה בסיס שלא נכלל בהגדרה הפשטנית שנתתי אבל ההכרח של הקיום שלו מובלע בה. את דוגמת עץ המשפחה אפשר לנצל לעוד רקורסיות – למשל, שני אנשים הם קרובים אם יש להם הורה משותף (זה מקרה בסיס), או אם הורה של אחד מהם הוא קרוב של הורה של השני (זו "הפעלה" של הרקורסיה).

בואו נעבור לדוגמה קלאסית מתחום המתמטיקה – סדרת פיבונאצ'י. הכלל שמגדיר את הסדרה הזו הוא שכל איבר בה שווה לסכום שני האיברים שלפניו, פרט לשני האיברים הראשונים ששניהם פשוט 1 (או לפעמים 0 ו-1 או לפעמים 1 ו-2, זה לא חשוב). זו בבירור הגדרה רקורסיבית: כל איבר בסדרה מוגדר בעזרת איברים "פשוטים" ממנו, כאשר "פשטות" כאן פירושה קרבה גדולה יותר לתחילת הסדרה. למה בעצם שזה ייחשב "פשוט יותר"? כי כדי לחשב את הערך של האיבר השישי בסדרה באמצעות הנוסחה הרקורסיבית נצטרך בסופו של דבר לחשב את ערכם של חמישה איברים אחרים, אלו שלפניו; אבל בשביל לחשב את הערך של האיבר השביעי נצטרך לחשב את ערכם של שישה איברים אחרים, וכן הלאה.

אם כן, כשאני אומר "פשוט יותר" אני לא מתכוון לפי איזה מדד אבסולוטי של פשטות, אלא לפי מעין רמת קרבה לאחד ממקרי הבסיס שבהם החישוב לא דורש הפעלה נוספת של הרקורסיה. עוד דוגמה מתמטית פשוטה היא פונקציית העצרת: !n הוא מכפלת כל המספרים הטבעיים מ-1 ועד n, כאשר מטעמי נוחות מגדירים ש-!0 שווה ל-1. זה מוביל להגדרה רקורסיבית פשוטה: \( n!=\begin{cases} 1 & n=0\\ n\cdot\left(n-1\right)! & n>0 \end{cases} \)

כמובן, כל הדוגמאות הללו לא מספקות לנו הגדרה חד משמעית של מהי רקורסיה, וברור שיש גמישות באופן שבו אנחנו נותנים את השם הזה לדברים שונים. הביטו בשלט הבא: האם מה שמתואר בו הוא בעל אופי רקורסיבי? hulda_recursion יש לנו כאן רחוב שנקרא על שם ישוב שנקרא על שם נביאה (שנקראה על שם בעל חיים? קרוב לודאי שלא, אבל זה משעשע יותר כך). האם זאת רקורסיה? הטהרנים יטענו שלא, כי רקורסיה תהיה רק סיטואציה של "ישוב שנקרא על שם ישוב שנקרא על שם ישוב", אבל לדעתי אין הכרח כזה. חשבו על תהליך "בירור שם" של דבר מה – אם המשהו קרוי על שם משהו אחר, מבררים מהיכן הגיע שמו של המשהו האחר.

ציור הידיים של אשר, שבראש הפוסט, גם הוא סוג של דוגמה לרקורסיה, למרות שאחת מופרעת שאין לה תנאי עצירה ושרשרת ההפעלות שלה היא לולאה. זה לא משהו מציאותי במיוחד, אבל אשר מעולם לא התיימר להיות מציאותי.

דוגמה אחרת ומבדרת למדי לרקורסיה קיבלנו לפני כמה שנים בקולנוע, בסרט Inception של כריסטופר נולאן. מבלי להיכנס לפרטי עלילה מיותרים, הסרט עוסק בחלומות שמתרחשים בתוך חלומות שמתרחשים בתוך חלומות… ומה שקורה ברמה אחת עשוי להשפיע על מה שקורה ברמה אחרת. כמובן, הרעיון של סיפור שמתרחש במספר "רמות" שונות הוא נפוץ למדי בספרות, לפחות כשמדובר על שתי רמות (זה מה שמכונה "סיפור מסגרת"). ב"גדל, אשר, באך" של דגלאס הופשטטר יש שימוש בסיפור שמתרחש בכמה רמות שונות בדיוק בשביל להדגים את הרעיון של רקורסיה.

בקיצור, אנחנו מכירים רקורסיות משלל הקשרים שונים והן דבר מבדר למדי תמיד. אבל מה זה אומר במדעי המחשב, ספציפית בתכנות (כי יש מושג של "פונקציה רקורסיבית" גם במדעי המחשב התיאורטיים והמושג הזה שונה לגמרי מהמושג המקביל בתכנות)? בתכנות "פונקציה רקורסיבית" היא פונקציה שקוראת לעצמה. ובואו נסביר את המושג הזה לטובת מי שלא בעניינים. כמובן, אני לא מכיר את כל שפות התכנות בעולם וייתכן שאני לא מתאר את הדבר הכללי ביותר; אבל לשפות תכנות כמו ++C או Ruby התיאור הוא פחות או יותר מדויק.

מושג עיקרי בתכנות הוא פונקציה: פונקציה היא קטע קוד שמקבל קלטים מסויימים ועושה איתם כל מני דברים ומחזירה פלט. לפעמים אפילו אין צורך בקלט או בפלט מפורשים, והפונקציה שואבת את הקלטים שלה ממקורות אחרים (למשל, משתנים גלובליים; אבל שימוש בהם הוא פשע!) או שהיא פשוט פועלת באותה הצורה בכל פעם; ולפעמים אין צורך בפלט אלא אנחנו מריצים את הפונקציה בשביל "תופעות הלוואי" של הריצה שלה (למשל, שינוי של משתנים מסויימים שהפונקציה קיבלה כקלט, או של משתנים גלובליים – אבל משתנים גלובליים זה פשע! – או הדפסה למסך, וכדומה). מה שחשוב בפונקציה הוא שמרגע שבו כתבנו אותה, אנחנו יכולים להפעיל אותה מכל מקום – "להריץ אותה". זה אומר שאם הקוד שלנו הגיע לשורה שבה אנחנו מריצים פונקציה, הוא שוכח באופן זמני מהאיזור בקוד שבו הוא רץ, ועובר לרוץ על איזור אחר בקוד – האיזור שבו הפונקציה שלנו כתובה. עם סיום הפונקציה הוא חוזר לאיזור המקורי שבו הוא היה.

אנלוגיה פשוטה לדבר הזה יש לנו בקריאת ספר: נניח שנתקלנו במילה לא מוכרת בספר; אנחנו עוצרים, שמים סימניה, פותחים מילון ומחפשים בו את המילה הלא מוכרת (קראנו לפונקציה "הפעל מילון" עם הקלט של המילה הלא מוכרת), קוראים את הפירוש או מתעצבים על כך שלא מצאנו פירוש, ואז סוגרים את המילון, שמים אותו בצד, חוזרים לספר שלנו ומוצאים את המקום שהיינו בו בספר בעזרת הסימניה. עכשיו, בואו נניח שהגענו בספר שלנו למילה קשה, ופתחנו את המילון, וקראנו את ההגדרה, וגם בתוך ההגדרה הייתה מילה קשה שלא הצלחנו להבין. מה עושים? שמים סימניה גם במילון, ופותחים שוב את המילון, עם חיפוש של ההגדרה הקשה, וכדומה. הבנתם את הרעיון. זו בדיוק הייתה קריאה רקורסיבית, ועכשיו יש לנו שתי סימניות להתעסק איתן.

בואו ניקח את זה צעד אחד קדימה בעזרת אנלוגיה מודרנית למדי – ויקיפדיה. להרבה אנשים מוכרת היטב התופעה שבה הם קוראים ערך בויקיפדיה, ובאמצע הקריאה נתקלים בקישור לערך מעניין אחר. ואז הם לוחצים על הקישור אליו, מתחילים לקרוא את הערך המעניין האחר, וכשהם מסיימים הם לוחצים על back כדי לחזור לערך המקורי. אבל לרוב בקריאת הערך המעניין האחר מגיעים לעוד קישור שנכנסים אליו, וכן הלאה. התוצאה היא שנוצרת "שרשרת" של ערכים ששמורה בזיכרון של הדפדפן. זה בדיוק גם מה שעשוי לקרות בתכנות – מקבלים שרשרת קריאות לפונקציות, ולכל קריאה כזו צריך לשמור את המידע של "איפה היינו". כפי שכבר ברור, המידע הזה חייב להיות רשימה באורך לא מוגבל, כי אין לנו הגבלה עקרונית לכמות הקריאות-בתוך-קריאות שאפשר לעשות. הרשימה הזו כוללת לא רק את רשימת ה"מקומות שבהם היינו" אלא גם מידע על המשתנים המקומיים של הפונקציות – מה הערכים שהם הכילו. באנלוגיית ויקיפדיה, דמיינו שאתם לא רק לוחצים על הלינק אלא ממש פותחים אותו בטאב חדש – תקבלו סדרה של טאבים של ערכים שונים. בכל טאב שמורה הכתובת של הערך, אבל גם התוכן של הערך. לרשימה הזו, של "המידע הרלוונטי של הפונקציות, מסודר לפי סדר הקריאות להן" קוראים המחסנית.

אין צורך להיכנס יותר מדי לפרטים; כשתוכנית מחשב רצה, יש כמה איזורים עיקריים בזכרון שבהם היא משתמשת, והמחסנית היא אחד מהם. קוראים לה "המחסנית" בגלל האופי שבו מוסיפים ומורידים ממנה דברים; הכלל הוא שהפונקציה האחרונה שהתווספה למחסנית תהיה גם הראשונה שתסולק משם, אחרי שנסיים את הריצה שלה ונצא ממנה (זה לא אומר בשום פנים ואופן שאין לנו דרך לקרוא משהו שאיננו בראש המחסנית, כפי שלפעמים תופסים "מחסנית" במדעי המחשב באופן שגוי). ברקורסיה הפונקציה קוראת לעצמה, אבל ההתנהגות של המחסנית היא זהה – מבחינתה יהיו עליה הרבה עותקים של כתובת חזרה (כשכתובות החזרה יצביעו כולן לתוך הפונקציה הרקורסיבית, למעט הכתובת שנשמרה עם הקריאה הראשונה לפונקציה הרקורסיבית ומצביעה על המקום שבו קראו לה), ולכל עותק של הרקורסיה יהיו המשתנים המקומיים שלו.

אפשרי, כמובן, שיהיה סוג עקיף יותר של רקורסיה: במקום פונקציה A שקוראת לעצמה, פונקציה A שקוראת לפונקציה B שקוראת לפונקציה C שקוראת שוב ל-A – הבנתם את הרעיון. גם כזה דבר מכונה רקורסיה, אבל הוא קצת פחות נפוץ.

בואו נתחיל לראות קוד (קוד רובי, כי זו השפה שאני אוהב). הנה פונקציה רקורסיבית שמחשבת עצרת:

def factorial(n)
	return 1 if n == 0
	return n * factorial(n-1)
end

השורה הראשונה היא מקרה הבסיס – החזר 1 עבור הקלט 0; והשורה השניה היא הקריאה הרקורסיבית. ועכשיו הנה ההזדמנות לדברי כפירה – הפונקציה הרקורסיבית הזו מיותרת. הנה מימוש לא רקורסיבי:

def factorial(n)
	result = 1
	for k in 1..n do
		result *= k
	end
	return result
end

(קצת סירבלתי, אפשר לעשות את זה פשוט יותר ברובי, אבל זה לא פוסט רובי). איזה משני המימושים עדיף? חד משמעית, השני. אבל למה? הראשון הרי נראה אלגנטי יותר! ובכן, השני יקר פחות. אתם מבינים, כשמפעילים רקורסיה, מאחורי הקלעים קורים דברים – המהומות הרגילות של קריאה לפונקציה, דחיפת מידע למחסנית, וכדומה. זה לוקח זמן, וזה גוזל מקום. לכל בעיה כזו כדאי להתייחס בנפרד. מבחינת זמן, ההבדל בזמן הריצה בין שתי הגרסאות שלי עשוי להיות ממש זניח עבור הרצה בודדת של הפונקציה, אבל צריך לזכור כשכותבים קוד שלעתים קרובות אחרי שנכתב קוד, קורה האסון שאנשים אשכרה משתמשים בו. אולי כחלק מדברים אחרים שהם כותבים. ופונקציה תמימה לכאורה עשויה להיקרא מיליארדי פעמים. ובעיה "קלה" בזמן ריצה הופכת לבעיה חמורה, וכדומה. לא פעם ולא פעמיים בעבר כבר חיסלתי פונקציה רקורסיבית והמרתי אותה בפונקציה לא רקורסיבית שקולה פשוט כדי לחסוך זמן והחסכון היה משמעותי.

מקום הוא בעיה אפילו יותר רלוונטית. תחשבו שאנחנו רוצים לחשב את 1000 עצרת – אנחנו הולכים לשמור על המחסנים 1,000 עותקים של הרקורסיה. יש למחסנית כמות מקום מוגבלת. מתישהו היא תיגמר והתוכנית תקרוס, בזמן הריצה. הודעת השגיאה הרלוונטית, stack overflow, היא כל כך נפוצה ומוכרת שהיא הפכה לשמו של אתר שאלות ותשובות בנושאי תכנות סופר-פופולרי. במימוש איטרטיבי באמצעות לולאה לרוב אפשר להסתפק בכמות קבועה של מקום, בלי תלות בכמות האיטרציות שלנו (וגם כשאי אפשר, לרוב עדיין יש חסכון כלשהו). לכן כלל ברזל ברקורסיות הוא: זה אחלה להשתמש בהן, אבל תוודאו בינכם לבין עצמכם שאתם באמת צריכים את זה, או שאין שום סכנה של "התפוצצות" עם קלטים גדולים. והנה עוד דוגמה שממחישה סכנה גדולה אפילו עוד יותר – חישוב מספרי פיבונאצ'י:

def fib(n)
	return 0 if n == 0
	return 1 if n == 1
	return fib(n-1) + fib(n-2)
end

<\pre> הפונקציה הקטנה והחביבה הזו היא אסון מוחלט. היא אחד מקטעי הקוד הגרועים ביותר שניתן להציג. למה? כי היא עושה המון עבודה כפולה. כדי לחשב את מספר פיבונאצ'י עבור 5, הפונקציה קוראת רקורסיבית לחישוב של 4. כחלק מהחישוב של 4 היא מחשבת גם את 3 ו-2, וכן הלאה. אחרי שהיא סיימה היא חוזרת לחישוב של 5 עם הערך של 4, ואז קוראת לחישוב של 3. אבל כבר חישבנו את 3 קודם! המידע פשוט לא שמור בשום מקום והלך לאיבוד. ככל שמספר פיבונאצ'י שאנחנו רוצים לחשב גדל, מספר ה"חישובים הכפולים" שלנו גדל אקספוננציאלית. התוצאה היא בזבוז עצום של זמן ריצה. אל תנסו את זה בבית. אז מה עושים? כמובן, במקרה הנוכחי אפשר פשוט לתת פתרון איטרטיבי:

def fib(n)
	return 0 if n == 0
	a, b = 0, 1
	for k in 2..n do
		a, b = b, a + b
	end
	return b
end

ובמקרים מורכבים יותר, כשבכל זאת רוצים סוג של קריאה רקורסיבית? אז משתמשים במבנה נתונים שנגיש לכל הקריאות של הפונקציה (למשל, כי מעבירים מצביע אליו בכל קריאה של הפונקציה) שבו מאחסנים את המידע של תוצאות הביניים כדי שלא נחשב אותן מחדש בכל פעם. מה שנקרא "תכנון דינמי" זה בדיוק הדבר הזה. לפעמים זה אפילו לא עניין של מידע שכבר חושב, אלא סתם לדעת ש"כבר היינו כאן". למשל, אלגוריתם סטנדרטי למציאת יציאה ממבוך הוא DFS: כשמריצים DFS על משבצת במבוך, אם היא איננה היציאה, אנחנו מריצים DFS על כל אחד מהשכנים של המשבצת. מן הסתם חייבים לסמן איכשהו שכנים שבהם כבר ביקרנו אחרת עוד יצא שנלך ימינה-שמאלה בין אותן שתי משבצות עד אינסוף (ליתר דיוק, עד שנקבל stack overflow). כשהייתי קטן ובניתי משחק של "סוגר שטחים", זה בדיוק מה שקרה לי – כשנסגר שטח ניסיתי לצבוע את כל המשבצות שבתוכו על ידי אלגוריתם רקורסיבי שצובע משבצת ואז מטפל רקורסיבית בשכניה; ברוב חוכמתי פשוט אמרתי "צבע את המשבצת" ולא "אם המשבצת צבועה, אל תעשה כלום; אחרת…". כמובן שקיבלתי stack overflow והייתי מאוד עצוב לראות שאפילו על כמות קטנה של משבצות הרקורסיה שלי מתה ללא סיבה.

פרט לכל אלו, יש שפות תכנות, בעיקר כאלו שבהן מסתמכים באופן מאוד חזק על רקורסיות כדוגמת Haskell, שבהן דברים מטופלים אוטומטית. למשל, מקרה ידוע לשמצה במיוחד של רקורסיה נקרא "רקורסיית זנב". ברקורסיית זנב, הקריאה הרקורסיבית היא הדבר האחרון שמתרחש בתוך הפונקציה הרקורסיבית, והפלט של הרקורסיה הוא הפלט של ההפעלה הרקורסיבית הזו. במקרה הזה ברור שיכלנו לשחרר את המשאבים של הרקורסיה הנוכחית לפני שהפעלנו את הרקורסיה הפנימית, ובכך לחסוך מקום; אבל זה לא קורה אוטומטית בהכרח. קומפיילר חכם כן יודע לעשות דברים כאלו, וגם מתוחכמים יותר (למשל, לטפל בפונקציית העצרת שהראיתי למעלה, שבה הרקורסיה היא "כמעט רקורסיית זנב". לא אכנס לפרטים הללו כאן.

בואו נעבור לראות כמה דוגמאות מעניינות יותר, שהן עדיין ברמת התרגיל אבל הן בכל זאת נחמדות. הדוגמא הראשונה היא משהו שהזכרתי בראשית ימי הבלוג – מגדלי האנוי. מגדלי האנוי הם משחק נחמד שבו יש לנו שלושה "מגדלים" שאפשר להשחיל עליהם טבעות בגדלים שונים. בתחילת המשחק כל הטבעות מסודרות לפי גודל על אחד המגדלים, והמטרה היא להעביר את כולן, מסודרות לפי גודל, למגדל אחר. החוקים: מותר להעביר רק טבעת אחת בפעם, ואסור לשים טבעת גדולה על טבעת שקטנה ממנה. זו הסיבה שבגללה יש שלושה מגדלים – המגדל השלישי הוא "מגדל עזר" שמסייע בהעברת הטבעות. מה שיפה כאן הוא שמספיקים שלושה מגדלים ולא משנה כמה טבעות יש.

הפתרון הרקורסיבי כאן הוא מקסים, כי הוא מציג במדויק את כוחה של החשיבה הרקורסיבית. הוא מחלק את הפתרון לשלושה שלבים: קודם כל נשים הצידה לרגע את כל הטבעות מלבד התחתונה (כלומר, נשים במגדל העזר); אחר כך נעביר את התחתונה אל מגדל היעד שלנו; ואחר כך ניקח את כל הטבעות ששמנו בצד ונעביר למגדל היעד. את הפעולה האמצעית אנחנו יודעים איך לבצע כי היא כוללת רק העברת טבעת אחת, אבל איך אנחנו יכולים להעביר את כל הטבעות "בבת אחת" ממגדל המקור אל מגדל העזר, וממגדל העזר למגדל היעד? ובכן, פשוט מאוד – נפעיל רקורסיבית את הפתרון שלנו… זה אומר שלרגע פשוט נשכח מכך שיש את הטבעת הגדולה שמסתובבת אי שם ונשחק כאילו היא לא קיימת; מכיוון שהיא הגדולה ביותר, היא לא יכולה להפריע לאחרות ולכן מבחינת ההפעלה הרקורסיבית היא באמת לא קיימת. הנה הקוד הפשוט מאוד.

def solve_hanoi(n, source_tower, aux_tower, goal_tower)
	return if n == 0
	solve_hanoi(n-1, source_tower, goal_tower, aux_tower)
	goal_tower.push source_tower.pop
	solve_hanoi(n-1, aux_tower, source_tower, goal_tower)
end

הקוד הזה הוא דוגמה לסיבה שבגללה בחרתי לכתוב דווקא ברובי – הוא כמעט פסאודו-קוד, אבל כזה שעובד ואפשר להריץ. הרעיון הוא שה"מגדלים" נתונים בתור מערכים ברובי, וככאלה הם תומכים בפעולות pop (הוצא את האיבר האחרון והחזר אותו) ו-push (דחוף לסוף המערך). כמו כן, צריך להיות מודעים לכך שמשתנים ברובי תמיד מועברים לפונקציה By Reference; כלומר, לא נוצר עותק נפרד שלהם אלא המשתנה שהפונקציה עובדת איתו הוא בדיוק אותו משתנה שמי שקרא לפונקציה עבד איתו, ולכן שינויים במשתנה שמתרחשים בתוך הפונקציה משפיעים גם מחוצה לה.

ברקורסיה הנוכחית התכונה הזו מנוצלת בצורה חכמה כדי "להחליף תפקידים" בין המגדלים השונים. בקריאה הרקורסיבית הראשונה, מי שהיה מגדל העזר הופך למגדל היעד, ומי שהיה מגדל היעד הופך למגדל העזר. בקריאה השניה החלפה דומה מתבצעת בין מגדל העזר ומגדל המקור. ה"חוכמה" של הפתרון מקופלת כולה בשרשרת החלפות התפקידים הללו שמתבצעת (נסו לעקוב אחרי האופן שבו רצה רקורסיה עבור n שווה 5 כדי לראות כמה החלפות תפקידים כאלו מתבצעות עוד לפני שמזיזים את הטבעת הראשונה). כמובן, אם תרוצו להריץ את התוכנית הזו תתאכזבו נורא כי היא לא עושה שום דבר שאתם מסוגלים לראות. אין הדפסה של המגדלים או משהו דומה. אז למי שרוצה את זה, הנה קוד יותר מלא שגם מדפיס וגם מאתחל וגם הכל:

class Hanoi
	def initialize(n)
		@source_tower = (1..n).to_a
		@aux_tower = []
		@goal_tower = []
		print_state
		solve(n, @source_tower, @aux_tower, @goal_tower)
	end
	def print_state
		puts @source_tower.inspect
		puts @aux_tower.inspect
		puts @goal_tower.inspect
		puts
	end
	def solve(n, source_tower, aux_tower, goal_tower)
			return if n == 0
			solve(n-1, source_tower, goal_tower, aux_tower)
			goal_tower.push source_tower.pop
			print_state
			solve(n-1, aux_tower, source_tower, goal_tower)
	end
end
Hanoi.new(4)

נעבור עכשיו לדוגמה אחרת – ייצור פרמוטציות. פרמוטציה של מערך היא מערך אחר שכולל את אותם איברים בדיוק, אבל בסדר שונה (לצורך העניין נניח שכל האיברים שונים זה מזה). לא קשה להראות שאם במערך יש n איברים, אז מספר הפרמוטציות שלו הוא !n, כך שפונקציה שמוציאה את כל הפרמוטציות של מערך תצטרך לעבוד קשה רק כדי לכתוב את כולן עבור ערכים גדולים של n. לכן די מתבקש להשתמש בפתרון רקורסיבי פה ממילא, כל עוד הוא לא לוקה בבזבוז משווע.

הרעיון הנאיבי הוא זה: תעברו על המערך איבר איבר. לכל איבר – הוציאו אותו מהמערך, בנו רקורסיבית את כל הפרמוטציות של המערך שנשאר, והוסיפו את האיבר שהוצאתם לכולן. הנה קוד שעושה את זה:

def permutations(a)
	n == a.length
	return [a] if n == 1
	result = []
	for i in (0...n) do
		temp_elem, temp_a = a[i], a[0...i] + a[i+1...n]
		for p in permutations(temp_a) do
			result << ([temp_elem] + p)
		end
	end
	return result
end

הקוד הזה הוא בבירור בזבזני – אנחנו יוצרים עותק חדש של המערך על כל הפעלה של הרקורסיה שאנחנו מבצעים. זה אמנם טוב לצורך הדגמת האופן שבו רקורסיה מנצלת את זה שבכל קריאה שלה היא מקבלת מקום נפרד עבור המשתנים שהיא מגדירה, אבל כאן זה מרגיש בזבזני. האם אפשר היה לעשות משהו טוב יותר? התשובה חיובית, אבל לא לגמרי קל לעלות על האלגוריתם או להבין למה הוא עובד. האלגוריתם הזה נקרא "Heap's Algorithm" והרעיון שבו הוא שמספיק לבצע שינויים בתוך המערך שקיבלנו כקלט , וליצור עותק מהמערך רק כשאנחנו מקבלים פרמוטציה שאנחנו רוצים להוסיף לפלט הסופי. הנה איך שזה נראה בקוד:

def permutations_heap(n, a)
	return [a.dup] if n == 1
	result = []
	for i in (0...n) do
		result += permutations_heap(n-1,a)
		a[i], a[n-1] = a[n-1], a[i] if n % 2 == 0
		a[0], a[n-1] = a[n-1], a[0] if n % 2 != 0
	end
	return result
end

בואו נעבור עכשיו לדבר על סוג שונה של בעיות – בעיות הכרעה, ובעיות ספירה נלוות. בבעיות הכרעה מהסוג הנפוץ יש לנו קלט שהוא אובייקט כלשהו שאנחנו תוהים אם הוא מקיים או לא מקיים תכונה מסויימת. בבעיות ספירה גם רוצים לדעת בכמה דרכים שונות התכונה מתקיימת. הנה הדוגמה שאני הולך לפתור – הקלט הוא מערך של מספרים חיוביים ומספר "יעד" כלשהו, והשאלה היא אם אפשר לסכום חלק מאברי המערך כדי להגיע אל היעד – ושאלת ההמשך היא בכמה דרכים שונות אפשר לעשות את זה. הבעיה הזו נקראת Subset Sum וזו בעיה NP-שלמה מפורסמת, למי שהביטוי הזה אומר לו משהו. התכל'ס של מה שזה אומר הוא שלא סביר שנצליח למצוא פתרון שהוא ממש יעיל, אז יאללה, בואו נתפרע עם רקורסיה.

אלגוריתם רקורסיבי כאן כותב כמעט את עצמו. אנחנו צריכים להגיע למספר יעד כלשהו; אנחנו בוחנים את המספר הראשון במערך. או שנוסיף אותו לסכום, או שלא. עבור כל אחת משתי האפשרויות הללו אנחנו מבצעים קריאה רקורסיבית על יתר המערך; במקרה שבו הוספנו את המספר לסכום, אנחנו מפחיתים אותו מה"יעד". העובדה שאני מניח שהמספרים הם כולם חיוביים עוזרת לי "להפסיק באמצע" בלי לבזבז זמן על חלק מהחישובים המיותרים – אם מספר היעד הפך להיות 0 פתאום, אני יודע שכבר הצלחתי ואני מסיים עם הפתרון הנוכחי (אני לא הולך להוסיף לו עוד שום דבר, מן הסתם). אם מספר היעד הופך להיות שלילי אני יודע שנכשלתי. לרקורסיה מסוג זה, שמסוגלת לזהות הצלחה או כשלון לפעמים "באמצע" ולחזור בהתאם קוראים Backtracking.

עם קצת להטוטי רובי אפשר לכתוב את הפתרון בשלוש שורות:

def subset_sum(a, n)
	return [] if n < 0 or (n > 0 and a.empty?) #empty solution set
	return [ [] ] if n == 0   #one solution - no elements
	return subset_sum(a[1..-1], n) + subset_sum(a[1..-1], n - a[0]).map{|sol| [a[0]] + sol}
end

השורה השלישית אולי נראית קצת מפחידה. אני בסך הכל אומר לקחת את כל הפתרונות לגודל n שמערבים את המערך בלי האיבר הראשון, ולהוסיף להם את כל הפתרונות שמערבים את המערך בלי האיבר הראשון, עבור הסכום n פחות האיבר הראשון, כשאני לוקח כל פתרון כזה ומוסיף לו בהתחלה את האיבר הראשון.

האם כאן אני יכול לתת פתרון איטרטיבי קצר? ובכן, לא ממש! אין לי רעיון איך לעשות פתרון שיהיה גם קצר וגם קריא וגם יעשה backtracking דומה. כמובן, תמיד אפשר לייצר סדרתית את כל המספרים מ-0 ועד 2 בחזקת גודל המערך פחות 1, להסתכל על הייצוג הבינארי שלהם ולסכום את האיברים שמתאימים למקומות שבהם כתוב 1; אבל זה כבר מסורבל למדי (אם כי פרקטי יותר, לפעמים; כאן, לא חושב) ואני לא רואה דרך נחמדה לשמר כך את תכונת ה-backtracking.

ואיך אפשר בלי פתרון מבוך. אני מניח שהמבוך נתון על ידי מערך דו ממדי שבו 0 מייצג משבצת פנויה ו-1 מייצג קיר, ושהמטרה היא להגיע אל 0,0. אני מרשה לעצמי "לקשקש" על המבוך – לכתוב 2 כדי לתאר משבצת שכרגע היא פוטנציאל למסלול היציאה, ו-3 למשבצת שכבר ויתרנו עליה. כך, אם נמצא מסלול ליציאה, הוא יהיה כתוב בתוך המבוך על ידי המשבצות שבהן כתוב 2:

def solve_maze(maze, row, col)
	return false if row < 0 or col < 0 or row >= maze.length or col >= maze.first.length or maze[row][col] != 0
	maze[row][col] = 2
	return true if row == 0 and col == 0
	neighbors = row + 1, col], [row - 1, col], [row,  col + 1], [row, col - 1
	neighbors.each{|row, col| return true if solve_maze(maze, row, col)}
	maze[row][col] = 3
	return false
end

ולמי שרוצה לראות את זה בפועל, הנה עוד קצת קוד שמאפשר לצייר מבוך ואת המסלול ליציאה שבתוכו, אם יש, ודוגמת הרצה:

def print_maze(maze)
	sym = {0 => " ", 1 => "+", 2 => ".", 3 => " "}
	maze.map{|row| row.map{|v| sym[v]}}.each{|row| puts row.join("")}
end
maze = [[0, 0, 1, 1, 1, 1, 1],
		[1, 0, 1, 1, 1, 0, 1],
		[1, 0, 1, 0, 0, 0, 1],
		[1, 0, 1, 0, 1, 0, 1],
		[1, 0, 0, 0, 1, 0, 1],
		[1, 1, 1, 1, 1, 1, 1]
	   ]

print_maze(maze)
puts
solve_maze(maze,4,5)
print_maze(maze)

ואפשר להמשיך ולתת עוד ועוד דוגמאות, אבל נראה לי שהבנו את הרעיון ואפשר לעצור כאן. למרות שאם אתם עדיין לא מרוצים, נסו לקרוא את הפוסט שלי כאן.

משפט הפונקציה ההפוכה ומשפט הפונקציות הסתומות

פרק ראשון, ובו בקושי התחלנו וכבר אנחנו מעגלים פינות

בואו נדבר על מעגל. מעגל הוא הצורה החביבה עלינו. אנחנו אוהבים את המעגל. מהו המעגל? עבורנו זה אוסף כל הנקודות ב-\(\mathbb{R}^{2}\) שמרחקן מנקודה נתונה ("המרכז") הוא זהה (ונקרא "הרדיוס" של המעגל). איך אנחנו מודדים "מרחק"? אצלנו המרחק של \(\left(x_{1},y_{1}\right)\) מ-\(\left(x_{2},y_{2}\right)\) הוא \(\sqrt{\left(x_{2}-x_{1}\right)^{2}+\left(y_{2}-y_{1}\right)^{2}}\). בואו נתמקד במעגל היחידה – מעגל ברדיוס 1 שמרכזו בראשית הצירים, כלומר ב-\(\left(0,0\right)\). מעגל כזה הוא אוסף כל הנקודות \(\left(x,y\right)\) שמקיימות את המשוואה \(x^{2}+y^{2}=1\), כלומר הקבוצה \(\left\{ \left(x,y\right)|\ |\ x^{2}+y^{2}=1\right\} \). אתם בוודאי כבר יודעים את כל זה, אבל אני הולך להשתמש במעגל הזה בצורה כל כך אינטנסיבית שטוב שנוודא שאנחנו מבינים על מה מדובר.

לא הלכתם לאיבוד. אנחנו עדיין בסדרת הפוסטים שלי על אנליזה וקטורית. במה אנחנו מתעסקים? בפונקציות מרובות משתנים. האם מעגל הוא פונקציה מרובת משתנים שכזו? לא! מעגל, כפי שאמרתי, הוא אוסף נקודות שמקיים תכונה מסויימת – אילוץ מסויים, אם תרצו. אבל זה לא אומר שאי אפשר לחשוב עליו בגישה פונקציונלית. הנה גישה כזו: נגדיר פונקציה \(F\left(x,y\right)\) באופן הבא: \(F\left(x,y\right)=x^{2}+y^{2}-1\). כעת, מעגל היחידה הוא בדיוק אוסף כל הקלטים שמאפסים את הפונקציה הזו. קיבלנו דרך התבוננות חדשה על אובייקטים גאומטריים – אוסף האפסים של פונקציה מסויימת. זו, למשל, נקודת המוצא של גאומטריה אלגברית, שמתעסקת (ברמה הבסיסית ביותר שלה – מדובר על תחום סבוך בצורה מטורפת) בקבוצות שניתן להגדיר באמצעות אוסף האפסים של פולינום מרובה משתנים שכזה (כמו המעגל).

בואו ניקח לרגע עוד דוגמה. הפונקציה \(F\left(x,y\right)=y-x^{2}\), שמתאימה למשוואה \(y=x^{2}\) שמתארת פרבולה. הדוגמה הזו מעניינת, כי אנחנו רואים בה בבירור שאפשר לחשוב על כל ערך של \(y\) כאילו הוא נקבע באופן יחיד על ידי הערך של \(x\); במילים אחרות, קיימת פונקציה במשתנה יחיד, \(f\left(x\right)\), כך ש-\(y=f\left(x\right)\) מתאר בדיוק את הפרבולה. אם לחדד, אנחנו מקבלים ש-\(F\left(x,f\left(x\right)\right)=0\) לכל \(x\), ואנחנו מאוד מרוצים מעצמנו ואומרים ש-\(f\) הוא חילוץ של \(y\) מתוך \(F\).

האם זה עובד גם עבור המעגל? ובכן, לחלוטין לא. אם תסתכלו על מעגל, קל לראות שהוא אינו גרף של פונקציה. הנה קריטריון פשוט כדי לזהות אם אובייקט גאומטרי הוא גרף של פונקציה (במקרה שלנו, ש-\(y\) הוא פונקציה של \(x\)): אם אתם יכולים להעביר קו אנכי כלשהו, כך שהוא יחתוך את האובייקט שלכם פעמיים, אז זו אינה פונקציה, כי יש ערך של \(x\) שעבורו יש שני ערכים אפשריים של \(y\). אבל מה כן אפשר לומר על מעגל? שהוא מורכב משילוב של שתי פונקציות, אחת שמתארת את כל מה שקורה מעל ציר \(x\), והשניה את כל מה שקורה מתחת לציר \(x\).

בואו נחזור אל המשוואה \(x^{2}+y^{2}=1\) שהגדירה את המעגל. נניח שאנחנו רוצים "לחלץ" את \(y\) כפונקציה של \(x\), מה נעשה? נעביר את \(x\) אגף ונוציא שורש. נקבל \(y=\pm\sqrt{1-x^{2}}\). קיבלנו את שתי הפונקציות שדיברתי עליהן – \(y=\sqrt{1-x^{2}}\) מתאר את מה שקורה מעל ציר \(x\) ו-\(y=-\sqrt{1-x^{2}}\) מתאר את מה שקורה מתחת.

אתן הגדרה פורמלית בהמשך, אבל לא פורמלית, המשוואה \(x^{2}+y^{2}=1\) מגדירה את מה שנקרא פונקציות סתומות (באנגלית Implicit Functions נשמע יותר טוב ויותר הגיוני, אבל מהווה חומר פחות טוב לבדיחות שוביניסטיות). פונקציה סתומה היא פונקציה שלא נתונה לנו במפורש, אלא ניתנת להסקה מתוך משוואה כמו זו שלעיל, ומגדירה מעין פתרון שלה. כמובן, זה לא תיאור פורמלי במיוחד ולא ברור למה נתתי דווקא את שתי הפונקציות \(\sqrt{1-x^{2}}\) ו-\(-\sqrt{1-x^{2}}\) בתור הפונקציות הסתומות שניתנות להסקה מהמשוואה, הרי יש עוד הרבה (למשל \(g\left(x\right)=\begin{cases}\sqrt{1-x^{2}} & 0\le x\le1\\-\sqrt{1-x^{2}} & -1\le x\le0\end{cases}\)). נדבר על כל זה בהמשך.

פרק שני, שבו אנחנו מנסים להיחלץ אבל רק מסתבכים בצורה סתומה

עכשיו אני רוצה לדבר על מה זה בעצם אומר, "לחלץ". מה שאעשה עשוי להיראות סבוך שלא לצורך, אבל חייבים לזכור שאני לא מנסה לפתור את הדוגמה שאני עובד איתה – כבר פתרנו אותה! אני רוצה למצוא משהו שיעבוד במקרים כללים יותר. הרבה, הרבה, הרבה יותר.

אז בואו נחזור אל \(F\left(x,y\right)=x^{2}+y^{2}-1\). אני רוצה לקבל מהיצור הזה את \(y\). אמרתי "נעביר אגפים". אבל מה זו העברת אגפים, במתמטיקה? זה אומר לחבר את אותו איבר לשני האגפים. אם אני מעביר את \(x^{2}\) אגף, אני בעצם מחבר לשני האגפים את \(-x^{2}\). אז בואו ניקח את \(F\left(x,y\right)\) ונעשה עליה את זה – נקבל \(y^{2}=F\left(x,y\right)-x^{2}+1\), ואחרי הוצאת שורש חיובי נקבל \(y=\sqrt{F\left(x,y\right)-x^{2}+1}\).

אפשר לחשוב על ה"חילוץ" הזה בתור תהליך שקיבל שני קלטים ועשה איתם הוקוס פוקוס כדי לקבל את \(y\). הקלטים היו \(F\left(x,y\right)\) אבל גם \(x\) – נזקקתי לשני המספרים הללו (במקרה הנוכחי נזקקתי ל-\(x\) כדי לדחוף את \(-x^{2}\) לחישוב). את העסק הזה אפשר לתאר באמצעות פונקציה, \(h\left(a,b\right)\), שמקיימת \(y=h\left(x,F\left(x,y\right)\right)\). כעת, אם \(\left(x,y\right)\) הוא קלט שמאפס את \(F\), אז נקבל ש-\(y=h\left(x,0\right)\); כלומר, אם אגדיר פונקציה \(g\left(x\right)=h\left(x,0\right)\) אז הפונקציה \(g\left(x\right)\) הזו תהיה בדיוק חילוץ של \(y\) כפי שרציתי. אז התעלומה הגדולה היא איך אפשר לקבל את \(h\) הזו באופן כללי.

אנסח במדויק את השאלה שלי: בהינתן \(F\left(x,y\right)\), האם קיימת פונקציה \(h\left(a,b\right)\) כך ש-\(y=h\left(x,F\left(x,y\right)\right)\), ואיך נמצא כזו? הבעיה הזו מזכירה לנו את בעיית ההיפוך של פונקציות, רק שזה לא בדיוק מה שקורה כאן: זה נראה שאנחנו הופכים את \(F\) במובן מסויים, אבל רק חלקי, כי \(F:\mathbb{R}^{2}\to\mathbb{R}\) היא פונקציה בשני קלטים ופלט אחד, ואנחנו מבקשים להפוך את הפלט הזה ולקבל ממנו את הקלט השני, אבל לא מספיק לנו לקבל את הפלט – כפי שראינו קודם, אנחנו צריכים לקבל גם את \(x\), לכן \(h:\mathbb{R}^{2}\to\mathbb{R}\) היא בעצמה פונקציה בשני משתנים. זו הסיבה להגדרה הזו, שנראית מוזרה במבט ראשון: אנחנו מגדירים פונקציה \(\Phi:\mathbb{R}^{2}\to\mathbb{R}^{2}\) כך ש-\(\Phi\left(x,y\right)=\left(x,F\left(x,y\right)\right)\), וכעת אנו שואלים את עצמנו האם קיימת ל-\(\Phi\) הופכית. אם קיימת, אז אותה ב- \(\Phi^{-1}\left(a,b\right)\). המשמעות של הופכית היא שמתקיים \(\Phi^{-1}\left(x,F\left(x,y\right)\right)=\left(x,y\right)\) לכל \(\left(x,y\right)\); מכאן ש-\(\Phi^{-1}\) היא מהצורה \(\Phi^{-1}\left(a,b\right)=\left(a,h\left(a,b\right)\right)\), ו-\(h\) הזו היא בדיוק הפונקציה שרצינו.

הצלחתם לעקוב, בערך, אחרי מה שהלך כאן? ברכותי, זו, בערך, ההוכחה של משפט הפונקציות הסתומות שאפילו לא ניסחתי עדיין פורמלית. הסיבה העיקרית שנכנסתי כל כך לפרטים הללו לפני שמגיעים לניסוחים הפורמליים היא כדי שנראה מייד מהו החלק בהוכחה שמבצע את העבודה הקשה אצלנו: ה"קסם" שמאפשר לנו, בהינתן \(\Phi\), לקבל שקיימת פונקציה הופכית \(\Phi^{-1}\), וממנה אנחנו כבר מחלצים את הפונקציה \(h\) שממנה אנחנו מחלצים את הפונקציה \(g\) שהיא החילוץ של \(y\) מתוך \(F\).

תנשמו עמוק.

ועכשיו נופל עלינו הר של שאלות ופרטים – מי מבטיח לנו ש-\(\Phi\) הזו הפיכה? מתי זה קורה? באילו תנאים? איך כמה ולמה? האמנם? מדוע? כיצד? וכו' וכו' וכו'. אלו הדברים שנתעסק בהם עכשיו. נתחיל עם הצגה פורמלית של משפט הפונקציה ההפוכה שמטפל בתנאים שבהם אכן ניתן להפוך את \(\Phi\) ופונקציות כלליות יותר; אחר כך נעבור להצגה פורמלית של משפט הפונקציות הסתומות; אחר כך נוכיח פורמלית את משפט הפונקציות הסתומות (הוכחה שתהיה דומה למה שהראיתי אבל מפורטת יותר) ובסוף, אחרי שכבר כולנו נהיה גמורים לחלוטין, נגיע להוכחה של משפט הפונקציה ההפוכה, שהוא החלק הכבד ביותר כאן.

יהיה בסדר.

פרק שלישי, ובו מתחילים עם הגדרות פורמליות ושום דבר לא בסדר

יש שתי נקודות עיקריות שינחו את מה שנעשה עכשיו. ראשית, הפונקציות שבהן אנחנו נתעסק (גם מה שאנחנו מקבלים כקלט וגם מה שאנחנו רוצים שיצא כפלט) הולכות להיות נחמדות מנקודת מבטה של האנליזה; באנליזה אוהבים פונקציות רציפות, ועוד יותר אוהבים פונקציות גזירות, ועוד יותר אוהבים פונקציות גזירות שגם הנגזרת שלהן רציפה, ועוד יותר אוהבים פונקציות גזירות שגם הנגזרת שלהן גזירה, וכן הלאה. שנית, כל ההיפוכים וחילוצי הפונקציות הסתומות הולכים להיות מקומיים; הטיעונים לא יהיו בסגנון "הנה פונקציה \(F:\mathbb{R}^{n}\to\mathbb{R}^{n}\), והנה פונקציה \(F^{-1}:\mathbb{R}^{n}\to\mathbb{R}^{n}\) שהיא ההופכית שלה". תמיד נגיד "בואו ניקח חתיכה \(A\subseteq\mathbb{R}^{n}\) ונהפוך את \(F\) רק בה". המעגל מתחילת הפוסט הוא המחשה טובה לסיבה שבגללה מקומיות שכזו היא הכרחית. אם אנחנו רוצים לחלץ את \(y\) כפונקציה של \(x\) מתוך המעגל, אנחנו מצטמצמים בכל פעם לחתיכה מהמעגל שכוללת נקודה כלשהי עליו ואת הסביבה הקרובה אליה; אם ניקח יותר מדי מהמעגל, נקבל בסופו של דבר נקודות שמתאימות לאותו ערך \(x\) ולשני ערכי ה-\(y\)-ים המתאימים לו, ואז לא תהיה לנו שום תקווה לחלץ את \(y\) כפונקציה של \(x\). שימו לב גם לכך שנקודות הקצה הימנית והשמאלית של המעגל הן כאלו שלא משנה איזו סביבה שלהן ניקח, חילוץ כזה עדיין יהיה בלתי אפשרי – עוד מעט נראה בדיוק את הקריטריון הפורמלי שלא מתקיים במקרה הזה.

בואו ניגש סוף סוף לפורמליזם. נתחיל עם משפט הפונקציה ההפוכה. נניח שיש לנו \(A\subseteq\mathbb{R}^{n}\) שהיא קבוצה פתוחה, ופונקציה \(F:A\to\mathbb{R}^{n}\) שהיא ב-\(C^{r}\) (כלומר, גזירה ברציפות \(r\) פעמים). ניקח נקודה \(a\in A\) כך ש-\(DF\left(a\right)\) היא הפיכה בנקודה הזו (כלומר, \(\det DF\left(a\right)\ne0\)). אז יש קבוצה פתוחה \(U\subseteq A\) כך ש-\(a\in U\) ו-\(F\) היא חח"ע על \(U\), ולכן אם נסמן \(V=F\left(U\right)\) נקבל ש-\(F:U\to V\) הפיכה וההופכית \(F^{-1}:V\to U\) שלה גם היא שייכת ל-\(C^{r}\).

שימו לב למה שהמשפט הזה עושה – סוג של רדוקציה לאלגברה לינארית. רוצים להפוך את \(F\)? בואו תסתכלו על הקירוב הלינארי של \(F\) בנקודה מסויימת, ותבדקו האם אותו קירוב לינארי הוא הפיך. אם כן, נשתמש ביכולת שלנו להפוך את הקירוב הלינארי הזה כדי לקבל את ההופכית של \(F\) סביב אותה נקודה. זה תמיד נחמד שתחומים מתמטיים מתנגשים.

להוכיח את קיום ההופכית יהיה קל יחסית; עיקר הקושי יהיה להוכיח שההופכית שייכת ל-\(C^{r}\). נחזור אל זה, כמובטח, בהמשך.

בואו נעבור עכשיו אל משפט הפונקציות הסתומות. כל הדיון שניהלתי עד כה עסק בפונקציות שמתוארות בצורה סתומה על ידי \(F:\mathbb{R}^{2}\to\mathbb{R}\), כלומר על ידי משוואה אחת בשני נעלמים שמתוכם אנחנו רוצים לחלץ אחד כפונקציה של השני. המשפט הכללי רוצה לעסוק בסיטואציה שבה יש לנו \(n+k\) משתנים, כך שאנחנו רוצים לחלץ את \(n\) המשתנים האחרונים כפונקציה של \(k\) המשתנים הראשונים. בשביל זה אנחנו זקוקים ל-\(n\) משוואות (מי שלא ברור לו למה, נסו לזכור מה קורה באלגברה לינארית). כלומר, אנחנו הולכים להתעסק עם פונקציה \(F:A\to\mathbb{R}^{n}\) כך ש-\(A\subseteq\mathbb{R}^{n+k}\) פתוחה. כרגיל, נניח ש-\(F\) ב-\(C^{r}\) עבור \(r\) כלשהו. עכשיו, מכיוון שלהתעסק עם \(n+k\) משתנים זה כאב ראש, אני אסמן את \(F\) בתור \(F\left(x,y\right)\) כך ש-\(x\) היא קבוצת \(k\) המשתנים הראשונים (כלומר, זו דרך מקוצרת לכתוב \(x_{1},\dots,x_{k}\)) ו-\(y\) היא \(n\) המשתנים האחרונים.

בואו ניקח נקודה \(\left(a,b\right)\) (שוב, \(a\) היא בעצם \(k\) קואורדינטות ו-\(b\) היא \(n\)) כך ש-\(F\left(a,b\right)=0\) (זו המקבילה שלנו לנקודה על המעגל שסביבה אנחנו רוצים לחלץ). עכשיו, \(DF\left(a,b\right)\) היא מטריצה מסדר \(n\times\left(n+k\right)\); אנחנו יכולים לקחת אותה ולהצטמצם לתת-המטריצה של \(n\) העמודות האחרונות ולקבל מטריצה \(n\times n\) שאסמן \(\frac{\partial F}{\partial y}\). כדי שהחילוץ יהיה אפשרי, אני דורש שיתקיים \(\det\frac{\partial F}{\partial y}\left(a,b\right)\ne0\), כלומר שתת-המטריצה הזו היא הפיכה. אם זה קורה, אז יש קבוצה פתוחה \(U\subseteq\mathbb{R}^{k}\) כך ש-\(a\in U\), ופונקציה \(g:U\to\mathbb{R}^{n}\) ב-\(C^{r}\) שמקיימת \(g\left(a\right)=b\) ו-\(F\left(x,g\left(x\right)\right)=0\) לכל \(x\in U\). \(g\) הזו היא החילוץ. מה שמעניין במיוחד פה הוא ש-\(g\) היא יחידה, כלומר אין שני חילוצים שונים שאפשר להגדיר על \(U\).

הדרישה ש-\(\det\frac{\partial F}{\partial y}\left(a,b\right)\ne0\) היא בדיוק מה שחסר בדוגמה שלנו עם המעגל כשאנחנו רוצים לבצע חילוץ בנקודות הקצה האופקיות. במקרה שלנו, \(F\left(x,y\right)=x^{2}+y^{2}-1\) ולכן \(Df=\left[2x,2y\right]\) ולכן \(\frac{\partial F}{\partial y}=2y\) (זה אכן הסימון המקובל לרוב לנגזרת חלקית) ובשתי הנקודות הקצה הללו (\(\left(-1,0\right),\left(1,0\right)\)) מתקיים ש-\(\frac{\partial F}{\partial y}=0\). לכן אלו הנקודות שבהן לא ניתן לבצע חילוץ של \(y\) .

פרק רביעי, ובו דוגמה זריזה שתיקח לנו הרבה מאוד זמן

הנה דוגמה זריזה לשימוש נחמד במשפט: גזירה סתומה. לפעמים אין לנו דרך לחלץ את \(g\left(x\right)\) באופן מפורש מהביטוי הסתום \(F\), אבל אנחנו עדיין צריכים לדעת משהו על הנגזרת שלה; אז אפשר לקבל ביטוי סתום גם עבור הנגזרת. בואו נסתכל על דוגמת המעגל שלנו. אמנם, שם אפשר לחלץ במפורש, אבל בואו נראה מה אפשר לעשות גם בלי זה.

הנגזרת של \(F\left(x,y\right)\) היא וקטור עם שתי כניסות, שהן הנגזרות החלקיות: \(\left[\frac{\partial F}{\partial x},\frac{\partial F}{\partial y}\right]\). על \(F\left(x,g\left(x\right)\right)\) אפשר לחשוב בתור הרכבה של \(F\) על פונקציה \(T:\mathbb{R}\to\mathbb{R}^{2}\) שמוגדרת על ידי \(T\left(x\right)=\left(x,g\left(x\right)\right)\) והנגזרת שלה היא הוקטור \(\left[\begin{array}{c}1\\g^{\prime}\end{array}\right]\). ההרכבה של שתיהן היא פונקציה רגילה, \(f:\mathbb{R}\to\mathbb{R}\) שמוגדרת על ידי \(f\left(x\right)=F\left(T\left(x\right)\right)=F\left(x,g\left(x\right)\right)\). את הנגזרת שלה אפשר לחשב על ידי כלל השרשרת ולקבל ש-

\(f^{\prime}\left(a\right)=DF\left(\left(a,g\left(a\right)\right)\right)\cdot DT\left(a\right)=\left[\frac{\partial F}{\partial x}\left(a,g\left(a\right)\right),\frac{\partial F}{\partial y}\left(a,g\left(a\right)\right)\right]\cdot\left[\begin{array}{c}1\\g^{\prime}\left(a\right)\end{array}\right]=\frac{\partial F}{\partial x}\left(a,g\left(a\right)\right)+\frac{\partial F}{\partial y}\left(a,g\left(a\right)\right)g^{\prime}\left(a\right)\)

(חלקכם אולי שמים לב שאני מתחיל לרמות בסימונים ולא להבדיל בין טרנספורמציה לינארית ממימד 1 על 1 ובין סקלר; רמאויות כאלו הופכות להכרחיות כשלא רוצים להיות ממש טרחניים בסימונים).

עכשיו, מכיוון ש-\(f\left(x\right)=F\left(x,g\left(x\right)\right)\) שווה זהותית לאפס, היא פונקציה קבועה, ולכן גם הנגזרת שלה שווה זהותית לאפס. המסקנה שלנו היא שמתקיים

\(\frac{\partial F}{\partial x}\left(a,g\left(a\right)\right)+\frac{\partial F}{\partial y}\left(a,g\left(a\right)\right)g^{\prime}\left(a\right)=0\)

וקיבלנו משוואה חדשה שמערבת את \(g^{\prime}\left(a\right)\) ואפשר לחלץ אותה משם ולקבל \(g^{\prime}\left(a\right)=-\frac{\partial F/\partial x}{\partial F/\partial y}\left(a,g\left(a\right)\right)\). במילים אחרות, גם בלי להיות מסוגלים למצוא ביטוי מפורש ל-\(g\), אנחנו עדיין יכולים לחשב את הנגזרת של \(g\). אצלנו מתקיים \(F\left(x,y\right)=x^{2}+y^{2}-1\) ולכן \(\frac{\partial F}{\partial x}=2x\) ו-\(\frac{\partial F}{\partial y}=2y\) ונקבל ש-\(g^{\prime}\left(x\right)=-\frac{2x}{2g\left(x\right)}=-\frac{x}{g\left(x\right)}\) – תבדקו ותראו שאכן \(\sqrt{1-x^{2}}\) ו-\(-\sqrt{1-x^{2}}\) מקיימות זאת.

בתיכון במקום להשתמש בסימני פונקציות מפורשים הרבה פעמים אוהבים לכתוב \(y=\sqrt{1-x^{2}}\) וכדומה, ואז להשתמש בסימון כמו \(y^{\prime}=-\frac{x}{\sqrt{1-x^{2}}}\). דרך ההצגה הזו היא מצד אחד מבלבלת, ומצד שני היא מאפשרת לנו לבצע גזירה סתומה בצורה יחסית פשוטה: קחו את הביטוי \(x^{2}+y^{2}-1\), ועכשיו תגזרו את הכל לפי \(x\). הנגזרת של ה-\(y^{2}\) היא כמובן \(2yy^{\prime}\), על פי כלל השרשרת (לא רואים את זה? מה הנגזרת של \(\left[g\left(x\right)\right]^{2}\)?). לכן נקבל \(2x+2yy^{\prime}=0\) ומכאן נקבל \(y^{\prime}=-\frac{x}{y}\). בהחלט יותר קל לזכור את הטכניקה הזו מאשר את הנוסחה שכתבתי למעלה, למרות שהן בעצם אותו הדבר בדיוק.

אבל רגע, כל הדיון הזה היה רק עבור המקרה הפשוט של פונקציות בשני משתנים. מה קורה באופן כללי? ובכן, עדיין מקבלים משוואות כמו זו שלמעלה, אבל מקבלים יותר משוואות, והמשוואות ארוכות יותר. הצורה הכללית של משוואה כזו היא

\(D_{j}F^{i}\left(a,g\left(a\right)\right)+\sum_{t=1}^{n}D_{k+t}F^{i}\left(a,g\left(a\right)\right)D_{j}g^{t}\left(a\right)=0\)

כאשר \(1\le i,j\le n\). הדבר הזה הוא מערכת משוואות לינארית ב"נעלמים" \(g^{1}\left(a\right),\dots,g^{n}\left(a\right)\) ומכיוון ש-\(\det\frac{\partial F}{\partial y}\ne0\) ניתן לפתור אותה, אבל לא אכנס לפרטים יותר מכך.

פרק חמישי, ובו אנחנו מוכיחים את משפט הפונקציות הסתומות וכבר אין לנו כוח לכותרת מתחכמת

בואו נראה עכשיו את ההוכחה של משפט הפונקציות הסתומות, שדומה למה שעוללתי בתחילת הפוסט. אנחנו מגדירים \(\Phi:A\to\mathbb{R}^{n+k}\) על ידי \(\Phi\left(x,y\right)=\left(x,F\left(x,y\right)\right)\). אנחנו רוצים להפוך את הפונקציה הזו בעזרת משפט הפונקציה ההפוכה, ולשם כך צריך להוכיח שהנגזרת שלה הפיכה. הגזירות של \(\Phi\) נובעת מייד מהגזירות של \(F\) (ומכך שהפונקציה \(G\left(x,y\right)=x\) היא גזירה באופן כמעט טריוויאלי). נקבל את הנגזרת \(D\Phi=\left[\begin{array}{cc}I_{k} & 0\\\frac{\partial F}{\partial x} & \frac{\partial F}{\partial y}\end{array}\right]\). זו מטריצת בלוקים, שאתם אמורים להכיר מלינארית; הבלוקים ב"שורה" הראשונה מתאימים ל-\(G\left(x,y\right)=x\) וב"שורה" השניה ל-\(F\). חישוב דטרמיננטה של מטריצת בלוקים זה קל, ואנחנו מקבלים ש-\(\det D\Phi=\det\frac{\partial F}{\partial y}\). כאן נכנס לתמונה השימוש בכך ש-\(\det\frac{\partial F}{\partial y}\ne0\); בלי זה לא היינו מסוגלים לבצע את ההיפוך שהכרחי לצורך החילוץ.

יופי. אז עכשיו אפשר להשתמש במשפט הפונקציה ההפוכה ולהסיק שקיימת קבוצה פתוחה מהצורה \(U\times V\) עם \(U\subseteq\mathbb{R}^{k}\) ו-\(V\subseteq\mathbb{R}^{n}\) פתוחות, שמכילה את \(\left(a,b\right)\) (הנקודה שסביבה אנחנו רוצים לחלץ) וקבוצה פתוחה \(W\) שמכילה את \(\Phi\left(a,b\right)=\left(a,0\right)\), כך ש-\(\Phi:U\times V\to W\) היא הפיכה. שימו לב שההנחה שהקבוצה הפתוחה שלי היא מהצורה \(U\times V\) היא לא לגמרי מיידית כי משפט הפונקציה ההפוכה מבטיח לי "רק" קבוצה פתוחה ב-\(\mathbb{R}^{n+k}\), לא כזו שנראית כמו מעין מלבן שכזה; אבל אפשר להצטמצם לתת-קבוצה שכן נראית ככה.

עכשיו, \(\Phi^{-1}\) חייבת להיות כזו שב"קואורדינטה הראשונה" (בעצם ב-\(k\) הראשונות) משאירה את הקלט שלה ללא שינוי, כלומר מהצורה \(\Phi^{-1}\left(x,y\right)=\left(x,h\left(x,y\right)\right)\) כאשר \(h:W\to V\). זאת מכיוון ש-\(\Phi\) מקבעת את הקואורדינטה הראשונה הזו. נשאר לנו רק להגדיר \(g\left(x\right)=h\left(x,0\right)\), כמו בדוגמה. מכיוון ש-

\(\left(a,b\right)=\Phi^{-1}\left(\Phi\left(a,b\right)\right)=\Phi^{-1}\left(a,F\left(a,b\right)\right)=\Phi^{-1}\left(a,0\right)=\left(a,h\left(a,0\right)\right)=\left(a,g\left(a\right)\right)\)

קיבלנו ש-\(g\left(a\right)=b\) כפי שרצינו. כל מה שנשאר לעשות הוא להשתכנע שמתקיים \(F\left(x,g\left(x\right)\right)=0\) לכל \(x\in U\).

לצורך כך, ראשית כל נשים לב ש-\(\Phi^{-1}\left(x,0\right)=\left(x,h\left(x,0\right)\right)=\left(x,g\left(x\right)\right)\). כעת נפעיל את \(\Phi\) על שני האגפים ונקבל \(\left(x,0\right)=\Phi\left(x,g\left(x\right)\right)=\left(x,F\left(x,g\left(x\right)\right)\right)\), ועכשיו מהשוואת הקואורדינטות נקבל ש-\(F\left(x,g\left(x\right)\right)=0\), כפי שרצינו.

הגזירות של \(g\) נובעת מייד מכך שמשפט הפונקציה ההפוכה משמר את הגזירות של מה שהוא מופעל עליו. מכיוון ש-\(F\) הייתה ב-\(C^{r}\), כך גם \(\Phi\), שהרכיבים שלה הם \(F\) ופונקציית הזהות; ולכן גם \(\Phi^{-1}\) ב-\(C^{r}\), ולכן גם \(h\) שהיא רכיב של \(\Phi^{-1}\), ולכן גם \(g\) שהיא צמצום של \(h\).

מה נשאר? להוכיח ש-\(g\) היא יחידה. נניח ש-\(k\left(x\right)\) היא פונקציה כלשהי שמקיימת את המשפט, כלומר ש-\(F\left(x,k\left(x\right)\right)=0\) לכל \(x\in U\), ש-\(k\left(x\right)\) רציפה (לא צריך אפילו \(C^{r}\)) ושהיא מקיימת \(k\left(a\right)=b\). בשביל ההוכחה הזו אני אצטרך טיפה להתחכם יותר עם ההגדרה של \(g\). כרגע \(g\) מוגדרת על כל ההיטל של \(W\) על \(k\) הכניסות הראשונות. מה שאני רוצה בפועל הוא שהיא תהיה מוגדרת על קבוצה קשירה \(B\) כך ש-\(B\times\left\{ 0\right\} \subseteq W\) – תמיד אפשר להצטצמם כדי לקבל את זה. מה זו קבוצה קשירה? אינטואיטיבית זו קבוצה שלא מורכבת משני חלקים נפרדים; פורמלית, זו קבוצה שלא ניתן לכתוב בתור איחוד של שתי קבוצות פתוחות זרות לא ריקות. כדי להבין מה עשוי להשתבש עם קבוצה כזו חשבו לרגע על המעגל שלנו. אם, למשל, \(W\) הייתה מורכבת משני מלבנים נפרדים, אז בכל אחד מהמלבנים הללו הייתה לנו אפשרות לבחור לחלץ על פי החלק העליון של המעגל, או החלק התחתון שלו. המגבלה היחידה שלנו הייתה שהיינו צריכים לבחור את החלק שיש בו את \(\left(a,b\right)\), אבל זה קורה רק במלבן אחד, ובמלבן השני הייתה לנו בחירה חופשית, והופס – שני חילוצים שונים אפשריים!

אז אנחנו נאלצים להצטמצם. למרבה השמחה, זה מניב טיעון אלגנטי מעין כמותו ליחידות של \(g\), מסוג הטיעונים היפים שהולכים בטופולוגיה. בואו ניקח נקודה \(d\in B\) כלשהי ונניח ש-\(g\left(d\right)=k\left(d\right)\). אז אני טוען שקיימת קבוצה פתוחה \(D\subseteq B\) כך ש-\(d\in D\) ו-\(g|_{D}=k|_{D}\) (כלומר, שתי הפונקציות הללו מזדהות על כל איבר של \(D\)).

מה שאני רוצה לומר הוא ש-\(\Phi\left(x,k\left(x\right)\right)=\left(x,0\right)=\Phi\left(x,g\left(x\right)\right)\) ושמכאן אפשר להסיק ש-\(k\left(x\right)=g\left(x\right)\), אבל זה לא נכון באופן כללי; זה נכון רק בתחום שעליו \(\Phi\) היא חד-חד-ערכית, שהוא \(U\times V\). אני יודע ש-\(g\) מעבירה את כל הפלטים שלה ל-\(V\), אז אני רוצה למצוא \(D\) כך ש-\(k\left(D\right)\subseteq V\). כאן הרציפות של הפונקציות המעורבות נכנסת לתמונה. ההגדרה החשובה ביותר לרציפות של פונקציה, כזו שעובדת גם במרחבים טופולוגיים כלליים, היא זו: \(f:A\to B\) היא רציפה אם לכל \(V\subseteq B\) פתוחה, גם \(f^{-1}\left(V\right)\) היא פתוחה. כעת, \(g\left(d\right)\in V\) ו-\(V\) פתוחה, אז \(d\) שייכת ל-\(D=g^{-1}\left(V\right)\) הפתוחה. חד-חד-הערכיות של \(\Phi\) מבטיחה לי עכשיו ש-\(g|_{D}=k|_{D}\).

מה ראינו? שלכל נקודה \(d\in B\) שרירותית ש-\(g,k\) מסכימות עליה יש סביבה פתוחה ש-\(g,k\) מסכימות עליה. אז בואו ניקח את איחוד כל הסביבות של כל הנקודות ב-\(B\) ש-\(g,k\) מסכימות עליהן, כלומר כל הנקודות שמקיימות \(\left|g\left(x\right)-k\left(x\right)\right|=0\) (תכף נבין למה הסימון המוזר הזה). האיחוד הזה הוא של קבוצות פתוחות, ולכן הוא קבוצה פתוחה (זו תוצאה בסיסית למדי, נסו להוכיח אותה לעצמכם). והוא כמובן שווה לקבוצת כל הנקודות שעליהן \(g,k\) מזדהות (שוב, אם זה לא ברור, נסו להוכיח זאת לעצמכם).

מה נשאר? כל הנקודות ב-\(B\) שעליהן \(g,k\) לא מסכימות, שאנחנו מקווים שהוא קבוצה ריקה. דרך אחרת לכתוב את הקבוצה הזו היא בתור אוסף כל הנקודות שמקיימות \(\left|g\left(x\right)-k\left(x\right)\right|>0\), ומי שקצת משופשף בטופולוגיה ודאי יצעק מייד שזו בבירור קבוצה פתוחה, כי \(g,k\) הן רציפות ואי השוויון הוא חזק. לא אכתוב כאן הוכחת אפסילון-דלתא מלאה לטענה הזו כי שוב – ניחשתם – זה תרגיל טוב, אבל הנה הרעיון: נניח ש-\(x\) מקיימת \(\left|g\left(x\right)-k\left(x\right)\right|>0\) וש-\(y\) היא נקודה "קרובה" ל-\(x\). בגלל ש-\(g,k\) רציפות, זה אומר שהערך של \(g\left(y\right)\) "קרוב" לערך של \(g\left(x\right)\), ושהערך של \(k\left(y\right)\) "קרוב" לערך של \(k\left(x\right)\) ולכן הערך של \(\left|g\left(y\right)-k\left(y\right)\right|\) הוא "קרוב" לערך של \(\left|g\left(x\right)-k\left(x\right)\right|\). היופי כאן הוא שאנחנו מסוגלים לשלוט על מידת ה"קרבה" הזו ולהקטין את ההפרש כמה שנרצה. לכן, מכיוון ש-\(\left|g\left(x\right)-k\left(x\right)\right|\) גדול ממש מאפס, נאמר \(\varepsilon\), אנחנו יכולים לבחור את רמת הקרבה של \(y\) אל \(x\) בצורה שתבטיח ש-\(\left|g\left(y\right)-k\left(y\right)\right|\) יהיה רחוק מ-\(\left|g\left(x\right)-k\left(x\right)\right|\) רק עד כדי \(\frac{\varepsilon}{2}\), ולכן עדיין גדול מאפס.

מסקנה: קיבלנו ש-\(B\) היא איחוד של שתי קבוצות פתוחות זרות. לכן אחת מהן חייבת להיות ריקה. \(\left|g\left(x\right)-k\left(x\right)\right|=0\) כמובן לא ריקה כי היא כוללת את \(a\), ולכן הקבוצה השניה ריקה, מה שאומר ש-\(g\) שווה זהותית ל-\(k\) וסיימנו את כל ההוכחה!

פרק שישי, ובו אנחנו מוכיחים את משפט הפונקציה ההפוכה, וזה ארוך וקשה כפי שהבטחנו

את כל המהומה שהייתה עד עכשיו הצגתי בסדר הפוך ביחס לספרים, שבהם מתחילים ממשפט הפונקציה ההפוכה. למה? כי מוטיבציה. כדי שנראה שזה שימושי ומועיל ומעניין, ולנסות לתת לשלושה מכם שהגיעו עד לכאן מוטיבציה למה לנסות ולהבין איך מוכיחים את המשפט.

שתי הערות שכדאי לתת מראש: ראשית, אני הולך להשתמש בהוכחה בכל מני טענות ומושגים מטופולוגיה קבוצתית. אם אתם לא מכירים, תוכלו פשוט להאמין לי בנקודות הללו, ומומלץ לכם בכל מקרה לרוץ ללמוד טופולוגיה קבוצתית כי זה תחום נפלא. שנית, עד כה בכל הפוסטים לא ממש טרחתי להסביר מה זה הסימן \(\left|\cdot\right|\) שאני משתמש בו. ההנחה המובלעת הייתה שמדובר על הנורמה הרגילה על \(\mathbb{R}^{n}\): \(\left|x\right|_{2}=\sqrt{\sum_{i=1}^{n}x_{i}^{2}}\). עם זאת, הייתי יכול להשתמש באותה מידה גם בנורמה אחרת, נורמת הסופרמום, שמוגדרת בתור \(\left|x\right|_{\infty}=\sup\left\{ \left|x_{1}\right|,\dots,\left|x_{n}\right|\right\} \). שתי הנורמות הללו הן שקולות, במובן זה שהן מגדירות את אותה טופולוגיה של המרחב (אותן קבוצות פתוחות) ובאופן כללי מקיימות את אותן התכונות ולכן כל ההוכחות שנתתי עד כה עובדות באותה מידה עם שתיהן; עם זאת, הפעם יהיה לי קל יותר להשתמש בעיקר בנורמות הסופרמום, ולכן אסמן אותה ב-\(\left|\cdot\right|\) ואילו את הנורמה הרגילה ב-\(\|\cdot\|\).

בואו נזכור לרגע מה קורה במקרה החד ממדי. אם יש לנו פונקציה \(f:\mathbb{R}\to\mathbb{R}\) שהנגזרת שלה היא רציפה ושונה מאפס, נאמר חיובית, בנקודה \(a\), אז זה אומר שיש סביבה של \(a\) שבכולה מתקיים \(f^{\prime}\left(x\right)>0\) (הרציפות של הנגזרת הכרחית פה). מכאן שהפונקציה היא מונוטונית עולה בסביבה הזו ולכן חד חד ערכית שם ולכן הפיכה. הדבר הראשון שנעשה יהיה להכליל את הטיעון הזה גם עבור פונקציה \(F:\mathbb{R}^{n}\to\mathbb{R}^{n}\) כללית שהיא \(C_{1}\) בקבוצה פתוחה \(A\subseteq\mathbb{R}^{n}\) ועבור \(a\in A\) כלשהו מתקיים \(\det Df\left(a\right)\ne0\).

הרעיון יהיה למצוא סביבה כלשהי של \(a\) וקבוע \(\alpha>0\) כך שלכל שתי נקודות \(x,y\) בסביבה הזו מתקיים \(\left|F\left(x\right)-F\left(y\right)\right|\ge\alpha\left|x-y\right|\), כאשר כאן ערך מוחלט מייצג את נורמת הסופרמום – הערך המוחלט המקסימלי של כניסה של הוקטור. זה מבטיח שאם \(x\ne y\) אז \(F\left(x\right)\ne F\left(y\right)\), מה שנותן לנו את החד-חד-ערכיות המבוקשת. נזדקק לכמה חישובים וכדי לפשט את הסימונים אני אסמן ב-\(E\) את הטרנספורמציה הלינארית \(DF\left(a\right)\). על פי ההנחה שלנו, \(E\) הפיכה. עכשיו אפשר לקשר את המרחק בין נקודות והמרחק בין ההפעלה של \(E\) עליהן, אבל חסם שבמבט ראשון נראה "לא נכון" כי הוא חוסם את הכיוון ההפוך:

\(\left|x-y\right|=\left|E^{-1}\left(Ex-Ey\right)\right|\le n\left|E^{-1}\right|\left|Ex-Ey\right|\)

המעבר לאי-השוויון דורש הסבר: כאמור, \(\left|E^{-1}\right|\) מייצג כאן את נורמת הסופרמום של המטריצה – המקסימום מבין ערכי הכניסות של \(E^{-1}\) בערך מוחלט. אפשר להוכיח ישירות מההגדרה שאם \(A,B\) הן מטריצות מסדרים \(k\times n\) ו-\(n\times m\) אז \(\left|AB\right|\le n\left|A\right|\left|B\right|\); אנחנו חושבים על \(Ex-Ey\) בתור וקטור (מסדר \(n\times1\)).

ה-\(\alpha\) שאנחנו מחפשים כעת נמצא מולנו: \(\alpha=\frac{1}{2n\left|E^{-1}\right|}\). מייד אנחנו מקבלים ש-\(\left|Ex-Ey\right|\ge2\alpha\left|x-y\right|\). מה עכשיו?

עכשיו הגיע הזמן להכניס את \(F\) לתמונה. בואו נגדיר פונקציה \(H\left(x\right)=F\left(x\right)-Ex\) – הפונקציה הזו מתארת את "הטעות" של \(E\) בנקודה \(x\). גזירה שלה היא טריוויאלית: \(DH\left(x\right)=DF\left(x\right)-E\) (זוכרים? הנגזרת של טרנספורמציה לינארית זו היא בעצמה). מסקנה: \(DH\left(a\right)=DF\left(a\right)-E=E-E=0\). מכיוון ש-\(DF\left(x\right)\) היא רציפה, כך גם \(H\), ולכן קיים \(\varepsilon>0\) כך שלכל \(x\) עבורו \(\left|a-x\right|<\varepsilon\), מתקיים ש-\(\left|DH\left(x\right)\right|<\frac{\alpha}{n}\).

היכולת שלנו לשלוט על גודל הנגזרת של פונקציה מאפשרת לנו לשלוט על הקצב שבו היא משתנה. בואו נזכר במשפט מאינפי רגיל – משפט הערך הממוצע של לגראנז': אם \(f\) גזירה בקטע \(\left[a,b\right]\) אז קיימת נקודה \(c\in\left[a,b\right]\) כך ש-\(f\left(b\right)-f\left(a\right)=\left(b-a\right)f^{\prime}\left(c\right)\). חסם על גודל הנגזרת בקטע נותן לנו חסם על \(f^{\prime}\left(c\right)\) ולכן על \(f\left(b\right)-f\left(a\right)\). אנחנו נעשה דבר דומה עבור \(H\), אבל על הנגזרות החלקיות שלה: \(\left|H_{i}\left(x\right)-H_{i}\left(y\right)\right|=\left|DH_{i}\left(c\right)\left(x-y\right)\right|\le n\left|DH_{i}\left(c\right)\right|\left|x-y\right|\le\alpha\left|x-y\right|\). מכיוון שאנחנו עובדים בנורמת הסופרמום, המסקנה היא שמתקיים

\(\alpha\left|x-y\right|\ge\left|H\left(x\right)-H\left(y\right)\right|\) (תרגיל: לחשוב אילו תיקונים היו נדרשים כדי שההוכחה תעבוד עם הנורמה האוקלידית הרגילה; תראו חיש קל שזו סתם עוד עבודה טכנית ולכן היתרון שבשימוש בנורמת הסופרמום ברור).

אם נפתח את \(H\) לפי ההגדרה, נקבל גם חסם תחתון על ההפרש. זכרו שבאופן כללי מתקיים \(\left|x-y\right|\ge\left|x\right|-\left|y\right|\) (כי \(\left|x\right|=\left|x-y+y\right|\le\left|x-y\right|+\left|y\right|\)), ולכן:

\(\left|H\left(x\right)-H\left(y\right)\right|=\left|F\left(x\right)-Ex-\left(F\left(y\right)-Ey\right)\right|=\left|\left(Ey-Ex\right)-\left(F\left(y\right)-F\left(x\right)\right)\right|\ge\)

\(\left|Ey-Ex\right|-\left|F\left(y\right)-F\left(x\right)\right|\ge2\alpha\left|x-y\right|-\left|F\left(y\right)-F\left(x\right)\right|\)

משילוב החסם העליון והתחתון נקבל \(\left|F\left(x\right)-F\left(y\right)\right|\ge\alpha\left|x-y\right|\) – בדיוק מה שרצינו. קצת קסם, במובן זה שעדיין לא ברור מאיפה פתאום זה צץ.

סיימנו עם החלק הקל – להראות ש-\(F\) הפיכה בסביבה של \(a\). כלומר, ראינו שקיימת קבוצה פתוחה \(A\) כך ש-\(F\) היא חח"ע על \(A\). כדי להפוך אותה צריך לדבר גם על התמונה שלה, \(B=F\left(A\right)\). אנחנו כבר יודעים ש-\(F^{-1}:B\to A\) קיימת והיא חח"ע ועל, אבל מה אנחנו יודעים על \(B\) עצמה? חלק ממה שהמשפט בא להבטיח הוא ש-\(B\) היא נחמדה – שהיא קבוצה פתוחה בעצמה. איך נראה את זה?

אינטואיטיבית אולי לא ברור מה הבעיה. אם \(F:A\to B\). לפעמים קל להתבלבל ולחשוב שפונקציה רציפה היא בעלת התכונה שהתמונה של קבוצה פתוחה היא קבוצה פתוחה. בפועל זה ההפך שהוא נכון – המקור של קבוצה פתוחה הוא קבוצה פתוחה. דוגמה פשוטה מאוד לפונקציה רציפה שאינה מעבירה קבוצה פתוחה לקבוצה פתוחה היא \(f:\mathbb{R}\to\mathbb{R}\) קבועה, למשל \(f\left(x\right)=0\); התמונה של \(\mathbb{R}\) היא הקבוצה הלא פתוחה \(\left\{ 0\right\} \) (לא פתוחה, כי כל סביבה של 0 תכיל נקודות שאינן בקבוצה הזו). דוגמה קצת פחות טריוויאלית היא \(f\left(x\right)=\begin{cases}x & 0\le x\le1\\0 & x<0\\1 & x\ge1\end{cases}\) שמעבירה את הקבוצה הפתוחה \(\mathbb{R}\) אל הקטע הסגור \(\left[0,1\right]\) אבל היא בבירור רציפה בתור "הדבקה" של שלוש פונקציות רציפות שמסכימות זו עם זו בנקודות ההדבקה. אז מה השתבש כאן? השתבש שהפונקציה הרציפה "מועכת" את הקבוצה הפתוחה שהיא מקבלת ויוצרת בה קצוות סגורים. אלא ש"מעיכה" כזו מונעת מהפונקציה להיות חד-חד-ערכית – אנחנו חיביים שכמה ערכים שונים יימעכו ביחד לאותו פלט. לכן בסיטואציה שלנו, שבה הפונקציה היא חד-חד-ערכית, יש לנו תקווה שזה יעבוד.

כפי שהזהרתי, אני הולך להשתמש בכמה תעלולים מטופולוגיה קבוצתית בלי להוכיח אותם במפורש, ואני מקווה שתסלחו לי. ראשית, בואו ניקח \(b\in B\). המטרה שלנו היא למצוא \(\delta\) כך שהכדור הפתוח ברדיוס \(\delta\) סביב \(B\) מוכל כולו ב-\(B\), דהיינו לכל \(y\) שמקיים \(\left|y-b\right|<\delta\) מתקיים ש-\(y\in B\), כלומר שהוא תמונה של \(x\) כלשהו: \(y=F\left(x\right)\) עבור \(x\in A\).

לשם כך, ראשית כל בואו נסתכל על \(a=F^{-1}\left(b\right)\). ניקח כדור סגור \(Q\) שמכיל את \(a\) ומוכל כולו ב-\(A\) (זה אפשרי כי \(A\) פתוחה). השפה \(BdQ\) של הכדור היא קבוצה סגורה וחסומה, ולכן קומפקטית; פונקציה רציפה מעבירה קבוצה קומפקטית לקבוצה קומפקטית, ולכן \(F\) מעבירה את השפה של הכדור לקבוצה קומפקטית. הקבוצה הזו לא מכילה את \(b\) אחרת היינו מקבלים סתירה לחד-חד-ערכיות של \(F\) (הרי \(a\) לא נכלל בשפה של הכדור שמקיף את \(A\)). לכן אפשר למצוא \(\delta\) כך שהכדור הפתוח סביב \(b\) ברדיוס \(2\delta\) זר ל-\(F\left(BdQ\right)\). מצאנו את ה-\(\delta\) שלנו; מה שצריך להראות הוא שאם \(c\) היא נקודה כלשהי שרחוקה מ-\(b\) עד כדי \(\delta\) (בנורמה הרגילה ולא בנורמת הסופרמום), אז קיים \(x\in A\) כך ש-\(F\left(x\right)=c\).

בואו נגדיר פונקציה שאומרת כמה \(x\) "מפספס" את \(c\): \(\phi\left(x\right)=\|F\left(x\right)-c\|^{2}\). מכיוון ש-\(F\) ב-\(C^{r}\), כך גם \(\phi\), ומכיוון ש-\(Q\) קומפקטית, קיים ל-\(\phi\) מינימום מעל \(Q\), ונסמן ב-\(d\) את הנקודה שבה מתקבל המינימום הזה, שאנחנו רוצים להראות כמובן שהוא 0.

ראשית אני רוצה להראות שהמינימום הזה חייב להתקבל בנקודה פנימית של \(Q\) ולא על השפה של \(Q\). נקודות על השפה מקיימות, כמובן, ש-\(\|F\left(x\right)-b\|\ge\delta\), כי הסכמנו כבר שהכדור הפתוח ברדיוס \(2\delta\) סביב \(b\) זר לתמונה של השפה, זה האופן שבו בחרנו את \(\delta\). אם כן, הערך שנקודות על השפה מחזירות הוא "יחסית גדול". מצד שני, \(\phi\left(a\right)=\|F\left(a\right)-c\|^{2}=\|b-c\|^{2}<\delta^{2}\) כי הנחת המוצא שלנו הייתה שהמרחק בין \(b\) ל-\(c\) הוא פחות מ-\(\delta\). מכיוון שאנחנו תמיד יכולים לבחור \(\delta<1\) הרי ש-\(\delta^{2}<\delta\), ומכאן שעבור \(a\) הערך המוחזר הוא "יחסית קטן", ולכן המינימום חייב להחזיר ערך עוד יותר קטן ולכן הוא לא יכול להתקבל על השפה.

החשיבות של כך שהמינימום לא מתקבל על השפה היא שזה מראה כי מדובר על מינימום מקומי, כלומר יש סביבה של הנקודה שבה המינימום מתקבל שבה כל הנקודות מחזירות ערך גדול יותר. ראינו בפוסט הקודם שהמשמעות של זה היא שהנגזרת של \(\phi\) בנקודה הזו מתאפסת. אז בואו נכתוב את \(\phi\) באופן מפורש, ונגזור אותה:

\(\phi\left(x\right)=\sum_{i=1}^{n}\left(F_{i}\left(x\right)-c_{i}\right)^{2}\)

נגזרת חלקית של פונקציה כזו, זה קל:

\(D_{j}\phi\left(x\right)=\sum_{i=1}^{n}2\left(F_{i}\left(x\right)-c_{i}\right)D_{j}F_{i}\left(x\right)\)

וכל הנגזרות החלקיות צריכות להתאפס ב-\(d\). כלומר נקבל \(\sum_{i=1}^{n}\left(F_{i}\left(d\right)-c_{i}\right)D_{j}F_{i}\left(d\right)=0\). את הדבר הזה אפשר לתאר בתור מכפלה סקלרית של שני וקטורים: וקטור ה"טעויות", \(v=\left[F_{1}\left(d\right)-c_{1},\dots,F_{n}\left(d\right)-c_{n}\right]\), והוקטור שמתאים לנגזרת ה-\(j\)-ית של \(F\), \(D_{j}F\). יש לנו \(n\) משוואות כאלו, אחת לכל נגזרת חלקית של \(F\), ואם נאחד את כולן נקבל את המשוואה הבאה של מכפלת וקטור במטריצה: \(v\cdot DF=0\). אחת מההנחות שלנו, כזכור, היא ש-\(DF\) היא הפיכה, ולכן על ידי כפל בהופכית שלה נקבל ש-\(v=0\), והמסקנה היא ש-\(F_{i}\left(d\right)=c_{i}\) לכל \(i\), כלומר \(F\left(d\right)=c\), וזה מה שרצינו.

סיכום ביניים: הייתה לנו פונקציה \(F:A\to\mathbb{R}^{n}\). הראינו קבוצה פתוחה \(B\) כך ש-\(F:A\to B\) היא חח"ע ועל, כלומר הפיכה; אני אסמן את הההופכית ב-\(G\). המטרה שלנו היא להראות ש-\(G\) גזירה. נעשה את זה בשני שלבים – קודם נוכיח שהיא רציפה, ואז נעבור לגזירות. רציפות זה קל למדי ונובע בחינם ממה שכבר עשינו: בטופולוגיה קבוצתית רואים שהגדרה שקולה לרציפות של \(G\) היא שלכל קבוצה פתוחה \(U\subseteq A\), המקור \(G^{-1}\left(U\right)\) הוא קבוצה פתוחה. אבל \(G^{-1}\left(U\right)=F\left(U\right)\), ולכן אפשר לחזור על כל הטירוף שהתבססנו עליו עד כה כדי להוכיח ש-\(B\) פתוחה בהינתן ש-\(A\) פתוחה, כדי להוכיח ש-\(F\left(U\right)\) פתוחה בהינתן ש-\(U\) פתוחה. קיבלנו ש-\(G\) רציפה. תודה לארדש, נותר רק להוכיח שהיא גזירה. וזה יהיה החלק הכי טכני פה.

אנחנו כמובן יודעים מה הנגזרת הולכת להיות: כבר ראינו בפוסט קודם שמכלל השרשרת נובע שאם \(G\) גזירה בנקודה \(b=F\left(a\right)\), אז בהכרח הנגזרת שלה היא \(\left(DF\left(a\right)\right)^{-1}\), כלומר ההופכית של הנגזרת של \(F\) באותה נקודה. הבעיה היחידה היא שלא מובטח לנו שהנגזרת של \(F\) אכן הפיכה בכל \(A\) – בניסוח המקורי של המשפט אנחנו רק דורשים שתהיה נקודה כלשהי שבה הנגזרת הפיכה, ואז המשפט מבטיח שתהיה לנקודה הזו סביבה פתוחה שבה הפונקציה תהיה הפיכה עם נגזרת נחמדה של הפונקציה ההפוכה. מכאן שייתכן שנצטרך לצמצם את \(A\) לסביבה קטנה ביותר, בהתאם לשאלה איפה \(DF\) אינה הפיכה; אבל הרציפות של \(DF\) מבטיחה שתהיה סביבה כזו (זה נובע מכך שטרנספורמציה לינארית היא הפיכה אם ורק אם הדטרמיננטה שלה היא אפס, ושדטרמיננטה היא פונקציה רציפה).

אם כן, הצטמצמנו לנקודות שבהן הנגזרת של \(F\) הפיכה. אם נסמן את הנגזרת הזו ב-\(E=DF\left(a\right)\) אז אנחנו רוצים להראות ש-\(E^{-1}\) היא הנגזרת ב-\(b=F\left(a\right)\). נחזור להגדרה: זה אומר שצריך להראות ש-

\(\lim_{k\to0}\frac{G\left(b+k\right)-G\left(b\right)-E^{-1}k}{\left|k\right|}=0\)

כרגיל, הטריק הוא בלדעת לפרק את המפלצת הזו לכמה חלקים שאנחנו יודעים לטפל בכל אחד מהם בנפרד. ראשית כל נסמן \(\Delta\left(k\right)=G\left(b+k\right)-G\left(b\right)\), כלומר הגבול שלנו הוא של הביטוי \(\frac{\Delta\left(k\right)-E^{-1}k}{\left|k\right|}\). כעת נכפול ונחלק ב-\(\left|\Delta\left(k\right)\right|\) ונוציא את \(E^{-1}\) החוצה ונקבל את הביטוי

\(-E^{-1}\left[\frac{k-E\cdot\Delta\left(k\right)}{\left|\Delta\left(k\right)\right|}\right]\frac{\left|\Delta\left(k\right)\right|}{\left|k\right|}\)

קיבלנו מכפלה של שלושה ביטויים. \(-E^{-1}\) הוא קבוע ולכן לא משפיע על הגבול. מה שנשאר לנו להראות הוא שהגורם האמצעי שואף לאפס, והגורם הימני "לא מפריע", כלומר הוא חסום כאשר \(k\) שואף לאפס.

הטריק בביטוי האמצעי הוא להראות שהוא שואף לאפס בגלל שהביטוי המתאים לנגזרת של \(F\) שואף לאפס. זאת משום ש-

\(b+k=F\left(G\left(b+k\right)\right)=F\left(G\left(b\right)+\Delta\left(k\right)\right)=F\left(a+\Delta\left(k\right)\right)\)

או במילים אחרות, \(k=F\left(a+\Delta\left(k\right)\right)-F\left(a\right)\). לכן הביטוי שבסוגריים הוא בעצם

\(\frac{F\left(a+\Delta\left(k\right)\right)-F\left(a\right)-E\cdot\Delta\left(k\right)}{\left|\Delta\left(k\right)\right|}\)

ומהגדרת הנגזרת, כאשר \(\Delta\left(k\right)\) שואף לאפס, הביטוי הזה שואף לאפס. מכיוון שכאשר \(k\) שואף לאפס כך גם \(\Delta\left(k\right)\), קיבלנו את מה שרצינו.

כל ההוכחה מתרכזת כעת, כמו שקורה המון באנליזה, בלהראות שאיזה שהוא ביטוי הוא חסום – הביטוי \(\frac{\left|\Delta\left(k\right)\right|}{\left|k\right|}\), כאשר \(k\to0\).

אם תחזרו לתחילת הסעיף הזה תזכרו שהוכחנו שקיימת סביבה של \(a\), נקרא לה \(C\), ו-\(\alpha>0\), כך שלכל שתי נקודות \(x_{0},x_{1}\in C\) מתקיים \(\left|F\left(x_{0}\right)-F\left(x_{1}\right)\right|\ge\alpha\left|x_{0}-x_{1}\right|\). בואו נסתכל עכשיו על \(F\left(C\right)\), שהיא סביבה של \(b\), ורק על ערכי \(\left|k\right|\) קטנים דיו ש-\(b+k\) מוכלת ב-\(F\left(C\right)\) לכל \(k\) כזה. במקרה הזה נבחר \(x_{0}=G\left(b+k\right)\) ו-\(x_{1}=G\left(b\right)\), ונפעיל את אי השוויון למעלה עליהם, תוך שימוש בכך ש-\(F\) מבטל את \(G\). כלומר, נקבל \(\left|k\right|=\left|b+k-b\right|\ge\alpha\left|G\left(b+k\right)-G\left(b\right)\right|=\alpha\left|\Delta\left(k\right)\right|\). כלומר קיבלנו ש-\(\frac{\left|\Delta\left(k\right)\right|}{\left|k\right|}\le\frac{1}{\alpha}\), וזה מה שרצינו.

נשאר רק דבר אחד לסיום, שבו אנפנף טיפה בידיים אבל לא יותר מדי, וזה להראות שאם \(F\) שייכת למחלקה \(C^{r}\) (גזירה ברציפות \(r\) פעמים) כך גם \(G\). זה נראה כמו הדבר הכי כבד כאן, אבל מן הסתם את העבודה הקשה כבר עשינו ונשתמש בטיעון פשוט יחסית לצורך ההוכחה. הרעיון הוא שמכיוון שאנחנו יודעים איך לגזור את \(G\), אנחנו גם יודעים (על פי כלל השרשרת) בדיוק איך הנגזרת שלה תיראה:

\(DG\left(b\right)=\left[DF\left(G\left(b\right)\right)\right]^{-1}\)

או במילים אחרות, \(DG\) היא הרכבה של שלוש פונקציות: \(G\), שעליה מרכיבים את \(DF\), שעליה מרכיבים את האופרטור שמעתיק טרנספורמציה לינארית להופכית שלה. אפשר להראות שהאופרטור הזה הוא ב-\(C^{\infty}\) וש-\(F\) היא ב-\(C^{r}\), והרכבה של פונקציות ב-\(C^{r}\) היא ב-\(C^{r}\), ולכן כל מה שצריך לעשות הוא לדבר על \(G\) עצמה, במין טיעון אינדוקטיבי שקצת נראה כמו מישהו שמרים את עצמו על ידי משיכה בשרוכי הנעליים: אנחנו כבר יודעים ש-\(G\) רציפה כי הראינו זאת במפורש, ולכן גם \(DG\) רציפה, כהרכבה של שלוש פונקציות רציפות, ומכאן ש-\(G\) בעצם שייכת ל-\(C^{1}\); אבל אם \(G\) שייכת ל-\(C^{1}\) אז גם \(DG\) שייכת ל-\(C^{1}\) כהרכבה של שלוש פונקציות ב-\(C^{1}\), וכן הלאה באינדוקציה עד אשר אנחנו נתקעים ב-\(C^{r}\) כי ההרכבה שלנו כוללת גם את \(F\), שאנחנו לא מסוגלים להגיד עליה כלום מעבר לכך שהיא ב-\(C^{r}\).

זה טיעון יפהפה ששווה את נפנוף הידיים. גם בגלל ה"משיכה בשרוכי נעליים" וגם בגלל איך שפתאום אני מכניס לתמונה את האופרטור שלוקח פונקציה להופכית שלה ומשתמש בגזירות שלו כטיעון – זו מעין יציאה מהמסגרת שבה היינו עד עכשיו. אני רק מקווה שהצלחתם לשרוד עד לכאן כדי ליהנות מזה.

פרק שביעי, ובו אנו שובתים מכל מלאכה

טוב, זה היה מתיש, אין לי כוח לכתוב סיום מתחכם.

אנליזה וקטורית – מציאת ערכי קיצון

חלק ראשון, שבו אנו מוצאים ערכי קיצון מקומיים

אחד מהשימושים הראשונים של החשבון הדיפרנציאלי והאינטגרלי, שאפשר להציג כבר בשלב מוקדם יחסית, כבר אחרי שראינו מהי נגזרת, הוא פתרון בעיות אופטימיזציה. למשל, מה הזווית הטובה ביותר שבה כדאי לזרוק כדור אם אנחנו רוצים למקסם את המרחק שהוא יגיע אליו. בבעיות כאלו יש לנו מערכת שההתנהגות שלה תלויה בפרמטר כלשהו ("הזווית שבה זורקים את הכדור"), ועבור ערכים שונים של הפרמטר אנחנו מקבלים "תוצאה" שהיא ערך מספרי כלשהו של המערכת ("המרחק שאליו הכדור מגיע") ואנחנו רוצים למצוא את הערך הטוב ביותר של הפרמטר מבחינתנו. לפעמים זה הערך שעבורו התוצאה היא הגדולה ביותר, ולפעמים זה הערך שעבורו התוצאה היא הקטנה ביותר, תלוי באופי הבעיה (לפעמים הערך הוא ה"מחיר" שאנחנו צריכים לשלם). בעיות אופטימיזציה צצות בתחומים שונים ומשונים במתמטיקה ויש טכניקות שונות ומשונות לטפל בהן. לעתים קרובות מאוד יש לנו אילוצים על הפרמטרים שהמערכת יכולה לקבל, ושקלול שלהם פנימה הוא חלק רציני מפתרון הבעיה.

מה שמתעסקים איתו בחדו"א הוא סיטואציה פשוטה יחסית, שבה המערכת מתוארת על ידי פונקציה \(f:\mathbb{R}\to\mathbb{R}\) שהיא "נחמדה", במובן זה שהיא גזירה. הרעיון הוא שאפשר להשתמש בנגזרת של \(f\) כדי לאתר מייד את כל נקודות המקסימום ומינימום הנקודתיות של הפונקציה; ובתקווה, אם אין הרבה כאלו, בדיקה קצרה תעלה מה מהן היא המבוקשת שלנו (שעבורה הערך הוא הטוב ביותר אבסולוטית עבור בחירת פרמטרים חוקית). זה לא עובד תמיד טוב, אבל זה עובד טוב מספיק כדי שזה יהיה שימושי ביותר. הטכניקה עצמה מאוד פשוטה – בכל נקודת קיצון מקומית של הפונקציה, הנגזרת שלה חייבת להתאפס (ההפך לאו דווקא נכון). הסיבה פשוטה: ניקח למשל נקודת מקסימום מקומית. כל עוד הפונקציה "עדיין לא הגיעה" אל נקודת המקסימום אבל היא קרובה אליה, היא עולה אליה; ומייד אחרי נקודת המקסימום היא יורדת ממנה. זה אומר שממש לפני ההגעה לנקודת הקיצון הנגזרת היא חיובית ומייד אחרי היא שלילית. זה מכריח את הנגזרת באותה נקודה להיות "בו זמנית חיובית ושלילית", כלומר בהכרח 0.

בסדרת הפוסטים הנוכחית אנחנו מתעסקים באנליזה וקטורית, כלומר בפונקציות ממשיות מרובות משתנים. אז יש לנו פונקציה \(f:\mathbb{R}^{n}\to\mathbb{R}\) ואנחנו רוצים לפתור את אותה בעיה – למצוא נקודות קיצון. קל לחשוב על הנקודות הללו בצורה ציורית כאשר \(n=2\) – אפשר לחשוב על \(f\) כאילו היא מתארת מפה טופוגרפית, במובן זה שלכל נקודה \(\left(x,y\right)\) במפה הדו-ממדית נתון לנו גם הגובה של אותה נקודה, \(f\left(x,y\right)\). נקודת מקסימום היא "פסגת הר" ונקודת מינימום היא "תחתית עמק". וזה מה שאנחנו רוצים למצוא.

הניחוש הנאיבי ביותר הוא שאותה אינדיקציה שעבדה במימד אחד תעבוד גם ב-\(n\) ממדים: אם יש לפונקציה נקודת קיצון ב-\(a\in\mathbb{R}^{n}\), אז \(Df\left(a\right)=0\) (כאשר כאן \(0\) מציין את טרנספורמציית האפס, טרנספורמציה לינארית שמחזירה 0 עבור הכל). למרבה השמחה, הניחוש הנאיבי הזה עובד, ואוכיח זאת עוד רגע; למרבה הצער, בכל זאת יש חלק קשה יותר, והוא הסיווג של נקודות הקיצון הפוטנציאליות, שמטרתו להכריע מי הן נקודות הקיצון האמיתיות ומי הן אנומליות לא קשורות.

בואו ניתן כמה הגדרות פורמליות. כרגיל, כל מה שאנחנו מניחים על \(f\) הוא שהיא מוגדרת על קבוצה פתוחה \(U\subseteq\mathbb{R}^{n}\); אין צורך להניח שהיא מוגדרת בכל מקום. עבור \(f\) כזו, אנחנו אומרים ש-\(a\in U\) היא נקודת מקסימום מקומית אם קיימת סביבה \(V\) של \(a\) ב-\(U\) ("סביבה" היא קבוצה פתוחה שמכילה את \(a\)) כך ש-\(f\left(a\right)\ge f\left(x\right)\) לכל \(x\in V\). באופן דומה מגדירים גם נקודות מינימום.

עכשיו, בואו נגדיר נקודה קריטית של \(f\) בתור נקודה \(a\) שבה \(f\) אינה גזירה, או שהיא גזירה אבל \(Df\left(a\right)=0\). המשפט הראשון שלנו אומר שאם \(a\) היא נקודת קיצון אז היא נקודה קריטית; אבל יכולות להיות נקודות קריטיות שאינן נקודות קיצון, וקוראים להן נקודות אוכף (כי נקודה שנמצאת על מושב האוכף היא דוגמה יפה לנקודה שבה הנגזרת מתאפסת אבל היא אינה נקודת קיצון). האתגר יהיה לזהות, בהינתן נקודה קריטית, האם היא נקודת קיצון או לא.

ההוכחה שנקודת קיצון היא קריטית מתבססת על רדוקציה למקרה החד ממדי. אם הפונקציה לא גזירה בנקודה, אז על פי הגדרה הנקודה היא נקודת קיצון; לכן אני מניח ש-\(Df\left(a\right)\) מוגדרת. כדי להראות ש-\(Df\left(a\right)=0\) אני צריך להוכיח שהטרנספורמציה הזו מחזירה 0, לא משנה על איזה וקטור היא מופעלת. ומה זו "הפעלה" של הנגזרת על וקטור \(u\)? אם תזכרו, כי דיברנו על זה מזמן מזמן, זה מה שנותן לנו את הנגזרת המכוונת של \(f\) בכיוון \(h\), שהוגדרה כך: \(\lim_{h\to0}\frac{f\left(a+hu\right)-f\left(a\right)}{h}\). עכשיו, בואו נגדיר פונקציה \(\phi:\mathbb{R}\to\mathbb{R}\) על ידי \(\phi\left(h\right)=f\left(a+hu\right)\). אז קיבלנו ש-

\(Df\left(a\right)\cdot u=\lim_{h\to0}\frac{f\left(a+hu\right)-f\left(a\right)}{h}=\lim_{h\to0}\frac{\phi\left(h\right)-\phi\left(0\right)}{h}=\phi^{\prime}\left(0\right)\)

עכשיו, אם \(a\) היא נקודת קיצון של \(f\), אז \(0\) היא נקודת קיצון של \(\phi\), ולכן \(\phi^{\prime}\left(0\right)=0\) (מהמשפט על נקודת קיצון במקרה החד ממדי), וסיימנו: ראינו ש-\(Df\left(a\right)\cdot u=0\) לכל \(u\) ולכן \(Df\left(a\right)=0\). אז זה היה קל, כמובטח. מה הלאה?

בואו נראה שתי דוגמאות פשוטות כדי לקבל תחושה של נקודת קיצון אל מול נקודת אוכף. נתחיל מ-\(f\left(x,y\right)=x^{2}+y^{2}\) – גרף של הפונקציה הזו נראה כמו מין קערית שכזו. הגרדיאנט קל לחישוב: \(\nabla f=\left(2x,2y\right)\). הוא מתאפס בדיוק בנקודה אחת: \(x=y=0\). לכן זו הנקודה היחידה שעשויה להיות נקודת קיצון, וקל לראות במקרה הזה שמדובר על נקודת מינימום. מסקנה: אין נקודות מקסימום בכלל, אחרת היינו מקבלים עוד נקודות קריטיות.

עכשיו בואו נעבור לדבר על האוכף. נתבונן ב-\(f\left(x,y\right)=x^{2}y+y^{2}x\). הגרדיאנט שלה הוא \(\nabla f=\left(2xy+y^{2},2yx+x^{2}\right)\). אז קיבלנו מערכת של שתי משוואות בשני נעלמים עבור \(\nabla f=0\). אם \(y=0\) אז \(2yx+x^{2}=0\) גורר ש-\(x=0\) ולכן פרט לנקודת הקיצון הברורה ב-\(x=y=0\) אנחנו יכולים להניח בהמשך הניתוח ש-\(x\ne0\) וגם \(y\ne0\) ולכן אפשר לחלק בהם. כעת, אם \(2xy+y^{2}=0\) נחלק ב-\(y\) ונקבל \(y=-2x\), ובאופן סימטרי \(x=-2y\) מתקבל מהמשוואה השניה. קיבלנו \(x=-2y=4x\), מה שגורר \(x=0\), וזו סתירה להנחה שלנו שהוא שונה; לכן הנקודה הקריטית היחידה היא \(x=y=0\). קל לראות שזו לא נקודת קיצון על ידי הסתכלות בישר \(x=y\): עליו, הפונקציה היא \(\phi\left(x\right)=f\left(x,x\right)=2x^{3}\) ולכן עבור \(x>0\) נקבל ערך חיובי ועבור \(x<0\) נקבל ערך שלילי, ומכאן ש-\(\left(0,0\right)\) היא לא נקודת קיצון. זו סיטואציה דומה למה שקורה במימד אחד עם, למשל, \(\tan x\).

אז איך מבדילים בין נקודת קיצון ובין "סתם" נקודה קריטית? בחדו"א של משתנה יחיד היה מבחן שעבד טוב במקרה שבו הפונקציה היא "נחמדה מספיק" – אם היא הייתה גזירה פעמיים, אז הנגזרת השניה שלה נתנה לנו את המידע הדרוש. אם הנגזרת השניה בנקודה הקריטית הייתה חיובית, הנקודה הייתה נקודת מינימום; אם היא הייתה שלילית, זו הייתה נקודת מקסימום; ואם היא הייתה 0 אז זו הייתה נקודה קריטית שאינה נקודת קיצון.

האינטואיציה כאן היתה פשוטה. בנקודת מינימום, רגע לפני הנקודה הפונקציה יורדת, כלומר בעלת נגזרת שלילית; רגע אחרי הנקודה הפונקציה עולה, כלומר בעלת נגזרת חיובית; זה אומר שבסביבות הנקודה, הנגזרת היא פונקציה עולה (בהתחלה שלילית, אחר כך 0, לבסוף חיובית). אם היא פונקציה עולה, אז הנגזרת שלה היא חיובית. שיקול דומה מטפל גם בנקודת מקסימום. ומה קרה ב-\(\tan x\), למשל? הפונקציה היא עולה כל הזמן, כלומר הנגזרת היא חיובית כל הזמן (למעט בנקודה הקריטית עצמה, שם היא 0). אבל בהתחלה הנגזרת היא פונקציה יורדת (מתחילה מאוד גדולה ולאט לאט קטנה עד שהיא מגיעה ל-0) ואחרי הנקודה הקריטית היא מתחילה לעלות מחדש. כלומר, בנקודה הקריטית הנגזרת היא חיובית קודם וחיובית אחר כך, כלומר הנקודה הקריטית היא נקודת מינימום של הנגזרת, ולכן הנגזרת השניה היא 0.

היינו שמחים להכליל את הטיעון הזה ל-\(n\) ממדים, וזה אכן מה שנעשה; אפשר להסיק את הקריטריון החד ממדי מהתוצאה שנראה. אבל למרבה הצער, הקריטריון שלנו יהיה מסובך משמעותית יותר מאשר במקרה החד משמעי, ודורש היכרות עם אלגברה לינארית. הקושי הוא בכך שאנחנו צריכים למצוא הכללה כלשהי ל"נגזרת השניה" של מימד אחד. הרי אצלנו "נגזרת" היא כבר לא פונקציה \(f:\mathbb{R}^{n}\to\mathbb{R}\) כמו הפונקציה שאותה גזרנו; היא אופרטור שלכל נקודה במרחב מתאים טרנספורמציה לינארית (או מטריצה, איך שתעדיפו להסתכל על זה), ואי אפשר לגזור את זה. אז אנחנו משתמשים במשהו אחר – מטריצה \(n\times n\) שכוללת את כל הנגזרות החלקיות המעורבות מסדר שני. המטריצה הזו נקראת הסיאן.

מה זו נגזרת חלקית אנחנו כבר יודעים – פשוט גוזרים את הפונקציה רק על פי משתנה בודד ומתייחסים ליתר בתור פרמטרים. ראינו כבר שאם \(f\) גזירה אז הנגזרת שלה ניתנת לתיאור בתור וקטור הנגזרות החלקיות של \(f\). נגזרת חלקית "מסדר שני" היא מה שמתקבל כשגוזרים נגזרת חלקית שוב, ו"מעורבת" אומר שאפשר לגזור שוב על פי כל אחד מהמשתנים. אני מסמן \(\frac{\partial^{2}f}{\partial x\partial y}\) את מה שמתקבל כשאני גוזר את \(f\) קודם כל לפי המשתנה \(x\) ואז לפי המשתנה \(y\). למשל, עבור פונקציית נקודת האוכף \(f\left(x,y\right)=x^{2}y+y^{2}x\) אנחנו יודעים ש-\(\frac{\partial f}{\partial x}=2xy+y^{2}\), ולכן אם נגזור שוב לפי \(y\), נקבל ש-\(\frac{\partial^{2}f}{\partial x\partial y}=2x+2y\).

מטריצת הסיאן מתקבלת באופן דומה – הכניסה בשורה ה-\(i\) ובעמודה ה-\(j\) שווה לנגזרת החלקית קודם לפי המשתנה \(x_{i}\) ואחר כך לפי המשתנה \(x_{j}\), כלומר \(\left[H\right]_{ij}=\frac{\partial^{2}f}{\partial x_{i}\partial x_{j}}\). אם נכתוב את ההסיאן של \(f\left(x,y\right)=x^{2}+y^{2}\) נקבל \(\left[\begin{array}{cc}2 & 0\\0 & 2\end{array}\right]\). אם נכתוב את ההסיאן של \(f\) של נקודת האוכף, נקבל \(\left[\begin{array}{cc}2y & 2x+2y\\2x+2y & 2x\end{array}\right]\). שימו לב שזו מטריצה סימטרית, כלומר יוצא שהנגזרת המעורבת קודם לפי \(x\) ואז על פי \(y\) שווה לנגזרת המעורבת קודם על פי \(y\) ואז על פי \(x\); זה לא מקרי וזה תמיד מתקיים אם שתי הנגזרות המעורבות הללו הן רציפות; אנחנו נניח מעכשיו ש-\(f\) היא ב-\(C^{2}\), אחרת המשפט שאני מתאר לא יהיה נכון.

עכשיו אפשר לנסח את הקריטריון שלנו בלשון שאותה יבינו מי שמכירים אלגברה לינארית: אם בנקודה הקריטית ההסיאן הוא מטריצה חיובית לחלוטין (Positive Definite Matrix), אז הנקודה הקריטית היא נקודת מינימום; ואם ההסיאן הוא מטריצה שלילית לחלוטין (Negative Definite Matrix) אז הנקודה הקריטית היא נקודת מקסימום; ואחרת אין לנו מושג מהי הנקודה הקריטית. מן הסתם המושג המרכזי פה הוא "חיובית/שלילית לחלוטין" שתכף אסביר, אבל למי שרוצים את התכל'ס, תנאי שקול לכך שמטריצה תהיה חיובית לחלוטין הוא שכל הערכים העצמיים שלה יהיו חיוביים, ואילו עבור שלילית לחלוטין, שכולם יהיו שליליים. זה מסביר את התוצאה בשתי הדוגמאות שראינו; במקרה הראשון קיבלנו מטריצה שהערך העצמי היחיד שלה הוא 2 החיובי, ולכן הנקודה הקריטית היא נקודת מינימום; ובמקרה השני ההסיאן ב-\(x=y=0\) הוא מטריצת האפס, שהערך העצמי היחיד שלה הוא 0 שאינו חיובי או שלילי.

הנה הסבר קצר לגבי מה זה מוגדרת חיובית ולמה זה רלוונטי פה, בלי להיכנס להוכחות עד הסוף. אם אין לכם כוח אליו אתם מוזמנים לדלג להמשך, שבו מדברים על כופלי לגראנז' שהם נושא נפרד ומגניב וחשוב בפני עצמו.

אנחנו יודעים שכל מטריצה \(A\) מסדר \(n\times n\) מעל שדה \(\mathbb{F}\) מגדירה טרנספורמציה לינארית \(T_{A}:\mathbb{F}^{n}\to\mathbb{F}^{n}\). אבל יש עוד סוג מעניין של העתקה בערך-לינארית שהמטריצה מגדירה: תבנית בילינארית, שהיא פונקציה \(B_{A}:\mathbb{F}^{n}\times\mathbb{F}^{n}\to\mathbb{F}\) שלינארית בכל אחד משני הרכיבים שלה בנפרד, ומוגדרת על ידי \(B\left(v,u\right)=v^{t}Au\) (כלומר, כופלים את המטריצה \(A\) בוקטור העמודה \(u\) כרגיל ומקבלים וקטור ב-\(\mathbb{F}^{n}\), אבל אחר כך כופלים את התוצאה הזו גם בוקטור השורה \(v^{t}\), דהיינו מבצעים מכפלה סקלרית של \(v\) ושל \(Au\)). כל תבנית בילינארית מגדירה, בתורה, גם פונקציה \(g:\mathbb{F}^{n}\to\mathbb{F}\) על ידי \(g_{A}\left(v\right)=B_{A}\left(v,v\right)=v^{t}Av\) (במילים, כופלים סקלרית את \(v\) בתמונה של \(v\) על ידי הטרנספורמציה הלינארית שמוגדרת על ידי \(A\)). לפונקציה כזו קוראים תבנית ריבועית והיא מה שמעניין אותנו כאן. דוגמה פשוטה לתבנית בילינארית היא מכפלה פנימית, ודוגמה פשוטה לתבנית ריבועית שמוגדרת על ידה היא נורמה (כמעט; כזכור, נורמה היא השורש של מכפלה פנימית של וקטור עם עצמו). תבניות בילינאריות וריבועיות מופיעות באינספור מקומות במתמטיקה, הגם שהן קצת פחות נפוצות מטרנספורמציות לינאריות, ולרוב מגיעים אליהן רק בקורס שני באלגברה לינארית.

עכשיו בואו נעזוב את האלגברה הלינארית הכללית ונזכור שאנחנו מדברים על המקרה שבו \(\mathbb{F}=\mathbb{R}\). בממשיים יש יחס סדר – אפשר להגיד "חיובי" ו"שלילי" (אפילו ב-\(\mathbb{C}\) אי אפשר להגיד דברים כאלו). זה מוביל אותנו להגדרה שאנחנו רוצים – \(A\) היא מטריצה חיובית לחלוטין אם התבנית הריבועית שהיא מגדירה מקיימת ש-\(g_{A}\left(x\right)>0\) לכל \(x\ne0\) (עבור \(x=0\) תמיד נקבל \(g_{A}\left(x\right)=0\), כמובן). בדומה \(A\) היא שלילית לחלוטין אם \(g_{A}\left(x\right)<0\) לכל \(x\ne0\). עבור מטריצה מסדר \(1\times1\) הקריטריון הזה שקול לכך שהכניסה היחידה של המטריצה תהיה חיובית/שלילית (כי אם \(A=\left[a\right]\) אז נקבל ש-\(g_{A}\left(x\right)=a\cdot x^{2}\)) ולכן קיבלנו פה הכללה של התוצאה עבור \(n=1\).

כדי להבין למה זה עובד ומאיפה \(H\) הגיעה בכלל אני צריך לשלוף מהכובע שפן שלפחות לעת עתה בחרתי לא לתת לו פוסט, אבל אולי בעתיד כן – פולינומי טיילור. תיארתי אותם פעם בבלוג במקרה החד ממדי, וכנראה שכדאי לתאר אותם בפירוט גם במקרה הרב ממדי, אבל לבינתיים אסתפק בהסבר קצר. כזכור, פולינום טיילור "רגיל" מאפשר לנו לקרב פונקציות מסובכות על ידי פולינומים שמחושבים מתוך כל הנגזרות של הפונקציה בנקודה מסויימת ש"סביבה" מפתחים אותה. פורמלית, \(f\left(x_{0}+h\right)=\sum_{k=0}^{n}\frac{f^{\left(k\right)}\left(x_{0}\right)}{k!}h^{k}+R_{n+1}\left(x_{0},h\right)\), כאשר \(\sum_{k=0}^{n}\frac{f^{\left(k\right)}\left(x_{0}\right)}{k!}h^{k}\) הוא הפולינום, ואילו \(R_{n+1}\left(x_{0},h\right)\) היא פונקציית ה"שארית" שמתארת את הטעות של הפולינום (ומן הסתם לב העניין הוא לחסום את הגודל שלה, מה שיוצא שונה עבור פונקציות שונות ונקודות פיתוח שונות). לפעמים פשוט כותבים טור חזקות אינסופי, \(\sum_{n=0}^{\infty}\frac{f^{\left(n\right)}\left(x_{0}\right)}{n!}h^{n}\), אבל עם הכתיב הזה צריך להיזהר כי לא בהכרח ברור עבור אילו ערכים של \(h\) הטור הזה מתכנס בכלל (עבור \(h=0\) הוא מתכנס תמיד, אבל פרט לכך? הדיון על רדיוס ההתכנסות של טורי חזקות הוא מעניין בפני עצמו וצריך להציג אותו בבלוג מתישהו) וגם לא ברור שאפילו אם הטור מתכנס, אז \(f\left(x_{0}+h\right)\) שווה לסכום שלו.

פולינומי טיילור של פונקציות \(f:\mathbb{R}^{n}\to\mathbb{R}\) עובדים בצורה דומה, אבל כפי שאתם מנחשים, צריך לזרוק פנימה את כל הנגזרות החלקיות וזה יוצא מתוסבך למדי לכתיבה בלי שמסכימים מראש על כל מני קיצורים. בכל זאת אני לא יכול להתאפק ואציג את הטור המלא של פיתוח סביב \(\left(a_{1},\dots,a_{n}\right)\):

\(\sum_{k_{1}=0}^{\infty}\cdots\sum_{k_{n}=0}^{\infty}\frac{\partial^{k_{1}}}{\partial x_{1}^{k_{1}}}\cdots\frac{\partial^{k_{n}}}{\partial x_{n}^{k_{n}}}f\left(a_{1},\dots,a_{n}\right)\frac{h_{1}^{k1}\cdots h_{n}^{k_{n}}}{k_{1}!\cdots k_{n}!}\)

או במילים: כל איבר בטור הזה מתקבל על ידי כך שגוזרים את \(f\) מספר מסויים של פעמים על פי כל משתנה, כופלים את התוצאה בחזקות מתאימות של כניסות \(\left(h_{1},\dots,h_{n}\right)\) ומחלקים בעצרת מתאימה. בואו נראה דוגמה פשוטה עבור פונקציה \(f\left(x,y\right)\) שהיא ב-\(C^{2}\) ולכן \(\frac{\partial^{2}f}{\partial x\partial y}=\frac{\partial^{2}f}{\partial y\partial x}\); נפתח את הטור עד סדר שני, כלומר עד וכולל ערכי ה-\(k\) שמקיימים \(k_{1}+k_{2}=2\):

\(f\left(x+h_{1},y+h_{2}\right)=f\left(x,y\right)+\frac{\partial f}{\partial x}\left(x,y\right)h_{1}+\frac{\partial f}{\partial y}\left(x,y\right)h_{2}+\frac{\partial^{2}f}{\partial x^{2}}\left(x,y\right)\frac{h_{1}^{2}}{2}+\frac{\partial^{2}f}{\partial y^{2}}\left(x,y\right)\frac{h_{2}^{2}}{2}+\frac{\partial^{2}f}{\partial x\partial y}\left(x,y\right)h_{1}h_{2}+R_{3}\left(h_{1},h_{2}\right)\)

ואם יש לנו \(n\) משתנים, הכתיב נשאר דומה:

\(f\left(x_{1}+h_{1},\dots,x_{n}+h_{n}\right)=f\left(x_{1},\dots,x_{n}\right)+\sum_{i=1}^{n}\frac{\partial f}{\partial x_{i}}\left(x_{1},\dots,x_{n}\right)h_{i}+\frac{1}{2}\sum_{i,j=1}^{n}\frac{\partial^{2}f}{\partial x_{i}\partial x_{j}}\left(x_{1},\dots,x_{n}\right)h_{i}h_{j}+R_{3}\left(h_{1},\dots,h_{n}\right)\)

כאן אנחנו קצת מרמים בסימון אבל מתקנים את זה בו זמנית: למשל, בסכום מופיעים גם \(\frac{\partial^{2}f}{\partial x_{1}\partial x_{2}}\) וגם \(\frac{\partial^{2}f}{\partial x_{2}\partial x_{1}}\) למרות שהאיבר הזה (אלו שתי הצגות שונות לאותו איבר, כי אמרתי שבמקרה שלנו הנגזרות המעורבות שוות) אמור להופיע רק פעם אחת. אז יש לי ספירה כפולה, אבל זה מתקזז עם הכפל ב-\(\frac{1}{2}\) שהוספתי שם (אם תשימו לב, בנוסחה המקורית אם גזרנו פעמיים לפי אותו משתנה צריך לכפול ב-\(\frac{1}{2!}\) ואם גזרנו לפי שני משתנים שונים לא עושים את זה).

את כל זה אפשר לכתוב אפילו עוד יותר בקיצור:

\(f\left(x+h\right)=f\left(x\right)+\nabla f\left(x\right)\cdot h+\frac{1}{2}H_{x}\left(h\right)+R_{3}\left(h\right)\)

במילים אחרות, הגרדיאנט של \(f\) הוא "האיבר הראשון" בפיתוח טיילור של \(f\), וההסיאן \(H\) הוא "האיבר השני". האנלוגיה למקרה החד ממדי (שבו האיבר הראשון בפיתוח הוא הנגזרת הראשונה, והאיבר השני הוא הנגזרת השניה) מובהקת כאן.

איך כל זה רלוונטי לענייננו? כזכור, אנחנו מניחים שב-\(x\) יש ל-\(f\) נקודה קריטית ורוצים לסווג אותה. נקודה קריטית פירושו של דבר ש-\(\nabla f\left(x\right)=0\), כך שאפשר לכתוב את פיתוח הטיילור גם בתור

\(f\left(x+h\right)-f\left(x\right)=\frac{1}{2}H_{x}\left(h\right)+R_{3}\left(h\right)\)

נניח שההסיאן ב-\(x\) הוא חיובי לחלוטין, ולכן על פי המשפט אמור לנבוע מכך ש-\(x\) היא נקודת מינימום. אם \(x\) היא נקודת מינימום של \(f\), אנחנו מצפים שאגף שמאל יהיה חיובי עבור כל ה-\(h\)-ים בסביבה קרובה מספיק של \(x\). ומה קורה באגף ימין? יש לנו קרב ענקים בין ההסיאן ובין \(R_{3}\left(h\right)\), השארית. כאן מגיע טיעון אינפי סטנדרטי – אם ניקח \(h\) "מספיק קטן" אז מצד אחד השארית תהיה קטנה מאוד, ומצד שני ההסיאן יחזיר לנו ערך שהוא יחסית גדול וחיובי, והערך הזה "ינצח" בתחרות. אני אדלג על המשך ההוכחה כי הוא טכני באופן סטנדרטי ואומר בדיוק את זה; הפואנטה המרכזית היא שבגלל שההסיאן הוא פונקציה "נחמדה" (בילינארית) מקבלים שקיים קבוע \(M\) כלשהי כך ש-\(H\left(h\right)\ge M\|h\|^{2}\) לכל \(h\), וזה נותן לנו את ה"יחסית גדול וחיובי" שלנו. הפרטים הטכניים פחות קריטיים פה – מה שמעניין בסיפור הזה, לטעמי, הוא מאיפה ההסיאן הזה צץ בכלל; כשברור שזה הרכיב השני בפיתוח הטיילור של הפונקציה, ושהרכיב הראשון איננו עמנו עוד כי אנחנו בנקודה קריטית, העניין נהיה מאוד ברור.

חלק שני, שבו כל העסק נהיה מאולץ

בתחילת הפוסט אמרתי שבבעיות אופטימיזציה יש לנו לעתים קרובות אילוצים על המערכת, כלומר לא כל פרמטר הוא חוקי. זה מגדיל מייד את רמת הקושי של הבעיה שלנו ועל פניו הופך את כל הטכניקה שראינו עד כה לחסרת תועלת. אתן דוגמה פשוטה. נסתכל על הפונקציה \(f:\mathbb{R}^{2}\to\mathbb{R}\) המוגדרת על ידי \(f\left(x,y\right)=x\). בבירור אין לה לא נקודת מינימום ולא נקודת מקסימום בשום מקום ולכן הטכניקה שראינו קודם לא תסייע לנו עם העיסוק בה בכלל. מצד שני, אם נוסיף למערכת את האילוץ שהקלטים ל-\(f\) חייבים להילקח רק ממעגל היחידה, אז ברור שפתאום יש ל-\(f\) מקסימום ב-\(\left(1,0\right)\) ומינימום ב-\(\left(-1,0\right)\). אבל איך מוצאים את זה?

לפני שנפתור את הבעיה הזו, צריך להבין מה המשמעות של "אילוץ". עבורנו זה אומר שנתונה פונקציה \(g:\mathbb{R}^{n}\to\mathbb{R}\) כלשהי ונתון \(c\in\mathbb{R}\), ואנחנו מגדירים אילוץ על ידי המשוואה \(g\left(x\right)=c\). כלומר, מותר לחפש את הפתרון רק בקרב ה-\(x\)-ים שמקיימים \(g\left(x\right)=c\). בדוגמה שלי, \(g\left(x,y\right)=x^{2}+y^{2}\) ואילו \(c=1\). כפי שבטח כבר ברור לכם, השיטה הזו להבעת אילוצים היא נוחה מאוד ומאפשרת לתאר שלל יצורים גאומטריים (ראינו כרגע מעגל; קו ישר מתואר על ידי \(g\left(x,y\right)=ax-by\) עבור \(a,b\) כלשהם, וכדומה).

כעת, נניח ש-\(g\) היא פונקציה "נחמדה" – גזירה. נסמן ב-\(S\) את המרחב שמוגדר על ידי \(S=\left\{ x\in\mathbb{R}^{n}\ |\ g\left(x\right)=c\right\} \) (מעכשיו אקרא לו "משטח" כי בתלת מימד משוואות כאלו מגדירות משטחים; שם מדויק יותר למקרה הכללי שבו אני עוסק הוא יריעה אבל זה מושג לא טריוויאלי ואני לא רוצה להיכנס להגדרה שלו כרגע), וניקח \(x_{0}\in S\) כלשהו. הנה אבחנה מיידית שבלבלה אותי בצורה יוצאת דופן כשרק למדתי את הנושא הזה: \(\nabla g\left(x_{0}\right)\) הוא אורתוגונלי ל-\(S\) בנקודה \(x_{0}\). הגרדיאנט של הפונקציה שמגדירה את המשטח ניצב למשטח באותה נקודה. למה זה מבלבל? כי לעתים קרובות נהוג להגדיר את הגרדיאנט של פונקציה בנקודה כלשהי בתור הוקטור שמצביע על הכיוון שבו היא "הכי תלולה". אם הגרדיאנט ניצב למשטח, הוא מצביע על כיוון שבו הפונקציה בכלל לא גדלה, וזה נראה הכי לא נכון שרק אפשר. אז למה זה מסתדר?

זה מסתדר כי עשיתי מיש-מש מכל העסק. הגרדיאנט לא ניצב לפונקציה; הוא ניצב למשטח שהפונקציה מגדירה בצורה מסויימת. מה שבלבל אותי בשעתו הוא שאפשר להגדיר משטחים בשתי דרכים שונות. דרך אחת, כללית פחות, היא לכתוב \(z=f\left(x,y\right)\) ובכך לתאר את המשטח \(S=\left\{ \left(x,y,f\left(x,y\right)\right)\ |\ x,y\in\mathbb{R}^{2}\right\} \); הדרך השניה, הכללית יותר, היא לכתוב \(S=\left\{ \left(x,y,z\right)\ |\ F\left(x,y,z\right)=c\right\} \). שימו לב שבדרך הראשונה אנחנו משתמשים בפונקציה של שני משתנים ובשניה בפונקציה של שלושה משתנים כדי להגדיר את אותו הדבר – משטח ב-\(\mathbb{R}^{3}\). אם יש לי פונקציה \(f:\mathbb{R}^{2}\to\mathbb{R}\) ואני רוצה להציג את המשטח שמוגדר על ידה בדרך הראשונה בעזרת דרך ההצגה השניה, אני פשוט אגדיר \(F\left(x,y,z\right)=z-f\left(x,y\right)\) ו-\(c=0\); לכן דרך ההצגה השניה כללית יותר. היא כללית יותר ממש (כלומר, יש דברים שאי אפשר לעשות בדרך הראשונה) כי למשל אני יכול לתאר את כדור היחידה על ידי \(F\left(x,y,z\right)=x^{2}+y^{2}+z^{2}\) ו-\(c=1\), אבל אין לי דרך לעשות את זה באמצעות הצגת קואורדינטת ה-\(z\) כפונקציה של שתי האחרות (כי עבור אותם \(x,y\) עשויים להיות שני ערכי \(z\) אפשריים שונים על המשטח).

הנה הוכחה זריזה לכך שהגרדיאנט ניצב למשטח שהפונקציה מגדירה. הרעיון הוא לקחת מסלול כלשהו במשטח שעובר דרך \(x_{0}\) ולהראות שהגרדיאנט ב-\(x_{0}\) ניצב אליו. בלי להיכנס לעובי ההגדרות, מסלול הוא פונקציה גזירה \(c:\left[0,1\right]\to\mathbb{R}^{n}\), ומסלול במשטח \(S\subseteq\mathbb{R}^{n}\) מקיים את הדרישה ש-\(c\left(\left[0,1\right]\right)\subseteq S\), ונניח ש-\(c\left(0\right)=x_{0}\). עכשיו, הרעיון במסלול שעובר דרך \(S\) הוא שכל נקודה בו מקיימת את האילוץ שמגדיר את \(S\). נניח שהאילוץ הזה הוא \(F\left(x\right)=c\), אז \(F\left(c\left(t\right)\right)=c\) לכל \(t\in\left[0,1\right]\). עכשיו אפשר להשתמש בכלל השרשרת, לגזור ולקבל ש-\(DF\left(c\left(0\right)\right)\cdot Dc\left(0\right)=0\), או בסימון קצת שונה, ש-\(\nabla F\left(x_{0}\right)\cdot c^{\prime}\left(0\right)=0\). עכשיו, \(c^{\prime}\left(0\right)\) הוא בדיוק שיפוע המשיק ל-\(c\) ב-\(x_{0}\), ואילו \(\nabla F\left(x_{0}\right)\) הוא הגרדיאנט של \(F\), וקיבלנו שהמכפלה הפנימית שלהם היא 0 – כלומר, הם ניצבים.

עכשיו בואו נפתור את הבעיה של אופטימיזציה-עם-אילוצים. הפתרון הוא סוג של הכללה של מה שראינו קודם. קודם בדקנו איפה הגרדיאנט של \(f\) מתאפס. ההכללה שלנו תהיה לבדוק איפה הגרדיאנט של \(f\) שווה לצירוף לינארי של האילוצים. המקדמים של האילוצים נקראים "כופלי לגראנז'", והשיטה נקראת על שמם – שיטת כופלי לגראנז'.

הנה הניסוח הפורמלי. נניח שיש לנו פונקציה \(f:\mathbb{R}^{n}\to\mathbb{R}\) שהיא מה שאנחנו רוצים לאפטמז, ופונקציות אילוצים \(g_{1},\dots,g_{k}:\mathbb{R}^{n}\to\mathbb{R}\) עם קבועים \(c_{1},\dots,c_{k}\) שמגדירות קבוצה \(S\) (כלומר, האילוץ הוא \(g_{i}\left(x\right)=c_{i}\) עבור \(1\le i\le k\)). נניח ש-\(x_{0}\) היא נקודה שמקיימת את כל האילוצים (\(g_{i}\left(x_{0}\right)=c_{i}\)) וש-\(\nabla g_{i}\left(x_{0}\right)\ne0\), ושיש ל-\(f|_{S}\) מקסימום או מינימום מקומי ב-\(x_{0}\) (הסימון \(f|_{S}\) פירושו "\(f\) מצומצמת ל-\(S\)"), אז קיימים \(\lambda_{1},\dots,\lambda_{k}\in\mathbb{R}\) כך ש-\(\nabla f\left(x_{0}\right)=\lambda_{1}\nabla g_{1}\left(x_{0}\right)+\dots+\lambda_{k}\nabla g_{k}\left(x_{0}\right)\). זה אומר שכשאנחנו מחפשים נקודות קיצון, אנחנו מקבלים מערכת של משוואות שנקודות הקיצון חייבות להיכלל בפתרונות שלה.

בואו נראה איך זה עובד במקרה של דוגמת המעגל שנתתי קודם. מכיוון ש-\(f\left(x,y\right)=x\) אז \(\nabla f=\left(1,0\right)\), ומכיוון ש-\(g\left(x,y\right)=x^{2}+y^{2}\), אז \(\nabla g=\left(2x,2y\right)\). משוואת כופלי לגראנז' נותנת לנו כאן את המשוואה \(\left(1,0\right)=\lambda\left(2x,2y\right)\) שמתורגמת בתורה לשתי משוואות פשוטות:

\(2x\lambda=1\)

\(2y\lambda=0\)

מהמשוואה הראשונה ברור ש-\(\lambda\ne0\) ולכן מהשניה קיבלנו ש-\(y=0\) הוא הכרחי. הנקודות היחידות שמקיימות את האילוץ \(g\left(x,y\right)=1\) ומקיימות \(y=0\) הן \(\left(1,0\right)\) ו-\(\left(-1,0\right)\) ועבור כל אחת מהן יש, כמובן, \(\lambda\) שפותר את המשוואה. קיבלנו ששתי אלו הן נקודות הקיצון שלנו, וזה אכן מה שהתחלתי ממנו.

חסרים לנו עוד שני דברים – אינטואיציה למה כל זה עובד, והוכחה. את ההוכחה המלאה אני לא אביא כאן, ובמקום זה אתן דגש חזק על הרעיונות הכלליים. הדבר הראשון שצריך להבין הוא שנתתי למעלה את הגרסה ה"שימושית" של המשפט – קחו את הגרדיאנט של \(f\), אז הוא צירוף לינארי של הגרדיאנטים של האילוצים. זה משהו שקל להשתמש בו פרקטית, אבל זו לאו דווקא הדרך הקלה ביותר לחשוב על המשפט. אז הנה ניסוח כללי יותר של המשפט: אם \(S\) הוא משטח, \(x_{0}\in S\) היא נקודה על המשטח ו-\(f\) היא פונקציה כך של-\(f|_{S}\) יש נקודת קיצון ב-\(x_{0}\), אז המישור המשיק ל-\(S\) בנקודה \(x_{0}\) מוכל בגרעין של \(\nabla f\left(x_{0}\right)\). אם אני אסמן את המישור המשיק ל-\(S\) בנקודה \(x_{0}\) בתור \(T_{x_{0}}S\) אז אפשר לכתוב פשוט \(T_{x_{0}}S\subseteq\ker\left(\nabla f\left(x_{0}\right)\right)\) (אתם אמורים להכיר גרעין כי זה מושג בסיסי באלגברה לינארית; אוסף כל הנקודות שמאפסות את הטרנספורמציה הלינארית \(\nabla f\left(x_{0}\right)\)).

המשפט הזה מכליל את התוצאה שלנו על נקודות קיצון ללא אילוצים: אם אין אילוצים, אז המשטח \(S\) שלנו הוא המרחב כולו, ולכן הדרך היחידה שבה הוא יהיה מוכל בגרעין של טרנספורמציה לינארית כלשהי הוא שזו תהיה טרנספורמציית האפס (עם זאת, כמו שנראה בהמשך, אנחנו משתמשים במשפט ה"בסיסי" כדי להוכיח את המשפט הכללי יותר, כך שאי אפשר להשתמש במשפט הכללי כדי לחסוך לנו עבודה).

הדרך להגיע מהניסוח הזה לניסוח שהצגתי קודם היא דרך תוצאה לא מרתקת במיוחד באלגברה לינארית: נניח ש-\(f:\mathbb{R}^{n}\to\mathbb{R}\) היא טרנספורמציה לינארית ו-\(G:\mathbb{R}^{n}\to\mathbb{R}^{m}\) היא טרנספורמציה לינארית, אז \(\ker G\subseteq\ker f\) אם ורק אם קיימים \(\lambda_{1},\dots,\lambda_{m}\) כך ש-\(f=\sum\lambda_{i}G_{i}\), כאשר \(G_{i}\) הוא ההטלה של \(G\) לרכיב ה-\(i\), כלומר \(G_{i}\left(a\right)=\left[G\left(a\right)\right]_{i}\).

מה שמעניין הוא להבין מה האינטואיציה שמאחורי המשפט הכללי. למה שהוא יהיה נכון? הנקודה הקריטית היא שאם \(S\) הוא משטח שמוגדר בצורה "נחמדה מספיק" אז בהינתן נקודה \(x_{0}\in S\) כלשהי, יש סביבה של \(x_{0}\) שנראית כמו תת-מרחב לינארי של \(\mathbb{R}^{n}\). ההגדרה של "יריעה", שאני חומק ממנה בפוסט הזה, מפרמלת את הרעיון הזה; בואו נראה דוגמה פשוטה. את המעגל שלנו מתחילת הפוסט אפשר לתאר באמצעות פרמטריזציה: פונקציה גזירה \(p:\mathbb{R}\to\mathbb{R}^{2}\) שמוגדרת על ידי \(p\left(t\right)=\left(\sin t,\cos t\right)\). על ה-\(p\) הזו אפשר להרכיב את \(f\) שלנו, שהיא הפונקציה שאנחנו מנסים לאפטמז, ולקבל את הפונקציה \(\varphi\left(t\right)=f\left(p\left(t\right)\right)=\sin t\). קיבלנו פונקציה במשתנה בודד שמוגדרת מעל \(\mathbb{R}\), כך שאפשר לחפש לה מקסימום ומינימום בדרך הרגילה – גוזרים ומשווים לאפס. תנסו, תראו שזה עובד.

אז גם באופן כללי, אם יש לנו פרמטריזציה של \(S\) בסביבה של \(x_{0}\) מצבנו טוב. בואו נניח ש-\(p:\mathbb{R}^{n}\to\mathbb{R}^{n}\) היא פרמטריזציה שכזו; פירוש הדבר הוא ש-\(p\left(\mathbb{R}^{n}\right)\) הוא סביבה של \(x_{0}\) ב-\(S\). אנחנו מניחים שב-\(x_{0}\) יש ל-\(f\) נקודת קיצון מקומית; בואו נסמן ב-\(a\in\mathbb{R}^{n}\) נקודה שמקיימת \(p\left(a\right)=x_{0}\). אז לפונקציה \(f\left(p\left(t\right)\right)\) יש נקודת קיצון מקומית ב-\(a\), מה שאומר ש-\(D\left[f\left(p\left(a\right)\right)\right]\) תהיה טרנספורמציית האפס. מכלל השרשרת נובע שזה אומר ש-\(Df\left(p\left(a\right)\right)\cdot Dp\left(a\right)\) היא טרנספורמציית האפס.

עכשיו, את \(Df\left(p\left(a\right)\right)\) אנחנו מכירים בסימון קצת שונה. ראשית, \(p\left(a\right)=x_{0}\). שנית, מכיוון ש-\(f\) היא פונקציה שמחזירה סקלר, אני מסמן את \(Df\) ב-\(\nabla f\). כלומר, \(Df\left(p\left(a\right)\right)=\nabla f\left(x_{0}\right)\) הישן והטוב.

שנית, מה זה \(Dp\left(a\right)\)? זכרו ש-\(p\) היא פונקציה שמגדירה לנו משטח; לכן \(Dp\left(a\right)\) מתארת את המישור המשיק למשטח בנקודה \(p\left(a\right)=x_{0}\), מה שסימנתי בתור \(T_{x_{0}}S\) (כן, זה היה נפנוף ידיים). כלומר, לכל קלט שהיא מקבלת, \(Dp\left(a\right)\) מחזירה לנו נקודה ששייכת ל-\(T_{x_{0}}S\).

עכשיו, ראינו שההרכבה של \(\nabla f\left(x_{0}\right)\) על \(Dp\left(a\right)\) היא זהותית אפס. זה אומר שלכל קלט ש-\(Dp\left(a\right)\) מקבלת, הפלט שלה (נקודה ב-\(T_{x_{0}}S\)) יגרום ל-\(\nabla f\left(x_{0}\right)\) להחזיר אפס. מכיוון ש-\(Dp\left(a\right)\) היא פונקציה על כל \(T_{x_{0}}S\) נקבל את התוצאה – \(T_{x_{0}}S\subseteq\ker\nabla f\left(x_{0}\right)\). הפורמליזם פה לא היה מלא אבל אני מקווה שהרעיון ברור עכשיו.

אז בנוגע למתמטיקה ובית הספר…

עד היום נמנעתי כמעט לגמרי מהתייחסויות בבלוג אל מה שהוא אולי הדבר החשוב ביותר למרבית הציבור בכל הנוגע למתמטיקה – האופן שבו נלמדת מתמטיקה בבתי הספר. האדם הממוצע הולך לפגוש את המתמטיקה כמעט אך ורק במסגרת הזו, והמסגרת היא זו שתקבע מה תהיה ההתרשמות שלו מהמתמטיקה. וכפי שכולנו יודעים, ההתרשמות הזו היא כמעט תמיד שלילית. וכולנו תוהים – האם לא ניתן לעשות את זה אחרת? בשנים האחרונות השאלה הזו עולה שוב ושוב בדיונים על האם כן צריך ללמד מתמטיקה לבגרות, או לא ללמד, והאם 5 יחידות, או לא 5 יחידות, והאם עתיד ההייטק של המדינה בסכנה, או לא בסכנה, ועוד כהנה וכהנה.

אז למה לא דיברתי על זה עד היום, בעצם? התשובה פשוטה: כי אני לא יודע כלום על חינוך מתמטי ברמת בית הספר.

יש לי נסיון כלשהו בהוראה של סטודנטים, ועוד נסיון קטן עם תלמידים מצטיינים בגיל חטיבת ביניים. האתגר שתלמידים כאלו מציבים בפני המורה הוא נמוך יחסית. אלו תלמידים שרוצים לדעת את החומר (סטודנטים אולי לא אוהבים את החומר בהכרח, אבל הם רוצים לדעת אותו כדי להצליח בקורס, והם על פי רוב לא נמצאים בלימודים האקדמיים כי מכריחים אותם) ושומרים על קשב גבוה ולא מפריעים כמעט בכלל. לעומת זאת, האתגר שהמורה עומד בפניו בכיתה ממוצעת של תלמידים הוא אדיר. מאמץ גדול נדרש רק כדי לשמור על הקשב ולמנוע הפרעות, רמת התלמידים לא אחידה, והמורה עצמו לאו דווקא שולט בצורה מיטבית בחומר. וזה מבלי שהתחלנו לדבר בכלל על חומר הלימוד. נסיון לחשוב איך צריכה להיראות, בעצם, תוכנית לימודים שגם יהיה לה סיכוי להיות מועברת בפועל בכיתות אמיתיות עם מורים אמיתיים זה אתגר כביר, ומה שנראה לנו נחמד על הנייר, כלל לא מובטח שיעבוד בפועל. הדבר היחיד שאני יכול לומר בודאות הוא שאין לי מושג וחצי מושג בנושא וכל מה שאני אומר צריך להילקח בערבון מוגבל גדול מאוד בשל כך.

עדיין, אולי כדאי שאגיד את דעתי, ושהדעה הזו לא תובא בתור סוף פסוק אלא בתור ההזמנה שלי להתחיל דיון, שממנו אני בוודאי אחכים (וכמובן, מאוד אשמח אם אנשים שאכן משתתפים בקביעת מדיניות לימודי המתמטיקה בבתי הספר ישתתפו בו).

הטרגדיה של שימוש בטובה בתור מפוח עלים

כמעט בכל דיון על מתמטיקה בבית הספר שאני משתתף בו צץ מתישהו מאמר בשם A Mathematicians Lament של פול לוקהארט שעוסק בחינוך מתמטי בבתי הספר. אני ממליץ על המאמר הזה (אבל לא מסכים עם כולו), אבל לא אגיד עליו כמעט כלום כאן אלא אנסה לכתוב פוסט שיעמוד בפני עצמו. מה שאני רוצה לשאול ממנו הוא את הפתיחה שלו, שמנסה להבהיר עד כמה המתמטיקה שנלמדת בבתי הספר נדמית לנו, האנשים ש"מכירים" מתמטיקה, בתור פספוס. אם תרצו, זהו נסיון להסביר מדוע הרצון שלנו לגרום לאנשים לאהוב מתמטיקה נידון לכשלון עוד לפני שניסינו בכלל – אנחנו מלמדים את הדבר הלא נכון. אבל כמובן, זה לא אומר שאנחנו מלמדים בטעות סינית במקום מתמטיקה; זה האופן שבו מלמדים חומר שללא ספק שייך למתמטיקה שכל כך בעייתי.

האנלוגיה של לוקהארט היא ללימודי מוזיקה. הוא מתאר מוזיקאי מבועת שמתעורר מחלום שבו לימודי המוזיקה עוסקים בקריאת דפי תווים. ביכולת להעתיק דפי תווים, לזהות סולמות, קונטרפונקטים ועוד כהנה וכהנה. מה שהם לא עושים בשום צורה הוא לשמוע מוזיקה או אפילו לראות כלי נגינה. אתם מוזמנים לקרוא את התיאור המלא – המאמר נפתח בו – עבורי התיאור הזה מצמרר לגמרי, כי הוא קולע בול אל לימודי מתמטיקה בבתי הספר כפי שאני מכיר אותם.

לוקהארט הולך לכיוון המוזיקה כי הוא רוצה לתאר את המתמטיקה בתור אמנות, בדומה לכך שהמוזיקה היא אמנות, אבל אני לא רוצה ללכת לכיוון הדיון הזה ורוצה לתת אנלוגיה אחרת. כמעט כל דיון על חינוך מתמטי בבית הספר מדבר על השימושיות של המתמטיקה, ועל כמה שהיא קריטית כדי לקיים לימודי מדע וטכנולוגיה גבוהים, ובשביל שתעשיית ההייטק תתקיים, וכדי שהשמש תזרח מחר ועוד כהנה וכהנה. עוד ביטוי אהוב בהקשר הזה הוא התיאור של המתמטיקה כארגז כלים. אז יאללה, בואו נלך אל הגישה הזו עבור מקצוע לימודים בדיוני – לימודי איקאה.

אני מניח שלא מעטים הקוראים שמתעבים את איקאה בכל ליבם או לא מבינים מה לכל הרוחות הקטע. וזה בסדר – הרי אותו הדבר קורה גם עם מתמטיקה. אבל בואו תחשבו לרגע על חובב איקאה מושבע. אחד כזה שאוהב את הרהיטים ואוהב להשתמש בהם ואוהב להרכיב אותם. אחד שבשבילו זה כמו משחק לגו גדול, עם ערך מוסף אחר כך של רהיט שאפשר לשים בו בגדים, או לישון בו, או לשבת לאכול עליו. והוא אוהב לבקר בחנות של איקאה (בשעות שבהן אין בני אדם – הוא יודע בדיוק מה הן כי הוא חובב איקאה), להסתכל על המגוון האדיר של רהיטים, אולי אפילו לשוטט קצת בדירות לדוגמא של "בואו תראו איך אנחנו וכל משפחתנו המורחבת והחתול וחזירון המחמד גרים בכיף ב-13 מטר מרובע!!!!!". והוא אוהב את תהליך הבניה – לפתוח את הקרטון, לשים לעצמו מוזיקה קלאסית ברקע, להצמיד לוח אל לוח, לסובב ברגים, לדפוק בפטיש, והופס – לראות איך מערימה אקראית של דברים צץ לו רהיט חדש. ואולי הוא אפילו אוהב לעשות האקינג – לקחת את חלקי הרהיטים ולבנות אותם שלא על פי ההוראות, כדי לקבל משהו חדש שמתאים לו אישית. והוא כנראה גם מפרסם את מעלליו באינטרנט לחבריו חובבי האיקאה, ואולי גם יומנים מצולמים, וכדומה.

ועכשיו האיש הזה מגלה שבבתי הספר התחילו ללמד "לימודי איקאה". והוא קופץ לראות איך השיעורים מתנהלים, ורואה שהם מתנהלים ככה: בשיעור הראשון מציגים תמונה מאמצע מדריך בניה של מיטה. אנחנו בדיוק בשלב שבו לוקחים את בורג מס' 11467 ומבריגים אותו לתוך לוח. עם מברג שטוח. המורה מסביר את זה לתלמידים כמה פעמים, באופן זה: ב-ו-ר-ג מספר אחד-אחד-ארבע-שש-שבע. את הבורג מבריגים אל תוך החור האמצעי בקצוות של הלוח. האמצעי. בורג מס' 11467. להבריג. עם מברג. שטוח. בחור האמצעי. בקצוות. של הלוח. עכשיו בואו ונעשה את זה!

במשך יתר השיעור התלמידים מבריגים את הבורג לתוך הלוח. ושוב. ושוב. ושוב. היד מתחילה לכאוב די מהר, אבל הגאווה גדולה – אנחנו כעת שולטים בבורג! אנחנו יודעים להבריג את הבורג לתוך הלוח! את בורג מספר אחד-אחד-ארבע-שש-שבע!

חובב האיקאה חוזר לשיעור הבא. בשיעור הבא שכחנו כבר מהמיטה, ועכשיו אנחנו מתעסקים עם שולחן, או משהו. כמקודם, אנחנו רואים רק תמונה מאמצע המדריך. בתמונה הזו דוחפים איזה משהו מעץ לתוך חורים באיזה… משהו. והמורה אומר: יש להקפיד לדחוף את משהו מעץ מספר אחד-אפס-אחד-שלוש-חמש-אפס! לא את אחד-אפס-אחד-שלוש-חמש-שש! האחד ארוך יותר מהשני! השוו אורכים! בדקו! דחפו את המשהו מעץ! עם האצבעות! מי שקשה לו עם האצבעות, שיאחז פטיש! וכעת, הבה ונתרגל!

ובמשך יתר השיעור התלמידים דוחפים משהו מעץ לתוך משהו אחר מעץ. חלה התרגשות זוטא כשאחד התלמידים דוחף בטעות פנימה משהו מעץ מספר 101356 והוא נתקע שם. המורה המבוהל רץ להביא פלייר ושולף את המשהו השגוי מעץ; התלמידים מתלהבים לרגע מהפלייר אבל המורה מזהיר אותם שזה לא קשור לחומר הלימוד ושזה מתקדם מדי בשבילם אז שישכחו מזה.

וזהו.

ככה מתנהלים כל "לימודי איקאה". בכל משך בית הספר.

חובב האיקאה מבועת. כלומר, הוא מסכים לגמרי שמה שלומדים בשיעורים הללו רלוונטי לאיקאה; אלו דברים שהוא עצמו, בתור חובב איקאה, עושה כל הזמן. זה כישור שהוא הכרחי לבניית רהיטים מאיקאה. אבל בשם האלים הסקנדינביים, למה מלמדים את זה ככה?!

הסיפור נשמע קיצוני, כמובן, אבל לפחות אני מרגיש שזה המצב בפועל בכל הנוגע למתמטיקה תיכונית. לא כולה; אבל חלקים נרחבים יותר מדי ממנה. ואני מאמין שיש לזה השלכה ישירה על תופעת "שנאת המתמטיקה" הידועה לשמצה.

עכשיו צריך לעצור ולשאול את עצמנו כמה שאלות. ראשית, האם התיאור שלי נכון? האם אני צודק? ואולי זה היה נכון כשאני למדתי בבית הספר אבל זה לא נכון עכשיו? ואולי זה נכון עכשיו אבל אוטוטו תהיה תוכנית לימודים חדשה לבתי הספר שתטפל בזה? אלו שאלות טובות. אנסה בהמשך לתת דוגמה או שתיים למשהו שקורה עכשיו בחומר הלימוד, אבל לדבר על מה שיקרה אולי בעתיד אני לא יכול.

שנית, וזו השאלה הקשה יותר, האם אופן הלימוד הזה הכרחי? האם נסיון ללמד מתמטיקה בדרך שלי נראית יפה או מעניינת יותר נידון לכישלון? על זה אני לא יכול לענות, כי אין לי נסיון בהוראה. אני כן יכול להגיד מה לדעתי כדאי לנסות, או מה הכיוון שנראה לי שצריך ללכת אליו, על מנת להפוך את המתמטיקה התיכונית למעניינת יותר, וזה מה שאנסה לעשות.

אני כן רוצה להביא דוגמה אחת מהמאמר של לוקהארט שהיא פשוט נפלאה, לגבי מהי מתמטיקה יפה, מהי מתמטיקה טכנית, וכמה דק ההבדל ביניהן לפעמים. לוקהארט מביא, לכאורה משום מקום, חידה: הנה ציור של משולש בתוך מלבן, ואנחנו רוצים לדעת איזה אחוז משטח המלבן תופס המשולש (יש שלושה משולשים, אני מתכוון לזה הגדול, שהצלע התחתונה שלו היא הצלע התחתונה של המלבן):

tri1

החידה הזו מעלה אוטומטית תחושות רעות: למי אכפת בכלל כמה שטח תופס המשולש? מה זה חשוב? איפה משתמשים בזה בחיים האמיתיים? איכס זה טכני, צריך לחשב שטחים, ואחוזים! מאיפה לנו לדעת, צריך למצוא כלי מדידה! ועוד ועוד ועוד. הבנתם את הקטע. גם בי החידה הזו מעלה את התחושות הללו. אבל צריך להבין שגם אצל המתמטיקאים יש את התחושות הללו, וחלק ממה שהמתמטיקאים עושים הוא למצוא דרך לעקוף אותן. ומה המתמטיקאים עושים כאן? פשוט מאוד – מציירים קו אנכי מהקודקוד העליון של המשולש אל הצלע התחתונה של המלבן:

tri2

והשינוי הקטן הזה פותר הכל. כי פתאום אנחנו רואים שחילקנו את המלבן לארבעה משולשים, כשכל זוג משולשים (שני הימניים ושני השמאליים) הם זהים. אם הם זהים, ברור שהמשולש תופס בדיוק חצי משטח המלבן, וזה מסיים את הכל. זו לא הוכחה מתמטית פורמלית, כי עדיין צריך להראות שבאמת כל זוג משולשים הם זהים, אבל זה עניין של חפיפת משולשים שהוא פשוט למדי, וזה לא העיקר כאן, אלא האופן שבו בעיה מסובכת וגועלית הפכה פתאום לטריוויאלית. אבל למה זה מעניין? ובכן, כי כמעט בלי לשים לב הוכחנו פה את הנוסחה של שטח משולש – שטח המשולש הוא חצי משטח המלבן, ושטח המלבן הוא מכפלה של אורך צלעותיו, אז אפשר לקחת את הצלע התחתונה (שהיא גם צלע של המשולש) ולכפול אותה בצלע השניה (שהיא גם האורך של האנך שהורדנו) ולחלק ב-2. קיבלנו את הנוסחה \(S=\frac{bh}{2}\) לשטח משולש שלרוב פשוט מפילים על התלמידים משום מקום ואז נותנים להם לפתור תרגילים איתה. למה, למה להפיל אותה משום מקום כשכל כך פשוט ויפה להראות איך מגיעים אליה? ההגעה אליה היא יותר מתמטיקה מאשר מאות תרגילים טכניים שבהם התלמידים "ישתמשו" בנוסחה הזו.

ועכשיו שימו לב שבהוכחה הזו השתמשנו בכל מני דברים – בכך שאנחנו בכלל מכירים מלבנים ומשולשים, ובכך שאנחנו יודעים שבמלבן הזוויות הן 90 מעלות, ובכך שאנחנו יודעים מה זה אנך, ואת הקטע הזה של לחלק ב-2, ועוד ועוד. אנחנו צריכים ידע ושליטה טכנית כלשהם כדי להבין מה הולך בהוכחה. אבל זו דוגמה ליישום יפה של הידע הזה. בבתי הספר זה לא ממש מה שקורה.

האם זו דוגמת מחץ שתשכנע אנשים שמתמטיקה היא יפה? כמובן שלא. אני מניח שרוב האנשים יסתכלו על הדוגמה הזו ועדיין יגידו "מה זה גועל הנפש הזה ואיך אתה אומר שהוא יפה?". אבל אני מאמין שיהיו גם אנשים שיגידו "שמע, עד עכשיו לא הבנתי על מה אתה מדבר, אבל עכשיו זה אולי טיפה יותר ברור". וניסיתי למלא את הבלוג בעוד אינספור דוגמאות אחרות, שאולי אחריהן זה יהיה עוד יותר ברור.

מדוע כן ללמד מתמטיקה?

בואו ננסה להבין על מה בעצם לומדים בבתי הספר. כיתות בית הספר בישראל מתחלקות לשלוש "רמות" שונות – בית ספר יסודי (כיתות א' עד ו'), חטיבת הביניים (ז' עד ט') והתיכון (י' עד י"ב). אני אפרט עכשיו מה לומדים בכל כיתה, אבל למי שאין לו כוח הנה התקציר: אני חושב שמה שלומדים עד וכולל חטיבת הביניים הוא בעיקרון טוב, חשוב והכרחי. משהו שכדאי שכל אדם ידע, ואפילו חלקו יהיה שימושי. עוד יותר בקצרה: בבית הספר היסודי לומדים אריתמטיקה (פעולות חשבון בסיסיות) וטיפה גאומטריה; בחטיבת הביניים לומדים יותר גאומטריה ואלגברה בסיסית (פתרון משוואות, חזקות, שורשים וכדומה). ובתיכון מתחילים להתפרש על שלל נושאים שבסופו של דבר נבחנים עליהם בבגרות. ב-3 יחידות לימוד הנושאים כוללים גאומטריה אנליטית, טריגונומטריה, סטטיסטיקה והסתברות, סדרות וחשבון דיפרנציאלי ואינטגרלי (חדו"א). ב-4 יחידות לימוד מתווספות גאומטריה במישור וטריגונומטריה במרחב (וכמו כן החדו"א נראה מקיף יותר), וב-5 יחידות מתווספים וקטורים ומספרים מרוכבים. אני מקווה לכתוב בהמשך פירוט על מה קורה בכל אחד מהתחומים הללו, הן בתיכון והן במתמטיקה "אמיתית", אבל שוב, הנה תקציר: אף אחד מהנושאים הללו לא נראה לי הכרחי לתלמידים, למעט הסטטיסטיקה וההסתברות שהן משהו שאני סבור שראוי להכיר באופן כללי.

אני אנסה לתת נימוק אחד שלדעתי הוא טוב מאוד לגבי מה מבדיל את המתמטיקה הטרום-תיכונית משאר תחומי הלימוד, ובגללו חשוב מאוד ללמוד אותה. מתמטיקה היא באופן כללי תחום שבו חומר הלימוד בנוי בשכבות, כך שכל שכבה נזקקת לקודמותיה באופן קריטי. מי שאינו שולט בחיבור, לא יוכל לבצע כפל; מי שלא יודע לבצע כפל, יסתבך עם שברים ואחוזים; מי שמסתבך עם שברים יכול לשכוח מפתרון משוואות בנעלם אחד; מי שלא יודע לפתור משוואות בנעלם אחד, יכול לשכוח מחדו"א. אני לא מכיר מקצוע בית ספרי כלשהו שבו המצב דומה. בלימודי היסטוריה, למשל, לומדים על תקופות ואירועים רבים, אבל אם נשכח לגמרי את כל האימפריה הרומית, למשל, עדיין נוכל להבין לא רע את מלחמת העולם השניה. במתמטיקה זה לא כך. המתמטיקה הרבה פחות סלחנית. קפצתם מעגלת המתמטיקה? חלפו שניותיים והנה נשארתם מאחור.

זה אחד ההסברים הנפוצים עבור הקושי של המתמטיקה הבית ספרית. שמעתי סיפורים אישיים עגומים רבים על אנשים שהגיעו למסקנה שמתמטיקה היא לא בשבילם, וברוב המקרים הסיטואציה הייתה דומה – בשלב זו או אחר התלמיד איבד לרגע את החומר, והמורה היה לא סלחן ולא סבלני ולא סייע לו להשלים, ומאותו רגע והלאה הכל היה אבוד והשליטה במתמטיקה מעולם לא חזרה. הייתה לי בעיה דומה עם לימודי שפות – הן בצרפתית והן בערבית בשלב מוקדם כלשהו לא הבנתי את מה שהמורה אמרה, ומאותו רגע והלאה היא הניחה שאני מכיר מילים שלא הכרתי, ולא הצלחתי להבין יותר מה היא אמרה והסוף הגיע חיש קל. אבל בלימודי שפה הסכנה של אובדן מוחלט מצויה בעיקר בתחילת הדרך, כשעוד מחפשים נקודת אחיזה בסיסית; במתמטיקה זה כל הזמן כך. גם במתמטיקה אוניברסיטאית. על כן, אם נוותר על המתמטיקה הטרום תיכונית, אפילו קצת, התלמידים יאבדו את זה, ונקבל מצב שבו אף אחד לא יודע שום דבר במתמטיקה ואין לו יכולת ללמוד מתמטיקה רצינית יותר, או פיזיקה, או כל תחום מדעי אחר שנזקק למתמטיקה, בלי השלמה שתהיה קשה מאוד לביצוע. במתמטיקה תיכונית המצב שונה מכיוון שאת רוב המתמטיקה שם לומדים ממילא מחדש, ברמה גבוהה יותר, באוניברסיטה.

לכן, אם למקד את הדיון, השאלה המרכזית היא למה צריך ללמוד מתמטיקה לבגרות? יותר ספציפית, למה צריך ללמוד דווקא 5 יחידות מתמטיקה לבגרות ולא לקחת את המינימום ההכרחי? השאלות הללו הן תמיד במרכז דיונים סוערים (יחסית, יחסית) ובזמן האחרון במיוחד.

אני אנסה לתת כמה תשובות אפשריות. השאלה המרכזית היא עד כמה המתכונת הנוכחית של לימודי המתמטיקה אכן תואמת את התשובות הללו, והאם אפשר לשנות אותה בצורה שתתאים יותר.

הסיבה הראשונה היא שמתמטיקה חשובה ללימודים ריאליים. ובגרסה קיצוניות יותר, שמתמטיקה הכרחית לשכר גבוה בתעשייה (עד כדי הבאת קורלציות – שמעידות או לא מעידות על גרירה, זה לא הדיון כאן – בין הציון במתמטיקה ובין השכר העתידי, שמביאות לטענות כמו "עדיף לקבל 60 בחמש יחידות מאשר 100 בארבע יחידות"). הסיבה הזו, כמובן, לא אומרת כלום למי שלא רואים את המשך הקריירה ותחומי העניין שלהם בתחומים ריאליים. אבל כמה היא רלוונטית למי שהולכים ללימודים ריאליים? כל מי שלמד חדו"א באוניברסיטה יכול להעיד על כך שחדו"א של תיכון לא ממש דומה. מצד שני, יש כל מני דברים שהמרצים באוניברסיטה יניחו שהסטודנט כבר יודע, למשל נוסחאות טריגונומטריות (שמשתמשים בהן לעתים רחוקות יחסית, אבל משתמשים). אין ספק שאם מבטלים עכשיו חלקים מהבגרות במתמטיקה, זה יכריח את האוניברסיטאות לשנות קצת את הגישה לסטודנטים, ואולי להציע קורס מבוא למתמטיקה (המצב לא שונה עד כדי כך בפועל גם היום; האוניברסיטה הפתוחה מציעה קורס "אשנב למתמטיקה" ובאוניברסיטאות פועלות מכינות שמטרתן בדיוק לתת ידע רלוונטי ברמה קדם-אוניברסיטאית).

אבל השאלה העיקרית כאן, מבחינתי, היא האם שינוי אופי לימודי המתמטיקה כך שיהיה קרוב יותר למה שאני מבין כמתמטיקה "אמיתית" ופחות טכנית יפגע במטרה הזו? מצד אחד, הרמה הטכנית של התלמידים כנראה תהיה פחותה; מצד שני, לא ברור עד כמה השליטה הטכנית הזו חשובה בלימודים האוניברסיטאים; דווקא היכרות עם נושאים נראית לי יותר רלוונטית מאשר ביצוע חישובים סבוכים. מכל מקום, ברור שזה מזמין דיון יותר פרטני שיכנס לפרטים המלוכלכים של חומר הלימודים התיכוני ומה שעושים באוניברסיטה. אני חושב שכולנו נסכים שבשל החשיבות של המתמטיקה בלימודים ריאליים, הרי שמתמטיקה היא בהחלט מקצוע שצריכה להיות בו בגרות, אבל לאו דווקא בגרות חובה. המציאות בפועל של שלוש-ארבע-חמש יחידות כבר מכירה בכך, אבל היא לא הולכת עד הסוף ועדיין מכריחה אנשים לא ריאליים ללמוד ברמת שלוש יחידות. וזה אומר גאומטריה אנליטית וטריגו וחדו"א ברמה כלשהי ואלו, חברים, לא תחומים קלים. אל תתנו למתנשאים על שלוש יחידות לשקר לכם. גם שלוש יחידות מתמטיקה זה לא ממש קל.

סיבה אחרת, ונפוצה למדי, ללימודי מתמטיקה היא שמתמטיקה היא משהו שכל בן תרבות צריך לדעת. חלק מהידע הבסיסי שבית הספר צריך להקנות. לדעתי זה בוודאי נכון עד למתמטיקה התיכונית, וכבר אמרתי זאת קודם; אבל מה עם החומר לבגרות?

בגרויות החובה בישראל הן באזרחות, אנגלית, היסטוריה, לשון, מתמטיקה, ספרות ותנ"ך. שימו לב לכך שהמתמטיקה במיעוט – מלבד אולי לשון, שהיא תחום שקשה לסווג אותו בצורה פשוטה, אין בגרות בשום תחום ריאלי או מדעי. פיזיקה, כימיה, ביולוגיה, מדעי המחשב (ואחרים שאני משמיט) כולם מקצועות בחירה. אם נשמיט את המתמטיקה, נקבל שבגרויות החובה אינן כוללות שום דבר שקשור למדע. בעיני זה מצב בלתי נתפס. אני יכול להבין מדוע קריטי ללמוד לבגרות אזרחות ואנגלית, אבל בנוגע ליתר הבגרויות אני לא רואה הצדקה לכך שהן יהיו חובה, אבל אף מקצוע מדעי לא. אפשר אולי לנהל דיון על ביטול חובת הבגרויות בכלל, אבל זה יהיה דיון רחב בהרבה מהדיון על המתמטיקה.

אולי נכון, אם כן, ללמד מקצוע מדעי אחר שאינו מתמטיקה? פיזיקה, גם ברמה תיכונית, נזקקת ללא מעט מתמטיקה; ביולוגיה וכימיה, פחות. מדעי המחשב מתחלקים לשני היבטים מרכזיים: פרקטיקה של תכנות, ותיאוריה. התיאוריה היא סוג של מתמטיקה (וסוג מעניין למדי) ואני חושב שללמוד תכנות נטו זה פספוס, כך שגם אם נמיר את המתמטיקה בפיזיקה או במדעי המחשב המשמעות תהיה שעדיין לומדים מתמטיקה ברמה כלשהי, פשוט מתמטיקה מסוג שונה. אם כן, אולי צריך להחליף אותה בכימיה או ביולוגיה? אלו תחומים שאיני בקיא בהם מספיק לצורך דיון רציני בעניין, בפרט לא ברמה שבה הם נלמדים בתיכון. אולי דווקא כדאי לעשות זאת. עם זאת, לא ראיתי הצעה כזו בשום מקום בפולמוס המתמטיקה כך שלא אכנס גם לעובי הקורה שלה.

אם כן, אם אנחנו כבר יוצאים מנקודת הנחה שיש איזה שהוא סט בסיס של "דברים שכל בן תרבות צריך לדעת", אני רוצה שהמתמטיקה תיכנס לשם. לא מסכימים? הייתי מעדיף שתתקפו את הרעיון של סט בסיס כזה מלכתחילה. עוד נחזור לזה אחר כך, כשנדבר על התנגדויות ללימוד מתמטיקה.

מבין הסיבות הנפוצות, המעורפלת ביותר לטעמי היא זו: המתמטיקה מחדדת את המחשבה. זו הרי אמירה מעורפלת לחלוטין. מה זה בכלל אומר, לחדד את המחשבה? אפשר למדוד את זה? אפשר להשוות את זה לחידוד של תחומים אחרים? להכיר את נפתולי מלחמת העולם השניה לא מחדד את המחשבה? להבין את המבנה של השפה העברית? להכיר ניתוחים של התנ"ך? ומה, לא שמענו אינסוף פעמים את טיעוני "מחדד את המחשבה" בהקשר ללימודים תורניים, כתירוץ להתנגדות ללימודי הליבה? מה זה הטיעון הזה?

אם כן, דבר ראשון שצריך לעשות הוא לקחת מהמתמטיקה את המונופול שלה כמחדדת מחשבה. לימודים מרוב הסוגים מחדדים את המחשבה, זו חלק מהפואנטה בלימוד, כל עוד הוא נעשה נכון. אפשר אולי לומר שהיא מחדדת את המחשבה בכיוונים מסויימים שתחומי לימוד "הומניים" יותר לא, אבל צריך להיות זהירים גם כאן. אני מוכן לקבל לגמרי את הטענה שמתמטיקה תיכונית מחדדת את המחשבה, ושמתמטיקה ברמה גבוהה יותר מחדדת את המחשבה, אבל אני חושב שאלו שני חידודים שונים לגמרי. אני חושב שהמתמטיקה התיכונית עושה משהו הרבה פחות מוצלח מאשר מתמטיקה "אמיתית". כך שגם אם מדברים על חידוד המחשבה, זה לא מצדיק את לימודי המתמטיקה במתכונתם הנוכחית, אלא אולי דווקא מדגיש את הצורך בחידוד נושאי הלימוד. וזה לא מצדיק מתן עדיפות למתמטיקה על פני מקצועות אחרים.

מדוע לא ללמד מתמטיקה?

אם כן, אני חושב שהנימוקים בעד מתמטיקה טרום-תיכונית הם טובים אבל שהנימוקים בעד מתמטיקה לבגרות הם לא חזקים יותר מאשר עבור אף מקצוע אחר. אבל מה עם נימוקים נגד המתמטיקה? ובכן, כאלו אנחנו מקבלים שוב ושוב; רוב המאמרים שיצא לי לקרוא הנוגעים לפולמוס המתמטיקה הם חד משמעית נגדה, לעתים עד כדי דמוניזציה גמורה. שוב, התקציר של דעתי על כלל המאמרים הללו הוא פשוט: הם שופכים את התינוק עם המים. הרי בבירור יש בעיה קשה מאוד עם לימודי המתמטיקה בבית הספר, והם נוקטים בפתרון הפשוט והעצלני של "אז בואו לא נלמד מתמטיקה!" וחסל, במקום לשאול את השאלות החשובות יותר – האם אפשר לשנות את חומר הלימוד? האם יש כאן בעיה שנוצרת בשל מורים לא טובים? שיטות הוראה לא מספיק טובות? מחסור בעזרים חיצוניים? התמקדות מופרזת בתרגול? יצירת תדמית שגויה בציבור? וכו' וכו' וכו'. על כל השאלות הללו אפשר לכתוב פוסט נפרד, וגם את זה אולי אעשה. בינתיים בואו ננסה לראות כמה דוגמאות למאמרים אנטי-מתמטיים.

לפני שנתחיל, אני רוצה לסנגר עליהם קצת, כי אחר כך אתרגז עליהם מאוד. המאמרים הללו לא מגיעים מאנשים עצלנים או טיפשים בשום צורה. הם מגיעים משילוב של שתי בעיות – האחת, המתמטיקה הבית ספרית כפי שהיא נלמדת כרגע היא קשה ומייאשת עבור תלמידים רבים; השניה, המתמטיקה מצויירת ביותר מדי מקומות בתור "כרטיס כניסה" לחיים, מה שגורם לאנשים לחוש צורך לציין שהיי, אפשר להיות בן אדם מתפקד ומועיל לחברה גם בלי מתמטיקה (מפתיע!). אלו שתי בעיות רציניות, ולרוב יוצא שהמאמרים מבקרים אותן, אבל זה איכשהו מתערבב בביקורת כללית על המתמטיקה (שבחלק מהמקרים הכותבים כנראה לא מכירים בכלל).

הטיעון הנפוץ ביותר הוא שלימודי מתמטיקה פוגעים בתלמידים בצורה שהיא כנראה קיצונית יותר מכל תחום אחר. הנה מאמר של נועה אסטרייכר שעוסק בסבל הפרטי שלה מלימודי המתמטיקה. זה מתחיל ב"הפסקתי להבין חשבון קצת אחרי שסיימנו ללמוד את לוח הכפל…אולי הוראה מתקנת או תשומת לב נוספת לילדה שנשרכת מאחור היו עוזרות לי לעלות שוב על השביל, אבל במקומם נתקלתי בחומה של בוז: חשבון זה קל, ומי שלא מבין אותו – הוא כנראה טיפש מכדי שיעכבו לכבודו את שאר הכיתה." ונמשך ב"למרות ההצלחה שלי במקצועות רבים בתיכון, המסר שקיבלתי היה ברור – את לא שווה כלום בלי מתמטיקה" ועובר לקריאה לביטול הבגרות "כאשר הדבר הכרחי לשימור וטיפוח יכולותיו האחרות של התלמיד, במקום להשמיד אותן תחת מכבש הלחצים המתמטי אשר לא מועיל בדבר" (ומסיים ב"די לטרור המתמטי"). והנה מאמר אחר, של רוחמה אלבג, שמתחיל בקריאה לבטל את הבגרות, מדבר על "החרדה המתלווה לבחינה, התסכול והאימה", ועובר לחוויה האישית של "שיעורי המתמטיקה עיקרו את נפשי. כמעט עזבתי את התיכון, ולא הייתי היחידה". במאמר אחר, של שלומי ברזל, הוא מדבר על "התחום הדמוני הזה נקרא עדיין חשבון. מתלווה אליו כמובן אחותו המפלצתית הנדסה, שבעוד שנה בערך תתהדר בשם המבעית גיאומטריה.". ורינת פרימו, בביקורת על "איך בוטלה המתמטיקה" של אביעד קליינברג אומרת ש"המתמטיקה הרסה והורסת להמון ילדים את החיים". במאמר אחר, אומרת אור סגל ש"בשיעור מתמטיקה הראשון השנה, המורה הודיעה שכדי להצליח בחמש יחידות צריך "לאפסן את החיים בקופסה"". במאמר אחר כותבת ספיר ליפקין ש"לגרום לתלמידים שלא ניחנו בגישה למתמטיקה להזיע מעל דפי התרגול ולבזבז שעות מזמנם בסבל במקום לעודד אותם להתפתח בתחומים שהם מוכשרים בהם זו פשוט התעללות".

הבנתם את העניין. בכל המקרים הללו הכותבים מדברים בעיקר מתוך החוויה האישית השלילית שלהם, אבל אני חושב שהחוויה הזו אכן מתארת את התחושה של רבים מאלו שמתמודדים עם מתמטיקה בית ספרית. אפשר להגיד שזה המצב ביחס לכל מקצוע בית ספרי, אבל זה לא נכון; אנחנו לא באמת רואים כל כך הרבה מאמרים שמתלוננים על ספרות בצורה שכזו, למשל. ואני באמת, באמת רוצה להבין למה. מה הופך את המתמטיקה לכל כך מפלצתית. עזבו אתכם לרגע מהאופן שבו מפמפמים את החשיבות של המתמטיקה ובחלק מהמאמרים שקישרתי אליהם מתלוננים עליה – למה זה כל כך נורא לתלמידים?

הבלוג הזה מיועד בעיקר לאנשים בעלי ידע כלשהו במתמטיקה על-תיכונית, גם כדי לעזור להם להבין נושאים שהם מתמודדים איתם כרגע, וגם כדי להכיר להם נושאים חדשים. אבל מדי פעם אני כותב פוסט שיש לי תקווה שיהיה מובן גם לאנשים בלי רקע במתמטיקה או נטיה מתמטית. בחלק מהמאמרים שקישרתי אליהם מדברים על כך שאין לכל האנשים "ראש ריאלי" או "חשיבה מתמטית" או מה שזה לא יהיה שמאפשר לאדם להתמודד עם מתמטיקה תיכונית. האם זה אומר שהוא לא יוכל להבין דברים כמו מונטי הול, או את גניבת האסטרטגיה של צ'ומפ, או את חישוב שטח המשולש שהראיתי קודם, או אפילו את המלון של הילברט? קראו לי נאיבי, אבל אני מאמין שאת הדברים הללו יכול להבין גם אדם שמעיד על עצמו שאין לו "ראש מתמטי" כלל. אני מאמין שלרובנו (למעט מקרים קיצוניים באמת) יש יכולת בסיסית להבין רעיונות מתמטיים ואולי אפילו לעשות איתם דברים. זה לאו דווקא כיף לנו ולאו דווקא מעניין, אבל היכולת קיימת. השאלה היא האם היא רלוונטית למה שעושים בבית הספר, או שבבית הספר עושים משהו מאוד ספציפי, שדורש דרישות אחרות מאשר דורשת מתמטיקה "אמיתית" והדרישות הללו הן אכן תובעניות מדי עבור אנשים רבים. הניחוש שלי הוא שהתשובה חיובית. לכן אני חושב שהביקורת של "תשאירו את המתמטיקה רק לאנשים שיש להם את הראש לזה" מפספסת. לפני שזורקים את המתמטיקה לפח צריך לחשוב האם היא חייבת להילמד במתכונת שמוציאה החוצה כל כך הרבה אנשים.

וכל זה, בלי שניכנס בכלל לשאלה האם הבעיה אכן טמונה בכך שאין לאנשים "ראש מתמטי" או במה שהזכרתי קודם – בכך שמתמטיקה היא מקצוע שכל כך קל לאבד אותו בלי סיכוי לחזור לעניינים, ואולי רק אנשים עם "ראש מתמטי" מסוגלים. או לחילופין, מורה פרטי טוב (אבל אני בספק אם מורה פרטי יוכל לסייע בכיתה י' למישהו שאיבד את זה בכיתה ד').

טיעון אחר בעד ביטול חובת המתמטיקה הוא ש"הטובים" ממילא יגיעו למתמטיקה. אפשר לראות אותו, למשל, במאמר של גיל גרטל: "כשם שהמתאימים לטיס מוצאים את דרכם להיות טייסים מעולים גם ללא שהיו בהקבצה א' לטיס בבית הספר היסודי, כך ימצאו לנו המתמטיקאים הדגולים, שיטיסו את האנושות קדימה". זה טיעון בעייתי משתי סיבות. ראשית, וזו גם מטרת הקמפיין הנוכחי בעד עידוד הלמידה בחמש יחידות מתמטיקה, אנחנו לא רוצים רק את "הטובים". אין מספיק "הטובים". אנחנו צריכים הרבה יותר אנשים, גם כאלו שלא יצליחו למצוא את דרכם לבד. שנית, וחשוב יותר, אם אדם כלל לא נחשף למתמטיקה – כלל לא מבין שהתחום קיים, או אם הוא מקבל עליו רושם שגוי לחלוטין – הסבירות שילך אליו תקטן. טיעון דומה קיים גם בספרות, ושם הוא חזק אף יותר – מבלי להיחשף למגוון רחב של יצירות וז'אנרים, איך התלמיד ידע עצמאית מה לחפש? הוא אפילו לא ידע שמשהו חסר לו. אנחנו יכולים אולי להגיד שוב ושוב לתלמיד שמתמטיקה זה מגניב (אבל בפועל מי אומר את זה? טוב, הבלוג הזה מנסה לומר את זה, ואני מקווה שמצליח, אבל קשה לומר שהוא מייצג את החברה) אבל האם זו חשיפה מספקת למתמטיקה?

כמובן, כלל לא ברור שתוכנית הלימודים הנוכחית במתמטיקה מספקת את החשיפה הנכונה; זו עוד המחשה לכך שמה שאמור היה להיות ביקורת (טובה) על תוכן הוראת המתמטיקה הפך לביקורת על עצם לימוד המתמטיקה.

טיעון דומה, ונפוץ ביותר, הוא שרוב התלמידים לא צריכים מתמטיקה. בלשונו של גרטל, "מתמטיקה כמו כל תחום אחר, צריכה להילמד בבית הספר עד רמת הצורך של הלומדים. אצל הרוב המכריע של הילדים מסופק צורך זה במהלך בית הספר היסודי, ואין צורך שמתמטיקה תהייה המקצוע הכי חשוב במערכת החינוך, כמקצוע חובה מעבר לחטיבת הביניים. כמה מאזרחי ישראל חפפו לאחרונה משולשים, חקרו פונקציה ופתרו משוואות דיפרנציאליות? התשובה ברורה, אחוזים בודדים בלבד." (אגב, אני לא חפפתי משולשים וחקרתי פונקציות מאז התיכון, ומשוואות דיפרנציאליות פתרתי רק בקורס העוסק בכך).

זו בדיוק גישת "המתמטיקה היא ארגז כלים" שהתרעמתי עליה בהתחלה. אפשר להחיל את התלונות הללו על כל מקצוע חובה לבגרות למעט אזרחות ואנגלית (שכן באנגלית רובנו המכריע משתמשים ביום יום, ובאזרחות אנחנו אמורים להשתמש, גם אם איננו עושים זאת). האם הכרת הסיבות לעליה השניה מסייעת לנו ביום יום, למעט בויכוחים אינטרנטיים (ותאמינו לי, גם ידע מתמטי יסייע לכם בויכוחים אינטרנטיים, אתם רק צריכים למצוא את המקום הנכון להתווכח בו)? ודין שור שנגח? והכניסי תחת כנפך? והיכרות עם בג"ד כפ"ת (אלא אם אתם מהאנשים המוזרים שרוצים לכתוב ולדבר בצורה תקנית בעברית, וזה חריג בדיוק כמו חובבי המתמטיקה)? הבנתם את הרעיון. שימושיות היא לא מדד טוב למקצועות החובה לבגרות, בטח לא שימושיות של חומר לימוד ספציפי כמו חפיפת משולשים. אם רוצים לתת טיעון בעד השימושיות, לרוב הוא יהיה משהו אמורפי יותר, איזו סגולה טמירה שלימודים הומניים מחדירים בתלמידים אבל לימודי מתמטיקה לא – מין הפוך-על-הפוך של טיעון "מחדד המחשבה" המתמטי (זה לא כל כך מפתיע שיש לטיעונים בעד טיעוני מראה שהם נגד). במאמר של אלבג נאמר "ישבתי וקראתי בספריה ועולמי נפתח – ויתרתי על חישוב קודקודים והתוודעתי לגיבוריה האלמותיים של האנושות. התמסרתי למחשבות, לרעיונות, לעולם רוחני שהיה מתוק פי כמה ממשוואה עם נעלם אחד או שניים או כמה יש שם, לעזאזל?".

אם כן, מדוע מודדים את ה"שימושיות" בצורה שונה שכזו? האם בגלל שכל מה שלומדים בבית הספר לא מתחבר ולא יכול להתחבר לתמונה גדולה כלשהי?

אז מה צריך לעשות?

הפתרון הקל מבחינתי הוא לומר "לבטל את חובת הבגרות במתמטיקה ולהשאיר רק מתמטיקה חמש יחידות בתור מקצוע בחירה". זה יציל את כל שונאי המתמטיקה מלסבול בגללה בתיכון ולהרגיש שהם חסרי ערך כי אין להם בגרות במתמטיקה (ולכן אין להם בגרות בכלל). האם זה באמת פתרון? זה לא ישנה את מעמדן (המוצדק או לא) של חמש יחידות מתמטיקה בתור "כרטיס כניסה" לחיים, או לפחות למעמד סוציואקונומי מסויים. האוניברסיטאות ימשיכו לתת בונוס לספי הכניסה לפקולטות מסויימות עבור מי שיש לו בגרות במתמטיקה (ובצדק, מבחינתן). מי שהיו ניגשים לשלוש יחידות בגרות כנראה יוותרו ברובם על המקצוע, וככל הנראה יהיה להם קשה להשלים אותו אחר כך אם יצטרכו; והאחרים יעברו למה שהיום הוא חמש יחידות ויהיה להם קשה שם. בקיצור, קשה.

אתגר אחר הוא להפוך את לימודי המתמטיקה התיכונית ליותר נגישים, למשהו שרוב התלמידים יכולים להתמודד איתו בלי טראומה. יש כאן שני דברים לפחות שיהיה צורך לטפל בהם: הראשון הוא חומר הלימוד של המתמטיקה התיכונית עצמה, אבל השני הוא החשוב יותר לדעתי – יהיה הכרחי להבטיח שתלמידים לא מגיעים לתיכון כשהם כבר "שרופים" מבחינת המתמטיקה ולא מסוגלים להתמודד עם איזה חומר שלא יהיה שנזרוק עליהם. כפי שאמרתי קודם, שריפה כזו יכולה לקרות בכל שלב, בגלל תלמידים שמאבדים את החומר לרגע ואז לא מצליחים להשלים אותו יותר. איך פותרים את זה?

התשובה הראשונה היא "מורים טובים". אין ממש מה לעשות בנוגע לכך – מורים טובים הם הדבר החשוב ביותר במערכת החינוך. גם תוכנית הלימודים הטובה ביותר כנראה לא תעבוד אם המורה שמעביר אותה עושה את זה רע. אבל אין מה לעשות, לא תמיד יהיו מורים טובים – מבחינתי זו הנחת יסוד. לכן צריך לדאוג לתלמידים ל"רשת ביטחון" כלשהי. דרך כלשהי לסייע להם ללמוד מתמטיקה בלי להיות תלויים במורה זה או אחר. מה שכיום מושג על ידי מורה פרטי עבור חלק מהתלמידים, ספציפית כאלו שהוריהם יכולים להרשות דבר כזה; זה בדיוק האפקט שאנחנו לא רוצים, אלא משהו שיעבוד "לכולם". ספרים ולומדות ממוחשבות לעבודה עצמית נשמעים כמו דבר סביר, אבל איך מכריחים את התלמידים לעשות אותם? זה עדיין ידרוש פיקוח מצד בית הספר. הייתי רוצה לומר שאפשר לגרום לתלמידים להתעניין באופן עצמאי, אבל האם אפשר לעשות כזה דבר בכלל? הנה לכם אתגר: האם אפשר לגרום לתלמידים בגילאי יסודי-חטיבת ביניים להתעניין במתמטיקה שהם לומדים? אני לא יודע; עבורי הגילאים הללו הם חור שחור. הבלוג משמש, לשמחתי, בתור "רשת הצלה" עבור סטודנטים באוניברסיטה בקורסים מסויימים (למרות שהוא לא נועד להחליף ספרי לימוד, אבל בתור חומר משלים שמיועד לשפר את ההבנה אני שמח לומר שהוא עובד, לפעמים, בתחומים מסויימים; אם אני גאה במשהו, זה בכך). אבל כתיבה עבור סטודנטים באוניברסיטה היא קלה; ילדים הם אתגר גדול בכמה סדרי גודל, למרות שהמתמטיקה היא לכאורה פשוטה יותר. מי שכבר הרים את הכפפה היה פרופ' רון אהרוני מהטכניון, שכתב ספרי "חשבון להורים" ו"אלגברה להורים" שמאפשרים להורים עצמם להיות רשת ביטחון עבור הילד. הספרים הללו היו הצלחה יחסית; ייתכן מאוד שזה בדיוק הכיוון שבו צריך ללכת. כיוון אחר הוא לומדה ממוחשבת – בימינו זה יהיה אתר אינטרנט (בתקווה נגיע יום אחד לכך שלכל התלמידים יש גישה לאינטרנט, לכל הפחות מבית הספר), משהו בסגנון Khan Academy אולי? צריך שיהיו בו סרטונים, ומלל כתוב, ותרגילים אינטראקטיביים. וכמובן, בעברית ומתאים לישראל. ורצוי שיהיה כיפי ומעניין. כל זה אפשרי, בתיאוריה; בפועל מישהו צריך להרים את זה ולקדם את זה ולהפוך את זה לסטנדרט.

וכן. אולי צריך לשנות גם את תוכנית הלימודים. אבל כשבאים להציע הצעות כאלו, אנחנו מתנהגים כמו פיל בחנות חרסינה. יש סיבות למה דברים נמצאים בתוכנית הלימודים, ואנחנו לרוב מציעים גזור-העתק-הדבק גסים שלא מודעים לסיבות הללו. זה לא אומר שלא עושים את זה – השמועות שאני שומע הן שתוכנית הלימודים בישראל אכן הולכת לקראת שינוי כלשהו.

אם בכל זאת הייתי נותן דרור לדמיון ומעלים עין מההשלכות, נראה לי שהדבר הראשון שהייתי חושב לשנות הוא את לימודי החדו"א בבתי הספר. כרגע החומר נלמד ברמה מאוד נמוכה ומאוד טכנית, ואני לא בטוח עד כמה זה הכרחי אפילו בתור הכנה לאוניברסיטה. האם ניתן ללמד חדו"א בצורה יותר רצינית, עם יותר דגש על הבנה של המושגים (הקשים) שבבסיסו, מבלי להגדיל את הקושי הטכני? שאלה טובה.

תחומים נוספים שלדעתי צריך לשנות, אולי לקצץ, הם גאומטריה אוקלידית וטריגונומטריה – שניהם חשובים מאוד, אבל מסיבות שונות. טריגונומטריה היא כלי טכני בסיסי שמשתמשים בו בכל תחומי המתמטיקה, אבל הוא גם דוגמה קלאסית לסיפור רהיט האיקאה שהבאתי קודם – בתיכון לא ממש עושים בו שימוש אלא רק מתאמנים על לסובב שוב ושוב ושוב את המברג, עם שלל נוסחאות מפחידות למראה שלאף אחד לא ברור מאיפה הן הגיעו. גאומטריה אוקלידית היא סיפור שונה לגמרי כי היא אולי התחום היחיד שדורש יצירתיות כלשהי, ומלמד את התלמידים איך נראית הוכחה מתמטית אמיתית, ואלו דברים חשובים ביותר – אבל אלו דברים שלטעמי צריך לראות בתחומים רבים יותר, ומתישהו הגאומטריה ממצה את האפקט הזה שלה ואנחנו נשארים שוב עם ערימה גדולה של משפטים שצריך להכיר ולא יהיו שימושיים יותר מדי לשום דבר בהמשך.

והאם צריך להוסיף משהו? יש שני תחומים שקופצים לי מיידית לראש – תורת הקבוצות, וחשבון מודולרי. בשני המקרים צריך להיות מאוד זהירים – אם מלמדים את תורת הקבוצות צריך להיות מאוד קונקרטיים ולחלוטין לא להציג אותה בתור "הבסיס למתמטיקה" או כל מני דברים דומים שאין בהם שום טעם בשלב הזה. עדיין, אני מאמין שאפשר להסביר מושג כמו יחס שקילות כבר בתיכון (בפרט אם לומדים חשבון מודולרי, שם הוא צץ מעצמו), ואפשר אפילו להסביר את האלכסון של קנטור. האם גם אפשר לבחון על הנושאים הללו? שאלה קשה יותר. בחשבון מודולרי אני מאמין שאפשר להסביר נושאים כמו האלגוריתם האוקלידי ומשפט השאריות הסיני ואולי אפילו להגיע לתיאור משהו כמו RSA. האם התחושה שלי מבוססת? קשה לי לדעת. כבר שמעתי סיפורי זוועות על נסיונות ללמד את תורת הקבוצות בבתי הספר וכשלונות חרוצים של הנסיון הזה, אבל האם זה נבע מאופי ספציפי של אופן הלימוד, או מכך שתורת הקבוצות היא חומר "בלתי נגיש" לתלמידי תיכון? לא יודע. זה מצדיק דיון רציני שעומד בפני עצמו; כרגע אני סתם זורק רעיונות.

הפוסט הזה, כאמור, אמור לשמש בתור נקודת התחלה, לא סיום. אני מתאר את המצב כפי שאני מבין אותו – ואני מבין היטב שאני לא באמת מבין אותו. האם ניתן להשתמש בנקודת ההתחלה הזו כדי להגיע אל משהו? תגידו לי אתם.

האם גוגולפלקס הוא הסמל של סוף המספרים? (לא)

לפני מספר ימים נתקלתי בספר בשם "מתמטיקסם" של יעל רוטנברג. למי שרוצים להתרשם ממנו, הנה לינק לצילומי מסך ממנו בעמוד הפייסבוק של הספריה הלאומית. כפי שניתן לראות שם, וכפי שגם אני התרשמתי בעלעול שלי, מדובר על ספר נחמד מאוד שמציג דברים יפים במתמטיקה עבור ילדים, ובאופן כללי עושה את זה היטב. זו הסיבה שבגללה כל כך הזדעזעתי (לא באמת הזדעזעתי, אין צורך לדבר על כך בתגובות) כשהגעתי לדף שכותרתו "גוגולפלקס – הסמל של סוף המספרים".

כבר הכותרת מעלה דאגות, עבור מי שמכיר את המושגים, והטקסט הוא אכן בעייתי מאוד, ברמה שאני אוהב לכנות Not even wrong (בפרפראזה לא מדויקת על הציטוט הידוע של פאולי). אצטט אותו, ואז אסביר מה הבעיות שם. כרגיל, המטרה של הפוסט הזה היא לא (רק) להגיד "מה לא" אלא גם להגיד "מה כן", וכאן יש נושא מעניין למדי שאפשר לדבר עליו. למען הסר ספק – אני לא רוצה שיתקבל מהפוסט הזה הרושם שלא כדאי להורים לקנות לילדיהם את הספר; מהתרשמותי ממנו אני חושב שבהחלט כדאי שהם יקנו את הספר; רק שיקפידו לתלוש את הדף על גוגולפלקס.

מה שהולך שם הוא דיאלוג בין שני דוברים, אחד כתוב באדום ואחד בכחול; אני אקרא להם אליס ובוב. והנה הוא:

אליס: מי יודע מהו המספר האחרון?

בוב: אני יודע: מיליארד!

אליס: מה פתאום? בכלל לא! תמיד אפשר לספר מיליארד ואחת, מיליארד ושתים, מיליארד ושלוש, מיליארד וארבע… ככה בלי סוף.

בוב: אז אולי טריליון?

אליס: לא נכון! הרי שוב: תמיד אפשר לספר טריליון ואחת, טריליון ושתים, טריליון ושלוש, טריליון וארבע…

בוב: אה… רגע… אז בעצם אין סוף למספרים, כי לכל מספר אפשר להוסיף עוד מספרים, שיגדילו אותו…

אליס: אתה צודק. באמת אין סוף למספרים!

בוב: אז למה קודם שאלת מהו המספר האחרון? הרי אין כזה דבר – "המספר האחרון"!

אליס: נכון, אין כזה דבר "המספר האחרון". הוא לא קיים. אבל יש לו כינוי.

בוב: ומה הכינוי הזה?

אליס: "גוגולפלקס"

בוב: גוגולפלקס? חה-חה-חה! איזה כינוי מצחיק!

אליס: הנה, ככה הוא נראה:

10,000,000,000,000,000,000,0

00,000,000,000,000,000,000,0

00,000,000,000,000,000,000,0

00,000,000,000,000,000

בוב: וואי וואי וואי… מה זה?

אליס: זה המספר 10 ואחריו מאה אפסים… זה גוגולפלקס.

בוב: אז בכל פעם שארצה לכתוב "גוגולפלקס" אצטרך לציר מאה אפסים? זה מאוד קשה!

אליס: אכן זה מאוד קשה. לכן במקום זה אפשר לכתוב עשר בחזקת מאה, כך: \(10^{100}\).

בוב: אני עדיין לא מבין איך אפשר לתת שם למשהו שלא קים. חוץ מזה, כיצד ייתכן שגוגולפלקס הוא המספר האחרון? הרי אחריו בא גוגולפלקס ואחת, גוגולפלקס ושתים, גוגולפלקס ושלוש, כמו שהסברת לי קודם…

אליס: הבן: גוגולפלקס אינו מספר; הוא סמל. אכן, לכל מספר אפשר להוסיף עוד מספרים, אבל לסמל הזה, גוגולפלקס, אי אפשר להוסיף עוד מספרים. לכן אין גוגולפלקס ואחת! הבנת?

בוב: אני חושב שכן, אבל תגידי לי: יש כזה דבר – גוגולפלקס ואחת, גוגולפלקס ושתיים, גוגולפלקס ושלוש?

זהו, כאן זה נגמר. מרגיש לכם קטוע? גם לי. ההשערה שלי היא שכל הטקסט היה טיוטא שהתפרסמה בטעות; וטיוטא שעירבבה בטעות שני נושאים לחלוטין לא קשורים. אחד מהם הוא המספר גוגולפלקס, והשני הוא השאלה האם קיים סוף למספרים. בטיפול בכל אחד מהנושאים נפלו טעויות, אבל הטעויות שקשורות לגוגולפלקס הן שוליות, בעוד הטעויות שקשורות לסוף המספרים… ובכן, אוי ואבוי.

נתחיל מגוגולפלקס. בטקסט זה השם שנותנים בטעות למספר גוגול, שהוא \(10^{100}\), כלומר 1 ואז מאה אפסים אחרי (ולא 10 ואז מאה אפסים אחריו כפי שאומרים בטעות בטקסט). את השם "גוגול" המציא ילד בן 9, מילטון סירוטה, בשיחה עם דודו המתמטיקאי אדוארד קסנר. אין לגוגול חשיבות מיוחדת במתמטיקה או פיזיקה (הוא "עגול" מדי ומתאים מדי לבסיס 10 בשביל להיות משהו שצץ באופן טבעי כמו \(e\) או \(\pi\)) והמטרה שלו היא פופולריזציה שלה אצל ילדים, ואת זה הוא עושה נפלא כי זה מספר מעניין עם שם מוצלח. וכן, כמובן שהדמיון לשמה של חברת גוגל אינו מקרי – גוגל היא שיבוש (בטעות, אם איני טועה) של גוגול.

ומה הוא גוגולפלקס? מילטון המציא גם אותו, בתור "1 ואז לכתוב אפסים עד שאתה מתעייף". קסנר הלך על הגדרה קצת יותר פורמלית (שמגדירה מספר הרבה, הרבה יותר גדול מאשר זה של מילטון): 10 בחזקת גוגול, כלומר \(10^{\left(10^{100}\right)}\). אם גוגול הוא אדיר ממדים, גוגולפלקס הוא אדיר ברמות שלא יאומנו. את גוגול כתבתי במלואו למעלה; את גוגולפלקס לא יהיה ניתן לכתוב גם אם כל היקום הידוע יהיה הנייר שלנו.

גוגול תואר בצורה נפלאה ב"אני שונא מתמטיקה" של מרילין ברנס, שהוא הספר הראשון שגרם לי, כילד קטן, להתעניין במתמטיקה; הנה מה שהולך בגרסה העברית:

googol1 googol2

ככה עושים את זה נכון.

וחזרה למתמטיקסם – מה הקשר בין גוגול, או גוגולפלקס, ו"סוף המספרים"? אין שום קשר! אני ממש לא מבין מה גוגולפלקס עושה שם בכלל. אבל זו לא הבעיה העיקרית. הבעיה העיקרית היא שהספר עושה מיש-מש אחד גדול מכל שאלת סוף המספרים.

ההתחלה דווקא טובה – הדיון של אליס ובוב נוגע בדיוק בלב העניין. לא משנה איזה מספר ניקח בתור מועמד להיות "המספר האחרון", תמיד אפשר להוסיף לו 1 והתוצאה תהיה מספר גדול יותר. זו הדרך לשכנע ילדים שאין מספר גדול ביותר. אבל אחרי השלב הזה בדיאלוג, אנחנו פתאום לומדים כל מני דברים:

  1. שבמתמטיקה יש דברים שלא קיימים אבל יש להם כינוי.
  2. שמספר שלא קיים יכול להיכתב בצורה קונקרטית בתור מספר אמיתי (\(10^{100}\)).
  3. שיש הבדל בין "מספר" ובין "סמל", ולסמל "אי אפשר להוסיף" מספרים (כלומר, \(10^{100}+1\) אינו מספר?)

גם סגנון הכתיבה פתאום הופך להיות פסקני ומעיק. מה זה ה"הבן" הזה? מי מדבר ככה? ומה זו הנחרצות של "לסמל הזה אי אפשר להוסיף עוד מספרים"? למה אי אפשר? איזו מין דרך זו להציג דברים במתמטיקה, לומר "אי אפשר כי אי אפשר וזהו"?

אני מנחש שמה שרצו לדבר עליו כאן במקור הוא \(\omega\). מה זה \(\omega\)? זה משהו שמכונה במתמטיקה מספר סודר. יש לי פוסטים על הפורמליזם של סודרים ולא אכנס אליו כאן. הרעיון האינטואיטיבי הוא שסודרים משמשים אותנו בשביל ספירה מסודרת, לא של כמות אלא של סדר: נאמר, בתור כלשהו יש את המקום הראשון, השני, השלישי, הרביעי וכן הלאה; המספרים הטבעיים משמשים אותנו כדי לתאר את הסדר של האיברים בתור. על כן, המספרים הטבעיים נקראים סודרים. השאלה היא רק האם יש משהו שמגיע "אחרי" כל המספרים הטבעיים – מספר כלשהו שגדול מכולם. התשובה היא שאין מספר טבעי שגדול מכל הטבעיים, כי אם \(n\) הוא מספר טבעי, גם \(n+1\) הוא מספר טבעי, אבל שאפשר לתת הגדרה כללית יותר למספרים סודרים, ובה נקבל שאכן, קיימים מספרים סודרים שגדולים מכל הטבעיים. למספר הסודר הקטן ביותר שמקיים את זה קוראים \(\omega\) (אומגה ביוונית). אם אתם תוהים איך אפשר לדעת שמשהו כמו אומגה קיים בכלל – הרעיון האינטואיטיבי הוא שכל סודר שווה לקבוצת כל הסודרים שקטנים ממנו, כך שאומגה הוא בסך הכל קבוצת המספרים הטבעיים; בפוסטים שקישרתי אליהם נכנסים אל העניין בצורה יותר מסודרת.

האם \(\omega\) הוא "הסוף של המספרים"? ובכן, לא; אפשר להוסיף גם לו 1! כלומר, \(\omega+1\) גם הוא סודר חוקי (פורמלית זו הקבוצה שכוללת את כל המספרים הטבעיים ואת \(\omega\)), וגם לסודר הזה אפשר להוסיף 1, וכן הלאה. למעשה, טריק ה"אפשר להוסיף 1" שגם ילדים ללא ידע במתמטיקה מסוגלים להבין הוא גם ההוכחה הפורמלית שאפשר לתת לכך שאין סודר גדול ביותר – אין ולא יהיה "מספר אחרון".

מה שנכון הוא שאפשר לחשוב על \(\omega\) בתור "סוף המספרים הטבעיים", במובן זה שכל המספרים הטבעיים קטנים מ-\(\omega\) ואין עוד מספרים סודרים בין \(\omega\) ובין הטבעיים. חשבו על \(\omega\) בתור מעין "קו גבול" שהוא בעצמו אינו מספר טבעי, והטבעיים הולכים ומתקרבים אליו אבל אף פעם אינם מגיעים אליו – הגבול הזה הוא ה"סוף" עבור המספרים הטבעיים. אבל זה שונה מהדיון על "המספר הטבעי האחרון" מכיוון ש-\(\omega\) אינו מספר טבעי, ולכן בוודאי שאינו המספר הטבעי האחרון; פשוט לא קיים מספר טבעי אחרון.

זו תחושת ההחמצה העיקרית שלי לגבי מה שהספר עשה – הייתה לו הזדמנות להציג את הרעיון הכל כך יפה ומגניב ונפלא הזה של \(\omega\), והוא לא עשה את זה. מילא שלא עשה את זה (נראה לי קשה להציג את \(\omega\) לילדים בצורה טובה) אבל מה שהוא עשה במקום זה…

אה, וגם לא ראיתי שמדברים בספר על המלון של הילברט. וזה באמת חבל.

אנליזה וקטורית – תכונות בסיסיות של הנגזרת

אז הכרנו את הנגזרת של פונקציה \(f:\mathbb{R}^{n}\to\mathbb{R}^{m}\) וראינו איך אפשר לחשב אותה באמצעות נגזרות חלקיות. בואו נעבור עכשיו לכמה תוצאות תיאורטיות כלליות וקלות יחסית, כדי שנתרגל; עד סוף הפוסט נגיע להצגת תוצאה לא טריוויאלית ושימושית – משפט הפונקציה ההפוכה. אבל נתחיל מהבסיס.

נתחיל בתכונה אחת שנובעת כמעט מייד מכך שפונקציה היא גזירה אבל טרם הראיתי זאת במפורש, והגיע הזמן כי נשתמש בה בהמשך: רציפות. נזכיר ש-\(f\) היא פונקציה רציפה ב-\(a\) אם \(\lim_{x\to a}f\left(x\right)=f\left(a\right)\) – או, באופן שקול, אם \(\lim_{h\to0}f\left(a+h\right)-f\left(a\right)=0\). זו תכונה מאוד מאוד מועילה במקרים רבים כי היא מבטיחה ש-\(f\) לא יכולה "להתפרע" יותר מדי כשמתקרבים לנקודה כלשהי. עכשיו, אם \(f\) גזירה ב-\(a\) היא גם רציפה שם. למה? כי נניח ש-\(\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)-Df\left(a\right)h}{\left|h\right|}=0\) ועכשיו ננסה לכתוב את \(\lim_{h\to0}f\left(a+h\right)-f\left(a\right)\) בעזרת הגבול ההוא:

\(\lim_{h\to0}f\left(a+h\right)-f\left(a\right)=\lim_{h\to0}\left|h\right|\left[\frac{f\left(a+h\right)-f\left(a\right)-Df\left(a\right)\cdot h}{\left|h\right|}\right]+Df\left(a\right)\cdot h\)

ומה קיבלנו פה? גבול שמערב כמה חלקים. ה-\(\left|h\right|\) שואף כמובן לאפס. ה-\(\left[\frac{f\left(a+h\right)-f\left(a\right)-Df\left(a\right)\cdot h}{\left|h\right|}\right]\) גם, כי הנחנו שהפונקציה גזירה. לכן כל המחובר השמאלי שואף לאפס. במחובר הימני אנחנו מקבלים מטריצה קבועה כפול וקטור ששואף לאפס – קל לראות שזה שואף לאפס (טפלו בכל רכיב בנפרד; זו פונקציה רציפה חד ממדית), וזה מסיים את ההוכחה.

עכשיו בואו נעבור לטפל בכללי גזירה שונים ומשונים. ככה זה עובד: הגדרנו פעולה של גזירה על פונקציות. מייד אנו תוהים – מה מניבה הגזירה עבור פונקציות פשוטות יחסית? כמו כן – על פונקציות מוגדרות כל מני פעולות – חיבור, כפל, הרכבה וכדומה. האם קל לדעת את הנגזרת של חיבור פונקציות, אם יודעים את הנגזרת של הפונקציות שמחברים?

פונקציה פשוטה במיוחד היא פונקציה קבועה: \(f\left(x\right)=c\) עבור \(c\in\mathbb{R}^{m}\) קבוע כלשהו. מכיוון שעבור פונקציה ממשית קבועה הנגזרת היא 0, נקבל כאן שהנגזרות החלקיות בכל מקום הן 0. אלו נגזרות חלקיות רציפות, ולכן \(f\) המקורית גזירה והנגזרת שלה היא מטריצת אפסים, כלומר \(Df\left(a\right)=0\) כשכאן 0 היא טרנספורמציית האפס. עוד פונקציה פשוטה במיוחד היא טרנספורמציה לינארית \(T:\mathbb{R}^{n}\to\mathbb{R}^{m}\). כאן אפילו אין טעם לדבר על נגזרות חלקיות כשההגדרה הבסיסית עובדת מייד ומראה לנו ש-\(T\) היא (כמובן) הדיפרנציאל של עצמה: \(\lim_{h\to0}\frac{T\left(a+h\right)-T\left(a\right)-T\left(h\right)}{h}=\lim_{h\to0}\frac{T\left(a+h-a-h\right)}{h}=\lim_{h\to0}\frac{T\left(0\right)}{h}=0\). דוגמה לטרנספורמציה לינארית פשוטה שכזו היא חיבור: \(s\left(x,y\right)=x+y\) (זו פונקציה \(s:\mathbb{R}^{2}\to\mathbb{R}\)), אז אנחנו יודעים לגזור גם אותה.

ומה על כפל? \(p:\mathbb{R}^{2}\to\mathbb{R}\) המוגדרת על ידי \(p\left(x,y\right)=xy\)? גזירה חלקית מראה שהנגזרת בנקודה \(\left(a,b\right)\) היא \(\left(b,a\right)\), כלומר הדיפרנציאל הוא \(bx+ay\).

מה שנחמד בפונקציות החיבור והכפל הללו הוא שהן יאפשרו לנו לטפל בחיבור וכפל של פונקציות סקלריות כלליות. למשל, אם \(f,g:\mathbb{R}^{n}\to\mathbb{R}\) ואנחנו מגדירים \(h=f+g\), אז \(h=s\left(f,g\right)\). יש לנו כאן הרכבה של פונקציה \(\mathbb{R}^{n}\to\mathbb{R}^{2}\) שבנויה על הזוג \(\left(f,g\right)\), עם הפונקציה \(s:\mathbb{R}^{2}\to\mathbb{R}\). אם נדע איך לגזור הרכבה, נדע לגזור גם חיבור וכפל של פונקציות, בלי שום מאמץ מחשבתי נוסף מצידנו. אז זו הבעיה שאפתור עכשיו.

הכלל שמתאר את העובדה שהרכבה של פונקציות גזירות הוא גזיר ונותן את הנוסחה לביצוע הגזירה נקרא כלל השרשרת. אתם בוודאי מכירים את הגרסה שלו עבור פונקציות ממשיות. בואו נתחיל מלראות אותה. מאוד קל לזכור את הגרסה הזו אם משתמשים בסימון של לייבניץ לגזירת פונקציות: אם \(f\left(x\right)\) היא פונקציה עם המשתנה היחיד \(x\), אז במקום לכתוב \(f^{\prime}\) (בערך הכתיב שבו ניוטון השתמש), אפשר לכתוב \(\frac{df}{dx}\). אחת הסיבות לכתיב הזה היא שקל לזכור את כלל השרשרת בעזרתו.

אם \(y:\mathbb{R}\to\mathbb{R}\) היא פונקציה, ואנחנו מסתכלים על ההרכבה \(f\left(y\left(x\right)\right)\), אז הנגזרת שלה היא \(\frac{df}{dx}=\frac{df}{dy}\frac{dy}{dx}\). הבעיה היא – וזה משהו שאני מרגיש ביתר שאת עכשיו, כשאני מנסה לכתוב את הפוסט הזה בצורה מסודרת – שזה כתיב מאוד לא פורמלי שקל לאבד בו דקויות. בואו נסתכל שוב על המשוואה \(\frac{df}{dx}=\frac{df}{dy}\frac{dy}{dx}\). כאן נראה ש-\(f\) היא פונקציה של שני משתנים שונים: המשתנה \(x\), באגף שמאל; והמשתנה \(y\), באגף ימין. אבל הרי \(y\) הוא לא באמת משתנה; הוא פונקציה. ומה שמופיע באגף ימין הוא בעצם לא \(f\), הוא פונקציה מסובכת יותר שמתקבלת מהרכבת \(f\) על \(y\). בקיצור, הסימון הזה יכול להיות מועיל אבל הוא גם מסוכן למי שלא שולט בו, ואני אישית לא אוהב אותו. וזה בלי שניכנס בכלל לתלונות על כך שמתרחש פה משהו שנקרא כמו "צמצום דיפרנציאלים" – משהו שבוודאי אין לו משמעות פורמלית עבור רמת החומר שבדרך כלל נלמדת באינפי 1.

אז הנה העסק בכתיב ניוטוני. נניח ש-\(f,g;\mathbb{R}\to\mathbb{R}\) ונגדיר \(h\left(x\right)=f\left(g\left(x\right)\right)\) (לפעמים זה מסומן ב-\(f\circ g\) ולפעמים ב-\(g\circ f\), תלוי איזה ספר אתם קוראים, ויש הגיון מאחורי שתי שיטות הסימון; לכן אני שונא גם את הסימון הזה). אז כלל השרשרת אומר לנו ש-\(h^{\prime}\left(x\right)=f^{\prime}\left(g\left(x\right)\right)g^{\prime}\left(x\right)\). כלומר, הנגזרת ב-\(x\) שווה למכפלה של הנגזרת של \(g\) ב-\(x\), כפול הנגזרת של \(f\), אבל לא ב-\(x\) אלא בנקודה שאליה \(g\) מעביר את \(x\) (ההבחנה הזו היא עניין מבלבל). למשל, אם \(g\left(x\right)=x^{2}\) ו-\(f\left(x\right)=\sin x\) אז \(h\left(x\right)=\sin\left(x^{2}\right)\) ולכן \(h^{\prime}\left(x\right)=\cos\left(x^{2}\right)\cdot2x\) (ולא \(\cos\left(x\right)\cdot2x\)).

האינטואיציה מאחורי ההוכחה של המקרה החד ממדי די פשוטה. ראשית, בואו ניזכר בכך שאפשר לכתוב את הנגזרת גם בצורה קצת שונה, אולי קצת יותר טבעית:

\(h^{\prime}\left(a\right)=\lim_{t\to0}\frac{h\left(a+t\right)-h\left(a\right)}{t}=\lim_{x\to a}\frac{h\left(x\right)-h\left(a\right)}{x-a}\)

תוך שימוש בניסוח הזה, פשוט מפרקים את הביטוי של הנגזרת למכפלה של שני ביטויי נגזרת מתאימים על ידי כפל וחילוק ב-\(g\left(x\right)-g\left(a\right)\):

\(h^{\prime}\left(a\right)=\lim_{x\to a}\frac{h\left(x\right)-h\left(a\right)}{x-a}=\lim_{x\to a}\frac{f\left(g\left(x\right)\right)-f\left(g\left(a\right)\right)}{g\left(x\right)-g\left(a\right)}\frac{g\left(x\right)-g\left(a\right)}{x-a}=f^{\prime}\left(g\left(a\right)\right)g^{\prime}\left(a\right)\)

כמובן, צריך להיות זהירים פה ולהסביר יותר במדויק למה \(\lim_{x\to a}\frac{f\left(g\left(x\right)\right)-f\left(g\left(a\right)\right)}{g\left(x\right)-g\left(a\right)}=f^{\prime}\left(g\left(a\right)\right)\); הרי יכולות לצוץ כל מני בעיות משונות בגלל ש-\(g\) יכולה להתנהג מוזר (מה קורה אם \(g\left(x\right)=g\left(a\right)\) עבור \(x\ne a\) כלשהו?). אני מביא את חצי ההוכחה הזו כדי שנרגיש מאיפה הנוסחה מגיעה בכלל. הוכחה מלאה ומדוייקת אני אתן עכשיו למשפט הכללי, עבור פונקציות וקטוריות כלליות; מן הסתם נקבל את כלל השרשרת המקורי בתור מקרה פרטי.

אז איך בכלל מנוסח המשפט הכללי? אם אני רוצה להרכיב את \(f\) על \(g\) אני צריך שהטווח של \(g\) יהיה מאותו מימד כמו התמונה של \(f\), כלומר \(g:\mathbb{R}^{n}\to\mathbb{R}^{k}\) ואילו \(f:\mathbb{R}^{k}\to\mathbb{R}^{m}\). שימו לב ל-\(k\) המשותף הזה. עכשיו נגדיר \(h\left(x\right)=f\left(g\left(x\right)\right)\) וקיבלנו פונקציה \(h:\mathbb{R}^{n}\to\mathbb{R}^{m}\) נטולת \(k\). בהינתן \(a\in\mathbb{R}^{n}\) אנחנו רוצים לדעת מהי \(Dh\left(a\right)\); זוהי מטריצה \(m\times n\) (זוכרים? כל שורה של המטריצה היא גרדיאנט של אחד מהרכיבים של \(h\); יש ל-\(h\) \(m\) רכיבים והאורך של כל גרדיאנט הוא \(n\)). אם נרצה פשוט לקחת את הנוסחה של כלל השרשרת החד ממדי ולכתוב אותה מחדש, נקבל את הדבר הבא:

\(Dh\left(a\right)=Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\)

מה יש לנו כאן? ובכן, \(Df\left(g\left(a\right)\right)\) היא מטריצה \(m\times k\) ואילו \(Dg\left(a\right)\) היא מטריצה \(k\times n\). לכן המכפלה שלהן – ובסדר הזה, הנגזרת של \(f\) משמאל והנגזרת של \(g\) מימין – נותנת לנו באמת מטריצה \(m\times n\). כך שנראה שהנוסחה עובדת! רק יהיה צריך להוכיח אותה. הבעיה היא שמייד ברור שההוכחה האלגנטית של המקרה החד ממדי לא תעבוד. כי אנחנו כבר לא עובדים עם ביטוי נחמד כמו \(\lim_{x\to a}\frac{h\left(x\right)-h\left(a\right)}{x-a}\) אלא עם המפלצת \(\lim_{t\to0}\frac{h\left(a+t\right)-h\left(a\right)-Dh\left(a\right)t}{\left|t\right|}\) שבה \(t\) הוא בכלל וקטור והמטרה שלנו היא לא להראות שהגבול קיים אלא שהוא אפס. לכו תפתחו את זה למכפלה של שני גבולות שונים, שבהם מה ששואף לאפס שייך למרחבים ממימד אחר, והדיפרנציאלים המעורבים הם ממימדים שונים, וכו' וכו' וכו'. בקיצור, זה הולך להיות יותר טכני. בשורה התחתונה מה שנעשה הוא פשוט לבוא עם פטיש גדול ולהתחיל לדפוק על ההוכחה עד שזה יסתדר – אין כאן חוכמה גדולה ובעיקר יש טיפול שנראה קצת משמים בכל מני ביטויים. סביר להניח שחלקכם יאבדו אותי כאן ויכולים פשוט לקפוץ אל "עכשיו אפשר לשכוח מכל המהומה הטכנית" שאחר כך; מי שבאמת רוצה להבין, אני ממליץ על כתיבת ההוכחה בעצמכם במקביל אלי (הדרך היחידה שבה אני ממש מבין את ההוכחה היא על ידי כך שאני כותב אותה).

בתור התחלה, אנחנו לא מניחים ש-\(f,g\) בהכרח מוגדרות לכל \(\mathbb{R}^{n}\) ו-\(\mathbb{R}^{k}\), בהתאמה (הרבה פעמים אנחנו רוצים להשתמש בכלל השרשרת גם לפונקציות שמוגדרות רק עבור חלק מהתחום הזה). כל מה שאנחנו מניחים הוא ש-\(g\) היא גזירה ב-\(a\) ו-\(f\) גזירה ב-\(g\left(a\right)\). מכך אני רוצה להסיק ש-\(h\) גזירה ב-\(a\) ולמצוא את הנגזרת שלה. לצורך כך אני רוצה להיות מסוגל לדבר על ערכים של \(h\) בסביבה של \(a\), כי זה מה שמופיע בהגדרת הנגזרת – כלומר, על ערכים מהצורה \(h\left(a+t\right)\) עבור \(t\) קטן. הטענה היא שעבור \(t\) קטן מספיק (כלומר, \(\left|t\right|<\delta\) עבור \(\delta>0\) מסויים), הביטוי \(h\left(a+t\right)\) יהיה מוגדר. עכשיו, מכיוון שאנחנו יודעים ש-\(f\) רציפה ב-\(g\left(a\right)\) בפרט קיים \(\varepsilon>0\) כך ש-\(f\) מוגדרת לכל \(y\) כך ש-\(\left|y-g\left(a\right)\right|<\varepsilon\). מהרציפות של \(g\) עולה שקיים \(\delta>0\) כך ש-שאם \(\left|x-a\right|<\delta\) אז \(g\) מוגדרת ב-\(x\) ומתקיים \(\left|g\left(x\right)-g\left(a\right)\right|<\varepsilon\) (זו ההגדרה של רציפות, כשפותחים אותה לאפסילון-דלתא). קיבלנו את ה-\(\delta\) שרצינו.

אם כן, בואו ניקח \(t\) כך ש-\(\left|t\right|<\delta\). זה אומר ש-\(\left|g\left(a+t\right)-g\left(a\right)\right|<\varepsilon\) ולכן \(f\) מוגדרת ב-\(g\left(a+t\right)\). כעת, מכיוון ש-\(f\) גזירה, זה אומר שמתקיים הגבול הבא:

\(\lim_{s\to0}\frac{f\left(g\left(a\right)+s\right)-f\left(g\left(a\right)\right)-Df\left(g\left(a\right)\right)s}{\left|s\right|}=0\)

בואו נרשום את הביטוי שבתוך הגבול בתור פונקציה של \(s\): \(F\left(s\right)=\frac{f\left(g\left(a\right)+s\right)-f\left(g\left(a\right)\right)-Df\left(g\left(a\right)\right)s}{\left|s\right|}\). הפונקציה הזו מוגדרת לכל \(s\) כך ש-\(0<\left|s\right|<\varepsilon\) (עבור \(s\)-ים גדולים יותר לא מובטח ש-\(f\left(g\left(a\right)+s\right)\) תהיה מוגדרת) ומה שאני רוצה לעשות הוא להציב במקום \(s\) את \(g\left(a+t\right)-g\left(a\right)\) (שראינו לפני רגע שאכן קטן בערכו המוחלט מאפסילון), בערך כמו מה שעושים בהוכחת כלל השרשרת הרגיל. ההצבה הזו מועילה לי במיוחד בטיפול בגורם \(f\left(g\left(a\right)+k\right)\): כרגע הוא לא משהו שאני יכול לכתוב עם \(h\), הפונקציה שאני רוצה בסופו של דבר לגזור; אבל אחרי ההצבה הזו נקבל את \(f\left(g\left(a+t\right)\right)=h\left(a+t\right)\).

אם כן, בואו ניקח את המשוואה שהגדירה את \(F\left(s\right)\) ונטפל בה קצת – נכפול ב-\(\left|s\right|\), נעביר אגפים ונקבל

\(f\left(g\left(a\right)+s\right)-f\left(g\left(a\right)\right)=\left|s\right|F\left(k\right)+Df\left(g\left(a\right)\right)s\)

לעת עתה אשתמש בקיצור \(\Delta g=g\left(a+t\right)-g\left(a\right)\) כי זה יחסוך לי כתיבה. אם כן, אחרי הצבת \(s=\Delta g\) אני מקבל

\(h\left(a+t\right)-h\left(a\right)=\left|\Delta g\right|F\left(\Delta g\right)+Df\left(g\left(a\right)\right)\cdot\Delta g\)

בואו ונסתכל על הגורם הכי ימני במשוואה הזו: \(Df\left(g\left(a\right)\right)\cdot\Delta g\). זה קצת מזכיר לנו את מה שאנחנו מצפים שיופיע בנוסחה הסופית: \(Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\). כך שהשלב המתבקש הבא הוא לנסות ולמצוא תיאור נחמד יותר עבור \(\Delta g\). אפשר לשכוח לרגע מהמשוואה שקיבלנו ולהתמקד בניתוח שלו.

לצורך כך, בואו ניזכר בכך שגם \(g\) היא פונקציה גזירה, ולכן אפשר לכתוב עבורה פונקציה דומה לזו שכתבנו עבור \(f\), רק פשוטה יותר:

\(G\left(t\right)=\frac{g\left(a+t\right)-g\left(a\right)-Dg\left(a\right)t}{\left|t\right|}\)

הפונקציה הזו מוגדרת לכל \(0<\left|t\right|<\delta\), ואפשר להגדיר \(G\left(0\right)=0\) ונקבל ש-\(G\) הזו גם רציפה לכל \(\left|t\right|<\delta\). ושוב, על ידי כפל והעברת אגפים נקבל

\(\Delta g=\left|t\right|G\left(t\right)+Dg\left(a\right)t\)

קיבלנו את התיאור עבור \(\Delta g\) שרצינו. עכשיו, בואו נחזור אל \(h\). המטרה שלנו, כזכור, היא לחשב את הגבול הבא:

\(\frac{h\left(a+t\right)-h\left(a\right)-Dh\left(a\right)t}{\left|t\right|}\)

כאשר ההימור שלנו למועמדת לתפקיד \(Dh\left(a\right)\) היא \(Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\). במילים אחרות, אנחנו רוצים לחשב את הגבול של

\(\frac{h\left(a+t\right)-h\left(a\right)-Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\cdot t}{\left|t\right|}\)

(שימו לב שאני כותב את \(Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\cdot t\) בלי סוגריים; זה תקין, מכיוון שכפל מטריצות הוא אסוציאטיבי).

עכשיו, נחליף את \(h\left(a+t\right)-h\left(a\right)\) בתיאור שמצאנו למעלה, ונקבל:

\(\frac{\left|\Delta g\right|F\left(\Delta g\right)+Df\left(g\left(a\right)\right)\cdot\Delta g-Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\cdot t}{\left|t\right|}\)

ועכשיו נציב את ה-\(\Delta g\) שמצאנו, ונקבל:

\(\frac{\left|\Delta g\right|F\left(\Delta g\right)+\left|t\right|Df\left(g\left(a\right)\right)G\left(t\right)+Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\cdot t-Df\left(g\left(a\right)\right)\cdot Dg\left(a\right)\cdot t}{\left|t\right|}\)

שני הגורמים האחרונים מבטלים זה את זה, כך שאנחנו נשארים עם הביטוי היחסית פשוט

\(\frac{\left|\Delta g\right|F\left(\Delta g\right)}{\left|t\right|}+Df\left(g\left(a\right)\right)G\left(t\right)\)

ואנחנו רוצים להראות שהוא שואף לאפס כאשר \(t\) שואף לאפס. מה שיש כאן הוא חשבון מכולת סטנדרטי של אינפי – מראים שיש לנו סכום של גורמים כך שכל גורם כולל חלק ששואף לאפס, וחלק שהוא חסום ולכן "לא מפריע" לו. נתחיל עם \(Df\left(g\left(a\right)\right)G\left(t\right)\). כאן \(Df\left(g\left(a\right)\right)\) הוא מספר קבוע בעוד ש-\(G\left(t\right)\) שואפת כמובן לאפס (למה "כמובן"? בטח איבדתם אותי לגמרי כבר; \(G\left(t\right)\) היא הפונקציה שמתארת את הגבול שמגדיר את הגזירות של \(g\)). הביטוי \(\frac{\left|\Delta g\right|}{\left|t\right|}F\left(\Delta g\right)\) מאתגר קצת יותר. מכיוון ש-\(g\) רציפה, הרי ש-\(\Delta g=g\left(a+t\right)-g\left(a\right)\) שואפת לאפס כאשר \(t\) שואף לאפס, ומכיוון ש-\(F\) שואפת לאפס כשהקלט שלה שואף לאפס (מאותה סיבה של \(G\)) קיבלנו ש-\(F\left(\Delta g\right)\) שואפת לאפס. נשאר רק להראות ש-\(\frac{\left|\Delta g\right|}{\left|t\right|}\) חסומה.

לצורך כך, זכרו שראינו כי \(\Delta g=\left|t\right|G\left(t\right)+Dg\left(a\right)t\). ניקח נורמה בשני האגפים ונקבל

\(\left|\Delta g\right|\le\left|t\right|\left|G\left(t\right)\right|+\left|Dg\left(a\right)\right|\left|t\right|=\left|t\right|\left(\left|G\left(t\right)\right|+k\left|Dg\left(a\right)\right|\right)\)

המעבר האחרון עשוי להיות קצת מבלבל עבור מי שלא מכיר. זכרו ש-\(Dg\left(a\right)\) היא מטריצה מסדר \(k\times n\) . לכן הביטוי \(\left|Dg\left(a\right)\right|\) עבורה שונה מאשר עבור, נאמר \(\left|t\right|\) – כאן זו נורמה של מטריצה. במקרה שלנו, ההגדרה של הנורמה הזו פשוטה – חשבו על המטריצה בתור וקטור ארוך, וקחו את הנורמה הרגילה שלה. כעת, \(Dg\left(a\right)\cdot t\) זו מכפלה שלוקחת וקטור מגודל \(n\) ומחזירה וקטור מגודל \(k\), שהכניסות שלו הן מכפלות סקלריות של \(t\) עם \(k\) שורות \(Dg\left(a\right)\). קל לראות, באמצעות שימוש באי-שוויון המשולש, שמתקיים \(\left|Dg\left(a\right)\cdot t\right|\le k\left|Dg\left(a\right)\right|\left|t\right|\), ומכאן המעבר שלי.

קיבלנו ש-\(\frac{\left|\Delta g\right|}{\left|t\right|}=\left|G\left(t\right)\right|+k\left|Dg\left(a\right)\right|\). כעת, \(G\left(t\right)\) רציפה ושואפת לאפס ולכן גם \(\left|G\left(t\right)\right|\), ולכן היא בוודאי חסומה; ואילו \(k\left|Dg\left(a\right)\right|\) הוא קבוע. זה מסיים את ההוכחה.

עכשיו אפשר לשכוח מכל המהומה הטכנית הזו ולקטוף באלגנטיות את הפירות. ראינו שהדיפרנציאל של \(s\left(x,y\right)=x+y\) בכל נקודה הוא \(s\) עצמה. כעת, נניח שיש לנו שתי פונקציות \(f:\mathbb{R}^{n}\to\mathbb{R}\) ו-\(g:\mathbb{R}^{n}\to\mathbb{R}\) ואנחנו רוצים לגזור את \(f+g\), מה עושים? נשים לב לכך ש-\(h\left(x\right)=\left(f+g\right)\left(x\right)=s\left(f,g\right)\left(x\right)\) (כאן \(f,g\) זו בעצם דרך לתאר פונקציה מ-\(\mathbb{R}^{n}\) אל \(\mathbb{R}^{2}\) ש-\(f,g\) הם רכיביה), ולכן נגזור על פי כלל השרשרת ונקבל

\(Dh\left(a\right)=Ds\left(f\left(a\right),g\left(a\right)\right)D\left(f\left(a\right),g\left(a\right)\right)=s\left(Df\left(a\right),Dg\left(a\right)\right)=Df\left(a\right)+Dg\left(a\right)\)

לא מפתיע, כמובן, אבל נחמד מאוד שזה מתקבל כך. קצת יותר מעניין יהיה לעשות את אותו דבר עבור כפל. שם הדיפרנציאל של \(xy\) בנקודה \(\left(a,b\right)\) היה \(bx+ay\). אצלנו, הנקודה \(\left(a,b\right)\) היא בעצם \(\left(f\left(a\right),g\left(a\right)\right)\) ולכן נקבל מכלל השרשרת בסופו של דבר את \(g\left(a\right)Df\left(a\right)+f\left(a\right)Dg\left(a\right)\).

אם כן, אנחנו יודעים כעת איך מחשבים את הנגזרת של פונקציות מורכבות יחסית – כאלו שמתקבלות מפונקציות פשוטות על ידי חיבור, כפל והרכבה. מה עם חיסור וחילוק? אפשר להרכיב את הפונקציה \(g\left(x\right)=-x\) על כל פונקציה שנרצה ולקבל בקלות ש-\(D\left(-f\right)=-Df\), ולכן \(D\left(f-g\right)=Df-Dg\).

חילוק, כמובן, יהיה בעייתי יותר, כי לא ניתן לחלק באפס. אנחנו רוצים להרכיב את \(g\left(x\right)=\frac{1}{x}\) (שהנגזרת שלה היא \(-\frac{1}{x^{2}}\), על פי כללי הגזירה הרגילים) על הפונקציה \(f\), אבל בשביל זה אנחנו צריכים לדרוש ש-\(f\) תהיה שונה מאפס בנקודה שבה אנחנו מחשבים את הנגזרת. כלומר, אם \(f\left(a\right)\ne0\) אז \(D\frac{1}{f}\left(a\right)=D\left(g\left(f\right)\right)\left(a\right)=-\frac{1}{f^{2}\left(a\right)}Df\left(a\right)\).

מכאן גם אפשר לקבל את הנגזרת הכללית של מנת שתי פונקציות: \(D\frac{h}{f}=D\left(\frac{1}{f}\cdot h\right)=D\frac{1}{f}h+\frac{1}{f}Dh=-\frac{hDf}{f^{2}}+\frac{1}{f}Dh=\frac{fDh-hDf}{f^{2}}\) – שוב, תחת ההנחה שאנחנו מחשבים את הפונקציות הללו רק בנקודות שבהן \(f\) שונה מאפס.

כל אלו הן תוצאות נחמדות, כי הן לא שונות, בעצם, ממה שקורה באינפי רגיל במשתנה יחיד, למרות שאצלנו \(Df\) זה יצור הרבה יותר מסובך מאשר הנגזרת הרגילה. זה בהחלט עוזר להרגיש ש"הצלחנו" בהגדרה שלנו. אם כן, הבה ונמשיך במיטב המסורת של אינפי, ונעבור אל הבניה האחרונה שלנו, שגם היא מוכללת בצורה טבעית, אבל הסיפור שלה אצלנו יהיה מסובך הרבה יותר – נגזרת הפונקציה ההפוכה.

נניח שיש לנו פונקציה \(f:\mathbb{R}^{n}\to\mathbb{R}^{n}\) (שימו לב – כאן גם התחום וגם הטווח הם מאותו מימד \(n\)). אז \(g:\mathbb{R}^{n}\to\mathbb{R}^{n}\) היא הפונקציה ההפוכה ל-\(f\) אם \(f\left(g\left(x\right)\right)=g\left(f\left(x\right)\right)=x\) לכל \(x\in\mathbb{R}^{n}\). לא תמיד קיימת כזו, כמובן (חשבו על \(f\left(x\right)=0\)). אם קיימת, מסמנים אותה לרוב ב-\(f^{-1}\). יותר מזה, לעתים קרובות לא קיימת ל-\(f\) הופכית על כל \(\mathbb{R}^{n}\), אבל אם נגביל את התחום של \(f\) לתת-קבוצה \(A\subseteq\mathbb{R}^{n}\) נקבל משהו הפיך. דוגמה קלאסית היא הפונקציה \(f\left(x\right)=x^{2}\); היא לא חד-חד-ערכית על הממשיים כי \(f\left(x\right)=f\left(-x\right)\); מצד שני, על הממשיים האי-שליליים היא כן חד-חד-ערכית והפיכה; ההופכית שלה היא \(g\left(x\right)=\sqrt{x}\) (המוסכמה הרגילה היא ש-\(\sqrt{x}\) כאשר \(x\) ממשי מחזיר את השורש האי-שלילי אם קיימים שני שורשים).

נניח שגם \(f\) וגם \(f^{-1}\) הן גזירות, ונניח שאנחנו יודעים מה הנגזרת של \(f\); האם אפשר למצוא ממנה את הנגזרת של \(f^{-1}\)? למשל, אנחנו יודעים שהנגזרת של \(\sin x\) היא מאוד פשוטה: \(\cos x\). אבל איך אפשר לקבל מזה את הנגזרת של \(\arcsin x\)? אני ממש לא זוכר את הנגזרת הזו בעל פה; בואו נראה אם נצליח לפתח אותה מחדש (כמובן, אנחנו מדברים פה על המקרה של אינפי בסיסי, אבל לא יהיה הבדל אמיתי בינו ובין המקרה הכללי).

הטריק הוא להשתמש בכלל השרשרת. אם \(f\left(f^{-1}\right)=I\) כאשר \(I\) היא פונקציית הזהות \(I\left(x\right)=x\), אז מצבנו טוב כי אנחנו יודעים בדיוק מהו \(DI\): כבר אמרנו שהנגזרת של פונקציה לינארית היא היא עצמה, כלומר \(DI\left(a\right)=I\) לכל \(a\). נסמן \(b=f^{-1}\left(a\right)\) ועכשיו אפשר להשתמש בכלל השרשרת ולקבל ש-\(I=Df\left(b\right)Df^{-1}\left(a\right)\). היינו רוצים עכשיו "לחלק" ב-\(Df\left(b\right)\), אבל צריך להיזהר פה: זה לא מספר שאפשר סתם לחלק בו. זו טרנספורמציה לינארית. "לחלק" בהקשר של טרנספורמציות לינאריות פירושו לכפול בהופכי. לכן אני צריך להניח ש-\(Df\left(b\right)\) הפיכה בכלל, וזה שקול לכך ש-\(\det Df\left(b\right)\ne0\) (מי שלא מכיר את \(\det\) – נו נו נו! אמרתי שצריך אלגברה לינארית. הנה הפוסט שלי על דטרמיננטות). במקרה שבו זה נכון, אז נקבל ש-\(Df^{-1}\left(a\right)=\left(Df\left(b\right)\right)^{-1}\) – אלגנטי ויפה.

כדי להבין את הנוסחה הזו, בואו נפעיל אותה במקרה של \(\mbox{arcsin}\). עבור פונקציות במשתנה יחיד, זכרו שמה שאנחנו קוראים לו \(Df\left(a\right)\) הוא בעצם הפונקציה הלינארית \(f^{\prime}\left(a\right)x\). הפונקציה הזו הפיכה אם ורק אם \(f^{\prime}\left(a\right)\ne0\) ואז ההופכית שלה היא פשוט \(\frac{1}{f^{\prime}\left(a\right)}x\). כלומר, הנוסחה במקרה הזה הופכת להיות \(\left(f^{-1}\right)^{\prime}\left(a\right)=\frac{1}{f^{\prime}\left(b\right)}\). לכן קיבלנו ש-\(\arcsin^{\prime}\left(a\right)=\frac{1}{\sin^{\prime}\left(\arcsin a\right)}=\frac{1}{\cos\left(\arcsin a\right)}\). כאן אנחנו לכאורה נתקעים, כי איך מחשבים קוסינוס של ארקסינוס? אבל מספיק לזכור את הזהות הבסיסית ביותר שקשורה לסינוסים וקוסינוסים – שהם מתארים נקודה על מעגל היחידה, ולכן \(\cos^{2}x+\sin^{2}x=1\) לכל \(x\). מכאן אפשר לחלץ ולקבל ש-\(\cos x=\sqrt{1-\sin^{2}x}\) עבור \(-\frac{\pi}{2}\le x\le\frac{\pi}{2}\) (עבור ערכי \(x\) אחרים צריך לפעמים לקחת את השורש השלילי). כלומר, \(\cos\left(\arcsin\left(a\right)\right)=\sqrt{1-\sin^{2}\left(\arcsin a\right)}=\sqrt{1-a^{2}}\). מסקנה: \(\arcsin^{\prime}\left(a\right)=\frac{1}{\sqrt{1-a^{2}}}\).

משהו כאן בבירור לא עובד כאשר \(a=\pm1\), כלומר כאשר הקלט ל-\(\sin\) הוא כזה שיחזיר 1 או \(-1\), כלומר \(\pm\frac{\pi}{2}\), כלומר הנגזרת שמצאנו עובדת רק עבור \(-\frac{\pi}{2}<a<\frac{\pi}{2}\) ואילו בשתי נקודות הקצה הללו משהו "מתפוצץ" (מה שמסביר, מנקודת מבט שונה, למה נאלצתי להצטמצם לתחום הזה). מה בעצם השתבש? אלו הן בדיוק נקודות המקסימום והמינימום של \(\sin\); אחרי \(\frac{\pi}{2}\), למשל, היא מתחילה "ליפול" בעוד שקודם היא עלתה. זה אומר שהיא כבר לא תהיה חד-חד-ערכית ולכן לא הפיכה, ולכן מראש היינו חייבים להצטמצם עם \(\arcsin\) לקטע הזה. עכשיו, דרך נחמדה לדמיין פונקציה הופכית במימד אחד היא לקחת את הגרף של הפונקציה ולסובב אותו ב-90 מעלות נגד כיוון השעון, ואז לשקף ביחס לציר \(y\); אם אתם לא מאמינים תנסו לעשות את זה עם \(f\left(x\right)=x^{2}\). מן הסתם כשעושים דבר כזה, אז נקודה שבה המשיק של \(\sin x\) היה אופקי (שיפוע 0) תהפוך לנקודה שבה המשיק של \(\arcsin x\) יהיה אנכי (שיפוע "אינסוף"), מה שמסביר את הפיצוץ הזה.

אם כן, למדנו דבר מעניין – שאם \(\det Df\left(a\right)\ne0\) אז הנגזרת של \(f^{-1}\) ב-\(a\) שווה ל-\(\left[Df\left(f^{-1}\left(a\right)\right)\right]^{-1}\). אבל שימו לב לשלוש ההנחות שיש לנו כאן:

  1. \(Df\left(a\right)\) הפיכה.
  2. \(f^{-1}\) קיימת.
  3. \(f^{-1}\) גזירה.

אם שלוש ההנחות הללו התקיימו, אנחנו יודעים לחשב את הנגזרת של \(f^{-1}\). אבל האמת היא שמתקיים פה קסם – אם \(f\) היא גזירה ברציפות (כלומר, בעלת נגזרת רציפה) אז די בכך ש-\(Df\left(a\right)\) תהיה הפיכה על מנת להבטיח שקיימת ל-\(f\) הופכית בסביבה של \(a\), ושההופכית הזו תהיה גזירה (למעשה, אם \(f\) גזירה ברציפות \(r\) פעמים, כך גם הנגזרת של ההופכית). הקסם הזה, שנקרא משפט הפונקציה ההפוכה, הוא המשפט הלא טריוויאלי הראשון שאנחנו הולכים לראות, ומייד אחר כך נראה שימוש יפה שלו – משפט הפונקציות הסתומות. מכיוון שזה לא הולך להיות קצר או פשוט, נחכה עם זה (כולל הניסוח הפורמלי) עד לפוסט הבא. לעת עתה, טיזר – בואו נבין אינטואיטיבית למה זה עובד כמעט מייד בפונקציות \(f:\mathbb{R}\to\mathbb{R}\). אם \(f^{\prime}\left(a\right)\ne0\) והנגזרת רציפה, זה אומר שיש סביבה של \(a\) שבה \(f^{\prime}\left(a\right)\) נמצאת כולה מעל 0 או מתחת ל-0. במקרה הראשון זה אומר ש-\(f\) עולה בסביבה הזו, ובמקרה השני – שהיא יורדת. בכל מקרה, היא מונוטונית. פונקציה מונוטונית היא, כמובן, הפיכה (עדיין צריך להוכיח שהיא גזירה, אבל לא נדבר על זה פה). כמובן שעבור פונקציות במימד גבוה יותר העסק כבר לא יהיה כל כך פשוט כי זה שהנגזרת היא טרנספורמציה לינארית הפיכה לא יגרור שהפונקציה היא מונוטונית; בפוסט הבא ניכנס לפרטים המלוכלכים.

משפט קוק-לוין

חור מטריד שקיים בבלוג ואני מתכוון להשלים כעת הוא תיאור והוכחה של אחד מהמשפטים הבסיסיים והחשובים ביותר בתורת הסיבוכיות – משפט קוק-לוין. אף שכבר תיארתי את הבסיס לתורת הסיבוכיות בעבר, וגם הראיתי תוצאות מסובכות יותר מקוק-לוין, איכשהו המשפט הזה חמק ממני והגיע הזמן להשלים את החסר. בפוסט הזה לא רק אתאר את המשפט ואת הרקע שלו אלא גם אתאר את כל ההוכחה; מכיוון שזה לרוב המשפט בעל ההוכחה המסובכת ביותר שסטודנטים נתקלים בו בקורס המבוא לנושאים הללו, אני מקווה שהפוסט יתגלה כמועיל למדי. אני בעיקר רוצה להבהיר שההוכחה הזו אינה קשה ואינה מפחידה כפי שהרושם הראשון שלה עשוי להצטייר (בפעם הראשונה שבה ראיתי הוכחה לא הבנתי כלום).

קל מאוד לנסח את המשפט: "השפה SAT היא NP-שלמה". אני מניח שאתם מכירים את המושגים הללו, כי אין טעם לקרוא ישר על משפט קוק-לוין בלי להכיר אותם, ובכל זאת תזכורת קטנה למי ששמע את המושגים ואין לו כוח לחזור עליהם: אנחנו מתעסקים פה בבעיות הכרעה של שפות פורמליות, כלומר בהינתן מחרוזת \(w\) כלשהי אנחנו שואלים האם היא שייכת או לא לקבוצה \(L\) – קבוצה כזו נקראת "שפה".

השפה SAT היא דוגמה אחת לשפה שכזו, מאוד מעניינת: המחרוזות ששייכות אליה מקודדות פסוקים מתחשיב הפסוקים, שהם מהצורה הנורמלית CNF. כלומר, כל פסוק הוא מהצורה \(\varphi=C_{1}\wedge C_{2}\wedge\dots\wedge C_{n}\) כך שכל \(C_{i}\) כזו נקראת פסוקית והיא מהצורה \(C=\left(l_{1}\vee l_{2}\vee\dots\vee l_{k}\right)\) כאשר כל \(l_{j}\) כזה נקרא ליטרל והוא או משתנה או שלילה של משתנה (או מהצורה \(x\) או מהצורה \(\neg x\) עבור משתנה \(x\) כלשהו). שימו לב שמספר הליטרלים בכל פסוקית יכול להיות שונה; פסוק CNF פשוט לדוגמה הוא \(\left(x\vee\neg y\right)\wedge\left(\neg x\vee y\vee z\right)\).

פסוק CNF נקרא ספיק אם קיימת השמה של ערכי אמת למשתנים שלו שמספקת אותו. כדי לספק פסוק CNF צריך לספק בו זמנית את כל הפסוקיות שלו; כדי לספק פסוקית צריך לספק לפחות ליטרל אחד. כדי לספק משתנה צריך להציב בו את הערך True, וכדי לספק שלילה של משתנה צריך להציב באותו משתנה את הערך False. זה הכל. בפועל אני מייצג את True ו-False בעזרת 1 ו-0, בהתאמה.

הבעיה של הכרעה האם פסוק CNF כלשהו שייך ל-SAT היא בעיה קשה, מבחינה חישובית: אם יש לפסוק \(n\) משתנים בסך הכל (פזורים לכל רוחב הפסוקיות שלו, לפעמים עם שלילה) אז יש \(2^{n}\) השמות אפשריות לפסוק, ולעבור אחת אחת ולבדוק את כולן – זה פתרון שהוא לא יעיל מבחינה חישובית. זה לא אומר שאין שיטות מתוחכמות יותר, אבל אין שיטה שמבטיחה תמיד, גם במקרה הגרוע ביותר, זמן ריצה שנחשב "יעיל" (פולינומי). עם זאת, ל-SAT יש גם תכונה נחמדה מאוד: אם נתון לכם פסוק \(\varphi\) שאכן שייך ל-SAT, אז אפשר לשכנע אתכם יחסית בקלות בכך אם נותנים לכם הוכחה מתאימה לכך – במקרה הזה, ה"הוכחה" היא פשוט השמה מספקת עבור הפסוק; אתם בודקים בעצמכם שההשמה אכן מספקת ולא מרמים אתכם, ואם היא מספקת, השתכנעתם שהפסוק שייך ל-SAT.

הרעיון הזה, של שפות שקל לבדוק הוכחה לשייכות של מילה אליהן מגדיר את המחלקה NP. פורמלית, \(L\in\mbox{NP}\) אם קיים מוודא שהוא מכונת טיורינג פולינומית (אחזור על הפורמליזם שמגדיר מכונות טיורינג בהמשך, כשאזדקק לכך) \(M\) כך ש-\(M\) רצה על זוג קלטים, \(x,y\); הרעיון הוא ש-\(x\) הוא המילה שאת שייכותה ל-\(L\) בודקים, ו-\(y\) הוא "הצעת הוכחה" לשייכות הזו. זמן הריצה הפולינומי של \(M\) נמדד רק ביחס ל-\(x\), או לחילופים דורשים שהגודל של \(y\) יהיה פולינומי בגודל של \(x\), אחרת במקום "הוכחה" היינו יכולים פשוט לדחוף \(y\) ג'יברישי ארוך מאוד ובכך לאפשר ל-\(M\) לרוץ המון זמן ולבדוק את שייכות \(x\) לשפה באופן ישיר, מה שכמובן מפספס את הפואנטה. עכשיו, אם \(x\in L\) הדרישה שלנו היא שקיים \(y\) כך ש-\(M\) מסיימת את ריצתה על הזוג \(x,y\) ואומרת "כן", ואילו אם \(x\notin L\) אז לכל \(y\), \(M\) תסיים את ריצתה על \(x,y\) עם אמירת "לא". שימו לב לחוסר הסימטריה פה ("קיים" אל מול "לכל"). זו כל ההגדרה. יש הגדרה שקולה, שמדברת על מכונת טיורינג אי דטרמיניסטית (וגם את ההגדרה שלי אפשר לנסח בצורה שונה, בעזרת יחסים) אבל אני לא אכנס לזה כרגע – ההוכחה שלי תהיה עבור ההגדרה שנתתי, והוכחות אחרות הן אותו הדבר בערך.

שפות ב-NP יש המון. המון המון המון. עשרות אלפי בעיות מעניינות במדעי המחשב הן בעלות התכונה היפה של NP. ולכן היה מעניין, במידת מה, לגלות שיש שפה ב-NP שמסוגלת לקודד את כולן. השפה הזו הייתה SAT, וזה התוכן של משפט קוק-לוין. למה אני מתכוון ב"לקודד"? בואו ניקח שפה \(L\in\mbox{NP}\) כלשהי; הטענה היא שלכל \(x\) (בין אם הוא ב-\(L\) ובין אם לאו) ניתן לבנות בזמן יעיל (פולינומי) פסוק CNF \(\varphi_{x}\) כך ש-\(\varphi_{x}\in\mbox{SAT}\) אם ורק אם \(x\in L\). לבניה כזו קוראים רדוקציה פולינומית. לכן, ניסוח אחר למשפט קוק-לוין הוא: SAT היא בעלת התכונה שכל שפה ב-NP ניתנת לרדוקציה פולינומית אליה. שפה עם תכונה שכזו נקראת NP-קשה; השם "NP-שלמה" בא להעיד על כך שזו שפה שהיא גם NP-קשה וגם שייכת בעצמה ל-NP.

את המשפט פרסם סטיבן קוק בארה"ב ב-1971. ב-1973 התפרסמה בבריה"מ גרסה אחרת של המשפט שהוכיח לאוניד לוין. זו הייתה אחת מתופעות הלוואי העגומות של המלחמה הקרה – תורת הסיבוכיות התפתחה בארה"ב ובברה"מ באופן בלתי תלוי, וגם הזמנים המדויקים לא ברורים לי (לוין כנראה הוכיח את המשפט הרבה לפני 1973). הניסוח של לוין היה שונה ומה שאני מציג הוא את הניסוח של קוק; אבל מה שלוין עשה עדיין תפס את לב העניין ולכן אני מעדיף לקרוא למשפט על שם שניהם.

משפט קוק היה אמנם מעניין, אבל על פניו הוא לא הוכיח משהו מרגש במיוחד – ניתן ללא קושי מהותי לייצר שפה מלאכותית שהיא NP-שלמה. אבל זה לב העניין – זו תהיה שפה מלאכותית ולא מעניינת, וההוכחה תהיה פשוטה בהתאם. לעומת זאת, קוק תפס שפה חשובה ושימושית, אבל לאף אחד כנראה לא היה ברור עד כמה היא שימושית עד שריצ'ארד קארפ בא בשנת 1972 והציג רשימה של 21 בעיות ב-NP – בעיות מרכזיות ומעניינות במדעי המחשב – ש-SAT ניתנת לרדקוציה אליהן בדרך זו או אחרת. עכשיו, די קל לראות שניתן להרכיב רדוקציות; לכן אם \(L_{1}\) ניתנת לרדוקציה אל SAT, ואילו SAT ניתנת לרדוקציה אל \(L_{2}\), אז \(L_{1}\) ניתנת לרדוקציה אל \(L_{2}\). המשמעות: קארפ הוכיח שעוד 21 בעיות הן NP-שלמות (יום אחד אני ארצה לתאר את כל המאמר שלו בבלוג – זו יצירת מופת של רדוקציות יצירתיות ופשוטות). מכאן כבר הזרם היה בלתי ניתן לעצירה. כדי להוכיח שבעיה היא NP-שלמה, כל מה שצריך לעשות הוא לרדקץ אליה בעיה אחרת, שאנחנו כבר יודעים שהיא NP-שלמה, וככל שאנחנו מכירים יותר כאלו, כך יהיה לנו קל יותר לרדקץ; כיום יש אלפי בעיות שאנו יודעים שהן NP-שלמות. וכל זה נובע מהבסיס, שהוא SAT, דהיינו משפט קוק-לוין.

האנלוגיה הנכונה למשפט קוק-לוין היא בעיית העצירה של טיורינג, השייכת לתורת החישוביות. טיורינג הוכיח עבור בעיה קונקרטית שאין אלגוריתם שמסוגל לפתור אותה; ומכאן ואילך נפתחה הדרך להוכיח עבור שלל בעיות אחרות שאין דרך לפתור אותן, על ידי הצגה של רדוקציה מבעיית העצירה אליהן. כעת, בעיות NP-שלמות הן בוודאי בעיות שניתן לפתור, פשוט לא בהכרח ביעילות; האנלוגיה הנכונה היא לטעון שאם בעיה היא NP-שלמה אז היא בודאות לא שייכת ל-P. לרוע המזל, איננו יכולים להגיד זאת גם כיום. אנחנו יכולים להגיד שאם בעיה NP-שלמה כלשהי שייכת ל-P, אז ינבע מכך מייד שכל הבעיות ב-NP שייכות ל-P (כי בהינתן בעיית NP כלשהו, נרדקץ אותה בזמן פולינומי לבעיה NP-שלמה ששייכת ל-P ואז נפתור את הבעיה הזו). כלומר, אם P שונה מ-NP אז כל הבעיות ה-NP-שלמות הן בודאות לא ב-P. השאלה הזו – האם P שונה מ-NP – היא אולי השאלה הפתוחה המרכזית במדעי המחשב התיאורטיים. כך היא הייתה בפעם הראשונה שכתבתי עליה בבלוג, וכך לצערי נשאר המצב גם כיום.

יפה, אז זה מה שהמשפט אומר; וקרוב לודאי שחידשתי מעט מאוד למי שכבר הכיר את ההגדרות. אז בואו נעבור למנה העיקרית שלנו – איך מוכיחים את המשפט?

הרעיון האינטואיטיבי הוא זה: נתונה לנו שפה \(L\in\mbox{NP}\). ניקח מכונת טיורינג \(M\) עבורה. כעת, בהינתן \(x\) כלשהו, נבנה פסוק \(\varphi_{x}\left(y\right)\) שבצורה מחוכמת כלשהי יקודד בתוכו חישוב של \(M\) על \(x,y\). שימו לב: כאן \(y\) מייצגים את המשתנים של הפסוק; הרעיון הוא שאנחנו יכולים להזין לפסוק ערכים שונים של \(y\), ושהפסוק יסתפק או לא יסתפק בהתאם לשאלה האם \(M\) מחזירה "כן" על \(x,y\) או "לא". אבל זה רק הרעיון האינטואיטיבי. הביצוע יהיה קצת יותר מסובך. בפועל לקודד חישובים עם CNF זה לא טריוויאלי, אז אנחנו נשתמש גם במשתני עזר שאסמן \(z\), והפסוק יסומן \(\varphi_{x}\left(y,z\right)\). שימו לב – גם \(y\) וגם \(z\) מייצגים וקטורים של משתנים, לא משתנים בודדים; כלומר, אני משתמש בכתיב הזה בתור קיצור לכתיב \(\varphi_{x}\left(y_{1},\dots,y_{n},z_{1},\dots,z_{k}\right)\) שתסכימו איתי שהוא מסורבל יותר. הרעיון הוא שלמשתני העזר הללו לא יהיה חופש בחירה: בהינתן השמה כלשהי ל-\(y\)-ים, תהיה בדיוק דרך אחת שבה אפשר לתת ערכים ל-\(z\)-ים אם אנחנו מקווים להצליח לספק את הפסוק; כל דרך אחרת שבה נציב ערכים ב-\(z\)-ים אוטומטית תגרום לכך שהפסוק לא יסתפק על ידי ההשמה הזו.

כדי להבין איך נראה חישוב של \(M\) צריך להיזכר בפרטים הטכניים של איך נראית מכונת טיורינג. יש למכונה סרט אינסופי שמחולק לתאים, כשבכל תא יכול להיות סימבול מתוך קבוצת סימבולים שנקראית אלפבית הסרט, \(\Gamma\). בנוסף יש למכונה ראש קורא וכותב שבכל רגע נתון נמצא מעל תא אחד בסרט, ומחובר למערכת בקרה שיכולה להימצא במצבים פנימיים שונים ומשונים מתוך קבוצה סופית \(Q\) של מצבים. כל רגע נתון בחישוב ניתן לתיאור מלא באמצעות שלושה פרטים: המצב הפנימי הנוכחי של המכונה; המיקום של הראש; התוכן הנוכחי של הסרט. שלשה כזו נקראת קונפיגורציה וחישוב של מכונת טיורינג הוא סדרה של קונפיגורציות, שכל אחת מתקבלת מקודמתה בהתאם לפונקצית המעברים של המכונה; זו פונקציה \(\delta:Q\times\Gamma\to Q\times\Gamma\times\left\{ L,R,S\right\} \) שלכל זוג \(\left(q,\sigma\right)\) של "המצב הפנימי הנוכחי \(q\) והתו \(\sigma\) שהראש כרגע קורא" מתאימה שלשה \(\left(p,\tau,X\right)\) שמשמעותה "עבור למצב \(p\); כתוב \(\tau\) על הסרט במקום \(\sigma\); והזז את הראש בהתאם ל-\(X\) (כאשר ימינה זה \(R\), שמאלה זה \(L\) והישארות במקום זה \(S\))".

מכונה יכולה להיכנס למצב פנימי מיוחד שמסומן ב-\(q_{acc}\) שמשמעותו שהיא עצרה ואמרה "כן"; באופן דומה המצב \(q_{no}\) אומר שהמכונה עצרה ואמרה "לא". קונפיגורציה שבה זה המצב הפנימי של המכונה נקראת קונפיגורציה סופית. פרט לכך יש גם קונפיגורציה התחלתית מוסכמת – זו שבה כל הסרט ריק פרט לקלט של המכונה (במקרה שלנו, הזוג \(x,y\)), הראש הקורא נמצא בקצה השמאלי של הסרט (הקצה הימני לא קיים; זו המשמעות של האינסופית של הסרט) והמצב הפנימי של המכונה הוא איבר מיוחד של \(Q\) שמסומן לרוב ב-\(q_{0}\).

אז השאלה שלנו היא זו: האם קיימת למכונה סדרת קונפיגורציות חוקיות כך שהקונפיגורציה ההתחלתית מתאימה לקלט \(x,y\), והסדרה מסתיימת בקונפיגורציה סופית מקבלת? המשתנים \(z\) שלנו הולכים לקודד את סדרת הקונפיגורציות הזו.

עכשיו, לכאורה יש לנו בעיה כאן – איך נייצג קונפיגורציה, שהרי היא אינסופית? וכמו כן, גם סדרת הקונפיגורציות עשויה להיות באורך לא חסום. כאן נחלצת לעזרתנו העובדה ש-\(M\) היא פולינומית. זה אומר שקיים פולינום \(p\left(n\right)\) כך שמספר הצעדים המקסימלי ש-\(M\) מבצעת על \(x,y\) הוא \(p\left(\left|x\right|\right)\). זה אומר שמספיק לנו להסתכל על \(p\left(\left|x\right|\right)+1\) התאים הראשונים של הסרט, כי \(M\) לא תגיע רחוק יותר, ועל סדרת קונפיגורציות מאורך \(p\left(\left|x\right|\right)+1\) כי \(M\) לא תבצע חישוב ארוך יותר. בואו נסמן \(m=p\left(\left|x\right|\right)+1\) אם כך.

כדי לעשות לעצמי את החיים קלים יותר, אני הולך להניח כמה הנחות מקלות על \(M\). ראשית, שהיא מבצעת בדיוק \(p\left(\left|x\right|\right)\) צעדים, בלי תלות בערך של \(y\), ובצעד האחרון עוברת לקונפיגורציה סופית. זה יחסוך לי את הטורח של לבדוק האם המכונה נעצרה בקונפיגורציה מוקדמת יותר מהאחרונה (זה לא טורח גדול, ועדיין). למה אפשר להניח את זה? כי קל לקחת את \(M\) שנתונה לי ולשנות קצת את הקידוד שלה כך שאם היא התכוונה להיכנס למצב סופי, היא "תתאפק קצת" ותחכה. לשם כך היא צריכה לתחזק מונה שסופר את הצעדים שלה וכדומה, אבל אפשר לעשות דברים כאלו עם מכונות טיורינג. זה מגדיל קצת את זמן הריצה – משנה את הפולינום \(p\) – אבל זמן הריצה עדיין יהיה פולינומי. באופן דומה, אני אניח שה-\(y\)-ים שהמכונה יכולה לקבל יחד עם \(x\) לא ארוכים מדי הם כולם מאותו האורך (אם זה מטריד אתכם תחשבו על כך שהמכונה יכולה לרוץ על כל הרישות של ה-\(y\) שקיבלה) וש-\(p\) גדול דיו כך שיש מקום ל-\(x,y\) על \(m\) התאים הראשונים של הסרט (על פניו הרשיתי ל-\(y\) להיות ארוך יותר, אבל אם המכונה לא תספיק לקרוא את כל התאים של \(y\) אפשר להחליף אותו ברישא של עצמו).

האינטואיציה עכשיו היא שלכל \(1\le i,j\le m\) יהיה לנו משתנה \(z_{i,j}\) שאומר מה נמצא בתא ה-\(j\) בסרט בקונפיגורציה ה-\(i\)-ית; חשבו על זה בתור טבלה גדולה שבה השורות הן הקונפיגורציות, והעמודות הן התאים האינדיבידואליים בסרט. אני ארצה לכתוב דברים כמו \(z_{i,j}=\sigma\) כדי לומר שיש את האות \(\sigma\) בתא הזה. והנה מגיע טריק נחמד: אני יכול "לדחוף פנימה" גם את שני הפרמטרים הנוספים של הקונפיגורציה – המיקום של הראש והמצב הפנימי של המכונה. אם, למשל, בקונפיגורציה \(i\) הראש מצביע על התא \(j\), המצב הפנימי הוא \(q\) ותוכן התא הזה הוא \(\sigma\), אז במקום \(z_{i,j}=\sigma\) המשתנה יגיד \(z_{i,j}=\left(q,\sigma\right)\). כלומר, הטבלה בגודל \(m\times m\) שלי מקודדת את כל המידע הדרוש על הקונפיגורציות.

אבל הנה בעיה: המשתנים שיש לי בפסוק CNF לא יכולים לקודד סימבולים מסובכים. הם בסך הכל יכולים לקבל ערכים של T ו-F. אלו משתנים בוליאניים. אז מה עושים? הפתרון לא מסובך במיוחד וסטנדרטי עבור מי שרגיל לקודד דברים עם CNF-ים; חלק מהקושי בהוכחה של משפט קוק-לוין ללא ספק נובע מכך שרוב מי שרואים אותו לא רגילים עדיין לשום דבר מסוג זה.

פתרון אחד הוא להתייאש ולתהות למה קוק טרח מלכתחילה להתעסק עם SAT ולא עם שפה גמישה קצת יותר. זו תשובה לגיטימית ויש ספרי לימוד שאכן משתמשים בוריאציה יותר מתוחכמת על השפה לצורך המשפט. אבל אני חושב שכדאי להישאר עם SAT כי זה לא כזה נורא. הרעיון הוא כזה: עבור כל ערך אפשרי \(\gamma\) שעשוי להתקבל על ידי המשתנה \(z_{i,j}\) שלנו (כלומר, תו \(\sigma\) או ביטוי מסובך יותר כמו \(\left(q,\sigma\right)\)) יהיה לנו משתנה בוליאני \(z_{i,j}^{\gamma}\). הרעיון הוא איכשהו להבטיח שלכל \(i,j\), בדיוק אחד מבין המשתנים \(z_{i,j}^{\gamma}\) יקבל את הערך T, והמשמעות של זה תהיה \(z_{i,j}=\gamma\).

כדי להבטיח שלפחות אחד מבין המשתנים יקבל T, אנחנו מוסיפים לפסוק שאנו בונים את הפסוקית \(\bigvee_{\gamma}z_{i,j}^{\gamma}\), כלומר הפסוקית תכיל את כל המשתנים מהצורה \(z_{i,j}^{\gamma}\) עבור \(i,j\) קבוע וכל ה-\(\gamma\) האפשריים.

כדי להבטיח שלכל היותר אחד מבין המשתנים יקבל T, אני מוסיף הרבה פסוקיות מהצורה \(\neg z_{i,j}^{\gamma}\vee\neg z_{i,j}^{\gamma^{\prime}}\), לכל זוג \(\gamma\ne\gamma^{\prime}\) של ערכים אפשריים. פסוקית כזו אומרת "או ש-\(z_{i,j}\ne\gamma\) או ש-\(z_{i,j}\ne\gamma^{\prime}\)", כלומר, באופן שקול, "לא ייתכן שגם \(z_{i,j}=\gamma\) וגם \(z_{i,j}=\gamma^{\prime}\)".

יפה. אז מעכשיו אני יכול להשתמש בחופשיות בסימון \(z_{i,j}=\gamma\) כשבעצם ברור שהכוונה היא למשתנה \(z_{i,j}^{\gamma}\). מה שהשגתי עד כה הוא שבניתי פסוק שכל השמה שמספקת אותו מגדירה סדרה של \(m\) קונפיגורציות מאורך \(m\). מה נשאר לי לעשות? את הדברים הבאים:

  1. להבטיח שהקונפיגורציה הראשונה בסדרה היא הקונפיגורציה ההתחלתית של \(M\) על \(x,y\).
  2. להבטיח שהקונפיגורציה האחרונה בסדרה היא מקבלת.
  3. להבטיח שהמעבר בין כל שתי קונפיגורציות סמוכות הוא חוקי.

את \(1\) קל להבטיח. נסמן \(x=x_{1}\cdots x_{k}\) ו-\(y=y_{1}\cdots y_{n}\), ונוסיף לפסוק שלנו פסוקיות שאומרות \(z_{1,1}=\left(q_{0},x_{1}\right)\) (כן, יש כאן מקרה קצה אם \(x\) ריק; אני בטוח שתדעו להתמודד איתו בעצמכם) ו-\(z_{1,i}=x_{i}\) עבור \(i>1\) ו-\(z_{1,k+1}=,\) (שווה לסימן פסיק, או מה שזה לא יהיה שנשתמש בו בתור מפריד בין \(x\) ו-\(y\)) ו-\(z_{1,k+1+i}=y_{i}\). האחרון מעניין, כי ה-\(y_{i}\)-ים הם לא קבועים – הם בעצמם משתנים. איך מקודדים את זה? ובכן, אם תזכרו שניה מה הקיצורים שלי מסמנים, אני בעצם מוסיף את הפסוקיות שמקודדות את הטענות הבאות: \(z_{1,k+1+i}^{1}=y_{i}\) ו-\(z_{1,k+1+i}^{0}=\neg y_{i}\) (שימו לב שמספיק לטפל בערכים 0 ו-1 כי זה כל מה ש-\(y\) יודע לקבל). אז יש לנו כאן שאלה כללית יותר של קידוד CNF-ים – איך מקודדים \(x=y\)? בקלות, הפסוקיות \(\left(x\vee\neg y\right)\wedge\left(\neg x\vee y\right)\). ואיך מקודדים \(x=\neg y\)? בקלות, וזה נובע ממה שכבר ראינו: \(\left(x\vee y\right)\wedge\left(\neg x\vee\neg y\right)\).

את 2 גם כן קל להבטיח על ידי פסוקית ענק שבודקת אם במקרה יש לנו מצב מקבל בקונפיגורציה האחרונה: \(\bigvee_{i,\sigma}z_{m,i}=\left(q_{acc},\sigma\right)\) כאשר כאן אנחנו רצים גם על כל \(1\le i\le m\) וגם על כל \(\sigma\) אפשרי. יכלנו להניח עוד הנחות על המכונה כדי לפשט את החיים (למשל, שהיא חוזרת לתא הראשון בסרט ומרוקנת אותו לפני שהיא עוברת למצב מקבל) אבל הנוסחה פשוטה מספיק גם ככה לטעמי.

נשאר לנו רק 3, שהוא לב העניין. שימו לב שעד עכשיו הפסוק שבנינו היה פולינומי בגודלו – הוספנו רק מספר פולינומי של פסוקיות מגודל פולינומי (פולינומי בגודל של \(x\)). האתגר מגיע כשאנחנו רוצים להבטיח שכל שתי קונפיגורציות סמוכות מייצגות מעבר חוקי. על פניו יש המוני אפשרויות לזוגות כאלו ולכו תבדקו אותם ומהומה והצילו ולא מובטח על פניו שנקבל פסוק פולינומי שמקודד את כל המהומה הזו. לב לבו של העניין ושל כל המשפט נעוץ בכך שמכונת טיורינג היא מודל חישובי שמבצע שינויים לוקליים – בכל צעד חישוב, השינוי שעובר על תא אחד בקונפיגורציה לא מושפע מכל הקונפיגורציה הקודמת, אלא רק מכמה תאים בקונפיגורציה הקודמת. זה אומר שאם אני רוצה לכתוב את הערך של \(z_{i+1,t}\), אני צריך לכתוב פסוקיות שמחשבות כפונקציה של מספר מצומצם של משתנים \(z_{i,r}\). אם לחדד, כל תא יכול להיות מושפע רק מהתא שבשורה הקודמת ומשני שכניו של התא הזה. הנה דוגמה שתמחיש את זה.

נניח שאני תא מס' 8 בשורה 5 ואני רוצה לדעת מה אמור להיות הערך שלי, על פי מה שקורה בשורה 4. הנה התרחישים שאני צריך להתחשב בהם:

  1. הראש של המכונה היה בתא 8 בשורה 4. במקרה הזה, לא משנה מה הראש מחליט לעשות, תא 8 בשורה 5 יהיה פונקציה בלעדית של תא 8 בשורה 4.
  2. הראש של המכונה היה בתא 7 בשורה 4. במקרה הזה, ייתכן שהראש יחליט לפנות ימינה (להגדיל את מס' התא שלו ב-1) ואז תא 8 יפסיק להכיל \(\sigma\) ויעבור להכיל \(\left(q,\sigma\right)\) עבור \(q\) כלשהו.
  3. הראש של המכונה היה בתא 9 בשורה 4. במקרה הזה, ייתכן שהראש יחליט לפנות שמאלה וזה כמו במקרה הקודם.
  4. כל מיקום אחר של הראש גורר שהוא לא יוכל להשפיע בשום צורה על תא 8.

אם כן, לכל \(\gamma\), הערך של המשתנה \(z_{i,j}^{\gamma}\) נקבע לכל היותר על ידי המשתנים \(z_{i-1,j-1}^{\gamma^{\prime}}\), \(z_{i-1,j}^{\gamma^{\prime}}\) ו-\(z_{i-1,j+1}^{\gamma^{\prime}}\) עבור כל \(\gamma^{\prime}\) אפשרי. זו קבוצה לא קטנה של משתנים, אבל גם לא גדולה יותר מדי. יש בה שלושה איברים כפול מספר ה-\(\gamma^{\prime}\) האפשריים. כזכור, \(\gamma\) הוא או תו מאלפבית הסרט \(\Gamma\) או שהוא זוג של תו מאלפבית הסרט ומצב פנימי \(Q\) של המכונה. אז יש לנו בסך הכל \(\left|\Gamma\right|+\left|\Gamma\right|\left|Q\right|\) אפשרויות כאלו. לכן כל משתנה תלוי לכל היותר ב-\(3\left(\left|\Gamma\right|+\left|\Gamma\right|\left|Q\right|\right)\) משתנים אחרים. עכשיו מגיע נפנוף הידיים היחיד שאני מרשה לעצמי בהוכחה, כי הוא ברור לכל מי שמכיר קצת CNF-ים: כל קשר מהצורה \(a=f\left(b_{1},b_{2},\dots,b_{n}\right)\) כאשר \(f\) היא פונקציה בולינאנית אפשר לתאר באמצעות CNF, במובן זה שלכל הצבה אפשרית של ערכים ל-\(b_{1},\dots,b_{n}\), הפסוק מסתפק אם ורק אם מציבים ב-\(a\) את \(f\left(b_{1},\dots,b_{n}\right)\). מה שעשיתי קודם, עם \(x=y\) היה מקרה פרטי פשוט של זה.

בכל זאת, אם אתם סקרנים, הנה הרעיון הכללי. \(a=f\left(b_{1},b_{2},\dots,b_{n}\right)\) זו פשוט דרך אחרת לכתוב פונקציה כללית יותר, \(g\left(a,b_{1},\dots,b_{n}\right)\), שמקבלת 1 כאשר \(a=f\left(b_{1},b_{2},\dots,b_{n}\right)\) ו-\(0\) אחרת. אז האתגר שלנו הוא רק לדעת איך כותבים CNF עבור פונקציה בוליאנית כללית. לצורך כך קל יותר לחשוב על איך כותבים DNF, שהוא המושג הדואלי ל-CNF: זה פסוק מהצורה \(C_{1}\vee\dots\vee C_{n}\) כאשר כל פסוקית היא מהצורה \(\left(l_{1}\wedge\dots\wedge l_{k}\right)\). פסוק כזה מקבל 1 אם ורק אם לפחות אחת מהפסוקיות מסתפקת; הרעיון הוא שכל פסוקית תתאים לשורה בטבלת האמת של \(g\). תוכן הפסוקית יתאים לערכים שהמשתנים של \(g\) מקבלים באותה שורה. למשל, אם \(g\left(x,y,z\right)\) היא פונקציה כך ש-\(g\left(1,0,1\right)=1\) אז הפסוקית שתתאים להשמה הזו תהיה \(x\wedge\neg y\wedge z\).

כעת, קל לראות שאם \(\varphi\) הוא פסוק DNF אז \(\neg\varphi\) הוא בעצם פסוק CNF בתחפושת – רק צריך להשתמש בכללי דה-מורגן כדי לדחוף את ה-\(\neg\) פנימה. למשל, בואו נכתוב DNF עבור \(x=y\): בבירור זה ה-DNF \(\left(x\wedge y\right)\vee\left(\neg x\wedge\neg y\right)\). עכשיו נפעיל \(\neg\) על הכל ונקבל:

\(\neg\left[\left(x\wedge y\right)\vee\left(\neg x\wedge\neg y\right)\right]\equiv\neg\left(x\wedge y\right)\wedge\neg\left(\neg x\wedge\neg y\right)\equiv\left(\neg x\vee\neg y\right)\wedge\left(\neg\neg x\vee\neg\neg y\right)\equiv\left(\neg x\vee\neg y\right)\wedge\left(x\vee y\right)\)

וקיבלנו CNF עבור השלילה של \(x=y\), כלומר עבור \(x\ne y\). המסקנה: אם אני רוצה למצוא CNF עבור \(g\), בואו נמצא DNF עבור \(\neg g\) ואז נפעיל עליו \(\neg\).

כמובן, נשאלת השאלה מה גודל ה-CNF הזה. התשובה היא שהוא עשוי להיות ענקי. אקספוננציאלי במספר המשתנים של \(g\). כך גם אצלנו – הגודל של הפסוקיות שאני מוסיף עבור כל תא \(z_{i,j}\) שאני רוצה לתאר את הפונקציה שלו עשוי להיות אקספוננציאלי. אבל אקספוננציאלי במה? במספר שחישבתי קודם, \(3\left(\left|\Gamma\right|+\left|\Gamma\right|\left|Q\right|\right)\). המספר הזה אינו תלוי בגודל הקלט \(x\) שאנחנו עושים עבורו את הרדוקציה; זה קבוע שמתאר את המורכבות של המכונה עבור \(L\) ותו לא.

מכאן אנחנו לומדים שני דברים: ראשית, שהרדוקציה של משפט קוק-לוין היא פולינומית; שנית, שזה לא אומר שיהיה קל לממש אותה בפועל עבור מכונות מסובכות; ה-CNF המתקבל עשוי להיות מפלצתי בגודלו למרות זאת.

האם סיימנו את ההוכחה? באופן מפתיע למדי, כן! קיבלנו פסוק \(\varphi_{x}\left(y,z\right)\) כך שלכל הצבה של ערכים ל-\(y\), מתקיים אחד משניים: אם \(M\) מקבלת את \(x,y\), אז קיימת הצבה (יחידה) של ערכים ל-\(z\) שמספקת את \(\varphi_{x}\left(y,z\right)\); ואם \(M\) דוחה את \(x,y\) אז כל הצבה של ערכים ל-\(z\)-ים לא תספק את \(\varphi_{x}\). כלומר, \(\varphi_{x}\) הוא ספיק אם ורק אם \(x\in L\). יותר מכך – יוצא שמספר ההשמות המספקות של \(\varphi_{x}\) שווה למספר ה-\(y\)-ים שעבורם \(M\) מקבלת את \(x,y\) (מספר ה"הוכחות" השונות של \(x\)). השוויון הזה מעניין כי הוא מצביע על השימושיות האפשרית של משפט קוק-לוין גם בטענות מתוחכמות יותר מסתם "SAT היא NP-שלמה", ואכן בנושאים מתקדמים יותר בסיבוכיות עושים וריאציות שכאלו על קוק-לוין כל הזמן; אבל אני אסתפק במה שהראיתי ואעצור כאן.

התעלומה המסתורית של הנער המבריק, יחס הזהב והנוסחה השגויה במוזיאון

העיתונים – גם אתר Nrg, אבל גם אתרים לא ישראליים – מספרים סיפור יפה. נער בן 15 (יהודי, טורחים לציין ב-Nrg, איך לא) מבקר במוזיאון המדע בבוסטון. מגיע לתערוכה על מתמטיקה, ומזהה שם משוואה שנראית לו – הצעיר המבריק – לא נכונה. הוא מודיע למוזיאון, ובכך מתקן שגיאה בת 35 שנים. נפלא! צעיר מבריק! עתיד מבטיח! כל הכבוד!

האמת העגומה היא שהסיפור הזה לא נכון. הנער בן ה-15 אכן ביקר במוזיאון וראה משהו שנראה לו כמו שגיאה והודיע על כך, והמוזיאון גם אמר שיתקן, אבל חיש קל התברר שבעצם לא הייתה פה שום שגיאה. פשוט, כפי שקורה לפעמים במתמטיקה, יש יותר מדרך אחת להציג דברים. הנער הכיר את אחת הדרכים, המוזיאון הציג דרך אחרת (מקובלת פחות, יש לציין), ומכאן והלאה התקשורת השתוללה.

אני לא הולך לדבר על הנער מכאן ואילך, כי אני לא רוצה להעביר עליו ביקורת, בטח כשאני לא יודע מה בדיוק הוא אמר; לי נראה שהוא דווקא יוצא טוב מכל הסיפור. הוא גם התעניין, גם בדק שמה שהוא מכיר אכן שונה ממה שנכתב במוצג במוזיאון, וגם התריע. אחלה! בגילו בכלל לא הכרתי את המושגים הרלוונטיים. אז הוא לא הבין שהטעות אינה באמת טעות, אז מה? זה לא מתפקידו לדעת את זה; אם כבר, המוזיאון יצא מוזר מאוד בכך שמיהר להגיד שיתקן את הטעות, והעיתונים יצאו עצלנים מאוד, כרגיל.

בואו נראה תמונה של המוצג, כפי שהנער צילם אותה:

golden_ratio_museum

כפי שאפשר להבין, התמונה עוסקת בקבוע מתמטי מפורסם ואהוב מאוד: יחס הזהב. מעולם לא כתבתי פוסט על יחס הזהב וגם כעת איני חש צורך לעשות את זה, כי לדעתי זה יחס שזוכה ליותר מדי תשומת לב ומנסים למצוא אותו יותר מדי במקומות שלא לגמרי קשורים. עם זאת, הוא צץ במתמטיקה במספר הקשרים נחמדים, ולכן יצא לי כבר לכתוב פוסטים על נושאים שבהם הוא הופיע: למשל זה, זה וזה. כיאה למספר שמופיע במקומות שונים רבים, יש כמה דרכים שונות להגדיר אותו. הנה אחת שמשתמשת במוצג שבתערוכה: מלבן זהב (Golden Rectangle). הרעיון במלבן זהב הוא פשוט ויפה: זה מלבן שאם מפרקים אותו לריבוע ומלבן נוסף, המלבן החדש שקיבלנו הוא בעל אותן פרופורציות כמו המלבן שממנו התחלנו (כלומר, היחס בין הצלע הארוכה והקצרה במלבן החדש שווה לזה של המלבן הישן). מהן הפרופורציות הללו? ובכן, זה תרגיל חשבוני קל. נסמן את הצלע הארוכה של המלבן ב-\(x\) ואת הצלע הקצרה שלו ב-1, כך שהיחס שאנחנו מחפשים הוא בדיוק \(x\); אז הריבוע שאנחנו גוזרים מהמלבן הוא בעל אורך צלע 1, ולכן המלבן החדש שנקבל יהיה בעל צלעות מאורך \(1\) (הארוכה) ו-\(x-1\) (הקצרה). אם הפרופורציות שוות, אז קיבלנו את המשוואה \(\frac{x}{1}=\frac{1}{x-1}\), שממנה מקבלים את המשוואה הריבועית \(x^{2}-x-1=0\) (בניסוח קצת יותר נוח, \(x^{2}=x+1\)).

golden_rectangle

את המשוואה הזו אפשר לפתור עם נוסחת השורשים, ומקבלים את הפתרונות \(\frac{1\pm\sqrt{5}}{2}\). מכיוון ש-\(\sqrt{5}\) הוא גדול מ-1, פתרון אחד יוצא שלילי ופתרון אחר יוצא חיובי. הפתרון החיובי מסומן ב-\(\phi\) (האות היוונית פי קטנה), והוא שווה ל-\(1.6180\dots\), כאשר שלוש הנקודות פירושן שהמספר ממשיך מכאן הלאה; אין להמשך חוקיות ברורה כי זה מספר אי רציונלי ולכן לא ניתן להצגה מחזורית (אבל יש לו הצגה מחזורית פשוטה במיוחד בתור שבר משולב; לא נדבר על זה כאן).

אם כן, \(\phi=\frac{1+\sqrt{5}}{2}\). מה ראה הנער במוזיאון? מוצג שכנראה מנסה להדגים איך ניתן לבנות מלבן זהב בעזרת סרגל ומחוגה. קשה לראות את הטכניקה עצמה בתמונה. הנה הסבר שנלקח מויקיפדיה העברית:

Golden_Rectangle_Construction.svg

בנייה של מלבן זהב:
1. בנה ריבוע שצלעו יחידה.(מודגש באדום)
2. חצה אותו לשני מלבנים.
3. השתמש באלכסון של אחד המלבנים כרדיוס לבניית מלבן הזהב

הנער ראה שבכיתוב במוזיאון כותבים \(\frac{\sqrt{5}-1}{2}\) בתור \(\Phi\), וקפצה לו נורת אזהרה לראש כי מה זה המינוס הזה, הרי יחס הזהב הוא \(\frac{\sqrt{5}+1}{2}\). גם אני נוהג לחפש טעויות כשאני מסתכל על מוצגים מתמטיים במוזיאון (כי נושא טוב לבלוג!) ויכול להבין מה עבר לו בראש. הפספוס שלו הוא הטקסט הקצת מוזר שכתוב במוצג: היחס בין הצלע הקצרה של המלבן והארוכה הוא \(\frac{\sqrt{5}-1}{2}\).

נזכיר: יחס הזהב הוא היחס בין הצלע הארוכה והקצרה, לא הקצרה והארוכה. אם יש לי צלע מאורך 6 וצלע מאורך 3, אז היחס בין הארוכה והקצרה הוא 2, בזמן שהיחס בין הקצרה והארוכה הוא \(\frac{1}{2}\). דהיינו, המספר שהם כתבו במוצג הוא לא \(\phi\) אלא \(\frac{1}{\phi}\). אלא שחישוב קצר יראה לכם שבאמת מתקיים \(\frac{1}{\phi}=\frac{\sqrt{5}-1}{2}\): פשוט תכפלו את \(\phi\) ב-\(\frac{\sqrt{5}-1}{2}\) ותקבלו \(\frac{5-1}{4}\). בקיצור, אין טעות בכיתוב.

אבל רגע, מה עם הסימן \(\Phi\)? יש לכל הפחות טעות בסימן, לא? ובכן, כך גם אני חשבתי הבוקר כשראיתי את הידיעה, אבל מסתבר שטעיתי – הסימון \(\Phi\) הוא דווקא סימון מקובל עבור \(\frac{1}{\phi}\), לפחות אצל וולפרם (לא בדקתי את הרפרנסים שלו). שימו לב להבדל: \(\phi\) היא אות קטנה, בעוד \(\Phi\) היא אות גדולה (זו אותה האות ביוונית – פי, phi). אז אפילו בסימון הזה הכיתוב צודק.

אני לא מתלונן, כמובן; כל דבר שמעלה את המתמטיקה לכותרות זה אחלה. עדיין, יש שני דברים שמעצבנים אותי בדיווח הזה. ראשית, הוא תורם לסטריאוטיפ של "רק גאונים יכולים להתעסק במתמטיקה", כי הנה, הייתה טעות במוזיאון במשך עשרות שנים שחיכתה שיבוא הגאון (ונער הוא תמיד גאון יותר מוצלח ממבוגר; ויהודי, אז בכלל) שיגלה אותה. סתם אנשים לא יכולים להבין (וכמובן, כמעט בשום מקום לא מראים מה הייתה הטעות בכלל). הדבר השני שמעצבן אותי הוא הניסוחים המקושקשים לגמרי שכתב Nrg הרשה לעצמו להשתמש בהם (בכתבות לא מהארץ שקראתי על הנושא הניסוחים היו טובים בהרבה):

במשך 35 שנים עמדו מבקרים במוזיאון המדע בבוסטון מול התערוכה "מתמטיקה – עולם של מספרים, ומעבר לכך" וניסו לפתור את המשוואות המתמטיות שהציגה התערוכה. מרביתם נתקלו בקשיים רבים, עד שהגיע תלמיד התיכון היהודי ג'וזף רוזנפלד בן ה-15 וגילה כי אחת המשוואות לא ניתנת לפיתרון פשוט משום שהיא מכילה טעות.

איזה משוואה הייתה כאן לפתור? שום דבר! מה לא ניתן לפתרון כאן? שום דבר! אז למה, הו למה, כתב Nrg נחמד, למה אתה חייב להמציא דברים לא קשורים? אתה הרי מבין שאתה לא מבין על מה מדובר, ולא טרחת לברר פרטים מעבר למה שפורסם במקומות אחרים, אז בחייך, אל תתחיל להמציא שטויות. בקצב הזה עוד נגיע למסקנה שבעיתונות כותבים דברים לא נכונים.

אנליזה וקטורית – נגזרת ונגזרת חלקית

אחרי פוסט המבוא שבו הבטחתי גדולות ונצורות, בואו נעבור לאקשן. כאמור, אני מניח ידע קודם אצל הקוראים, הן באינפי של פונקציות ממשיות והן באלגברה לינארית (עד וכולל מכפלות פנימיות) כך שלא אציג מחדש את המושגים הללו. אלא אם יש ערך מוסף כלשהו בלהציג אותם מחדש. כמו למשל עכשיו! אני רוצה שנדבר שוב על מהי נגזרת של פונקציה ממשית.

האינטואיציה הסטנדרטית מאחורי נגזרת של פונקציה \(f:\mathbb{R}\to\mathbb{R}\) היא למצוא את "קצב השינוי הרגעי" של פונקציה בנקודה מסויימת \(a\in\mathbb{R}\). אינטואיציה סטנדרטית נוספת היא למצוא את המשיק לגרף הפונקציה באותה נקודה – קו ישר שבנקודה הזו הכיוון שלו הוא כמו הכיוון של הפונקציה. את "קצב השינוי הרגעי" לוקחים על ידי חישוב של קצב השינוי הממוצע לאורך פרק זמן, ואז מקטינים את פרק הזמן כך שהוא שואף לאפס; את המשיק מוצאים על ידי כך שמחשבים את המיתר בין גרף הפונקציה ב-\(a\) ונקודה נוספת \(b\), קרובה אליה, ואז אנחנו משאיפים את \(b\) אל \(a\). עבור האינטואיציה הראשונה, מה שאנחנו מוצאים הוא מספר ממשי; עבור האינטואיציה השניה מה שאנחנו מוצאים הוא פונקציה לינארית (קו ישר). הקשר בין השניים מיידי: המספר הממשי (המספר הנגזר) הוא השיפוע של הפונקציה הלינארית, שבתורה מכונה הדיפרנציאל של הפונקציה.

הפורמליזם של האינטואיציה הראשונה הוא זה:

\(f^{\prime}\left(a\right)=\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)}{h}\)

הביטוי \(\frac{f\left(a+h\right)-f\left(a\right)}{h}\) הוא בדיוק השינוי הממוצע בין ערך הפונקציה ב-\(a\) וערכה בנקודה אחרת \(b\), רק שבמקום לכתוב \(\frac{f\left(b\right)-f\left(a\right)}{b-a}\) יותר קל לסמן \(b=a+h\) ולהמשיך משם.

את הביטוי הזה באופן די ברור אי אפשר להכליל כמו שהוא. בואו ניקח פונקציה \(F:\mathbb{R}^{n}\to\mathbb{R}^{m}\) וננסה לכתוב את הביטוי הזה עבורה:

\(\lim_{h\to0}\frac{F\left(a+h\right)-F\left(a\right)}{h}\)

מה נשבר כאן? ובכן, \(h\) היא חלק מהקלט של \(F\), ולכן \(h\in\mathbb{R}^{n}\) היא וקטור. במונה אנחנו מקבלים את הפלט של \(F\), גם כן וקטור, רק שב-\(\mathbb{R}^{m}\). אנחנו לא יודעים איך לאכול את הביטוי הזה מבחינה מתמטית; אין לנו דרך לחלק וקטורים אלו באלו, למעט במקרה שבו \(n=1\) (וכפי שנראה בהמשך, המקרה שבו \(n=1\) הוא אכן פשוט במיוחד, גם אם \(m>1\)). אגב, כאן אנחנו מתפצלים מהאנליזה המרוכבת; שם מה שקורה הוא שמחלקים במספר מרוכב, שמצד אחד אמנם נראה כמו וקטור דו ממדי של מספרים ממשיים, ומצד שני במרוכבים כן ידוע לנו איך לבצע את החלוקה.

דרך אפשרית להתמודד עם הבעיה הזו היא לא לחלק ב-\(h\) אלא בנורמה של \(h\), כלומר ב-\(\left|h\right|\). בדרך הזו נקבל "נגזרת" שהיא וקטור ב-\(\mathbb{R}^{m}\) ולא לגמרי ברור מה היא אומרת – חסרה לנו אינטואיציה.

אז בואו נעבור להגדרה השניה, עם המשיק. אמרנו ש-\(f^{\prime}\left(a\right)\) הוא השיפוע של המשיק, כלומר המשיק הוא הפונקציה \(f^{\prime}\left(a\right)\left(x-a\right)+f\left(a\right)\) (זו גאומטריה אנליטית: אם יש לנו ישר עם שיפוע \(m\) שעובר דרך \(\left(a,b\right)\) אז משוואותו היא \(y=m\left(x-a\right)+b\)). החלק שמעניין אותנו במשיק הוא הפונקציה \(T\left(x\right)=f^{\prime}\left(a\right)x\) – זו טרנספורמציה לינארית (המשיק עצמו איננו טרנספורמציה לינארית באופן כללי כי הוא לא עובר דרך ראשית הצירים). לחלק הזה אנחנו קוראים הדיפרנציאל של \(f\) בנקודה \(a\). כדי לראות למה הוא מעניין, בואו נחזור אל הנוסחה:

\(f^{\prime}\left(a\right)=\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)}{h}\)

נעביר אגפים:

\(\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)}{h}-f^{\prime}\left(a\right)=0\)

נעלה למונה:

\(\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)-f^{\prime}\left(a\right)h}{h}=0\)

וקיבלנו:

\(\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)-T\left(h\right)}{h}=0\)

אז הנה הגדרה אלטרנטיבית: הדיפרנציאל של \(f\) הוא הטרנספורמציה הלינארית \(T\) שעבורה הגבול לעיל שווה לאפס. אפשר עם קצת עבודה להוכיח שאם קיימת טרנספורמציה לינארית כזו, אז היא יחידה, כך שההגדרה הגיונית.

את ההגדרה הזו אפשר להכליל בצורה פשוטה לפונקציות כלליות: אם \(F:\mathbb{R}^{n}\to\mathbb{R}^{m}\) אז הדיפרנציאל של \(F\) בנקודה \(a\), אם הוא קיים, הוא הטרנספורמציה הלינארית היחידה שמקיימת

\(\lim_{h\to0}\frac{f\left(a+h\right)-f\left(a\right)-T\left(h\right)}{\left|h\right|}=0\)

אם הדיפרנציאל קיים, אז אומרים ש-\(f\) גזירה בנקודה \(a\). במילה נגזרת משתמשים כדי לתאר או את \(T\) או את המטריצה המייצגת שלה; זה לא כל כך משנה כי ברור לנו שבמובנים המהותיים זה בדיוק אותו דבר. אם כן, עבור פונקציות ממשיות רגילות, הנגזרת היא בעצם מטריצה \(1\times1\)!

הסימון המקובל לנגזרת של \(f\) בהקשר הזה הוא \(Df\left(a\right)\) (אם רוצים, אפשר לחשוב על \(D\) בתור אופרטור שלוקח את \(f\) ומחזיר פונקציה שלכל \(a\) מחזירה מטריצה/טרנספורמציה). שימו לב לאופן שבו כללי המשחק השתנו קצת ממה שהיה עם פונקציות ממשיות: בפונקציות ממשיות, \(Df\) הוא פונקציה ממשית (שמקבלת \(a\) ומחזירה את המטריצה \(1\times1\) שדיברתי עליה, שגם היא מספר ממשי) ולכן אפשר היה לגזור שוב ושוב ושוב. כאן בבירור זה לא עובד ואין משמעות לסימון \(DDf\), מה שאולי מעלה אצלכם את התהיה אם אי אפשר להגדיר גם נגזרות "רגילות" על פונקציות שכאלו.

אז בואו נתחיל עם דוגמה פשוטה ככל הניתן. פונקציה סקלרית (שמחזירה סקלר, כלומר הטווח שלה הוא ממימד 1) על המישור, \(f:\mathbb{R}^{2}\to\mathbb{R}\). למשל, \(f\left(x,y\right)=x\sin y\). אין לנו מושג כרגע איך למצוא לה את הנגזרת, אבל כל אחד מאיתנו שמיומן בגזירה כן יודע להתעלל בביטוי \(x\sin y\): אם נחשוב לרגע על \(y\) כפרמטר ועל \(x\) בתור משתנה, ברור לנו איך אפשר לגזור את הביטוי הזה. פורמלית, אם אני אסמן \(f_{y}\left(x\right)=x\sin y\) אז קל לי לחשב את \(f_{y}^{\prime}\left(x\right)=\sin y\). קל גם לחשב את \(f_{x}^{\prime}\left(y\right)=x\cos y\). הנגזרות הללו נקראות נגזרות חלקיות של \(f\), כי במובן מסויים אנחנו גוזרים רק חלק מ-\(f\). עבור פונקציות במספר קטן של משתנים, נהוג להשתמש בסימן \(\partial\) לתיאור נגזרת חלקית, כמו שמשתמשים ב-\(d\) לתיאור נגזרת של פונקציה ממשית: דהיינו, אם מסמנים \(\frac{df}{dx}\) בתור הנגזרת של הפונקציה \(f\left(x\right)\), אז מסמנים \(\frac{\partial f}{\partial x},\frac{\partial f}{\partial y}\) לתיאור שתי הנגזרות החלקיות של \(f\left(x,y\right)\). זה סימון מאוד ידוע ופופולרי, אבל אני בקושי אשתמש בו, כי עבור פונקציות בעלות מספר שרירותי הוא הופך למסורבל. נאמר ש-\(F\left(x_{1},\dots,x_{n}\right)\) היא פונקציה סקלרית . אז במקום לכתוב \(\frac{\partial F}{\partial x_{i}}\) כבר יותר קל לכתוב \(D_{i}F\) וחסל.

אז בואו נדבר על נגזרות חלקיות של פונקציה כללית, אבל לא כללית עד הסוף – אני אמשיך לדבר על פונקציות סקלריות, שהטווח שלהן הוא ממימד אחד. באופן כללי, אם \(F:\mathbb{R}^{n}\to\mathbb{R}^{m}\), אז נהוג לפרק אותה לרכיבים: לסמן \(F=\left(f_{1},\dots,f_{m}\right)\) כך ש-\(f_{i}:\mathbb{R}^{n}\to\mathbb{R}\) היא פונקציה סקלרית. את רוב התוצאות שנדבר עליהן אפשר לתאר עבור פונקציה סקלרית, ודי מובן מאליו איך "להרכיב" אותן עבור פונקציה כללית – עוד נעשה את זה, אבל כאמור, בואו נדבר רק על פונקציות סקלריות לרגע.

מצד אחד, אין דבר טבעי יותר מנגזרת חלקית עבור פונקציה בכמה משתנים. מצד שני, זו הגדרה שנראית צרה באופן כמעט שרירותי. הרי נגזרת חלקית היא מה שמקבלים כאשר מסתכלים על הפונקציה במקום על כל המרחב שבו היא מוגדרת, רק על ישר אחד, שבו היא נראית כמו פונקציה במשתנה יחיד עם פרמטרים – או ציר \(x\), או ציר \(y\) וכדומה. אבל אפשר להסתכל עליה גם על כל ישר אחר. זה מוביל אותנו להגדרה של נגזרת מכוונת: אם \(0\ne u\in\mathbb{R}^{n}\) הוא וקטור כלשהו שונה מאפס ב-\(\mathbb{R}^{n}\) ו-\(F:\mathbb{R}^{n}\to\mathbb{R}\) היא פונקציה, אז אפשר להגדיר את הנגזרת המכוונת של \(F\) עבור \(u\) בנקודה \(a\) בתור

\(\lim_{h\to0}\frac{F\left(a+hu\right)-F\left(a\right)}{h}\)

כאשר כאן \(h\in\mathbb{R}\) הוא סקלר. הנגזרות החלקיות הן מקרה פרטי של נגזרות מכוונות, עבור וקטורי הבסיס \(e_{i}=\left(0,\dots,1,\dots,0\right)\) של המרחב \(\mathbb{R}^{n}\) (שימו לב ש-\(u\) הוא חשוב, ולא רק הכיוון שלו; הכפלה של \(u\) בסקלר כלשהו תשפיע גם על הנגזרת המכוונת שהוא מגדיר. לכן לפעמים דורשים ש-\(u\) יהיה מנורמה 1).

עכשיו אפשר לחבר את כל המושגים הללו ביחד. ניקח \(F:\mathbb{R}^{n}\to\mathbb{R}\). אם \(F\) גזירה, אז כל הנגזרות המכוונות שלה קיימות, וקל מאוד לקבל אותן – הנגזרת המכוונת בכיוון \(u\) בנקודה \(a\) היא בדיוק \(DF\left(a\right)\cdot u\) – כלומר, לוקחים את המטריצה שמייצגת את \(DF\) בנקודה \(a\) ומכפילים סקלרית ב-\(u\) (מטילים על \(u\)). כלומר, \(DF\) מקודדת איכשהו את המידע על כל הנגזרות המכוונות של \(F\). מצד שני, זה אומר שעכשיו ברור לגמרי איך לחשב את \(DF\): אנחנו יודעים ש-\(DF\left(a\right)\) הוא וקטור ב-\(\mathbb{R}^{n}\) (מטריצה \(1\times n\)) ולכן ניתן להצגה כצירוף לינארי \(\sum_{i=1}^{n}\lambda_{i}e_{i}\), כאשר המקדמים נתונים בדיוק על ידי \(\left(a\right)\cdot e_{i}\)\(\lambda_{i}=DF\). מסקנה: \(DF\left(a\right)=\left(D_{1}F\left(a\right),\dots,D_{n}F\left(a\right)\right)\). הוקטור הזה כל כך חשוב שנותנים לו עוד סימון ושם: הוא נקרא הגרדיאנט של \(F\) ומסומן \(\nabla F\) (למשולש הזה קוראים נבלה, אם רציתם לדעת).

ההוכחה של הטענה הזו היא קלה למדי ומראה כמה היא מתבקשת. נניח ש-\(F\) גזירה ויהא \(u\) וקטור שונה מאפס כלשהו. אנחנו רוצים להראות ש-\(\lim_{h\to0}\frac{F\left(a+hu\right)-F\left(a\right)}{h}=DF\left(a\right)\cdot u\). כזכור, על פי הגדרת הנגזרת, \(\lim_{t\to0}\frac{F\left(a+t\right)-F\left(a\right)-DF\left(a\right)\cdot t}{\left|t\right|}=0\) (בהוכחה הזו \(h\) הוא סקלר ו-\(t\) הוא וקטור). מכיוון שהגבול הזה נכון עבור השאפה של \(t\) כללי לאפס, הוא נכון גם אם משאיפים את \(t\) לאפס רק לאורך ציר מסויים, הציר שמגדיר \(u\) (למי שלא מאמין, פשוט תפתחו את הגדרת האפסילון-דלתא ותראו). כלומר, אנחנו מקבלים את הגבול

\(\lim_{h\to0}\frac{F\left(a+hu\right)-F\left(a\right)-DF\left(a\right)\cdot\left(hu\right)}{\left|hu\right|}=0\)

נכפול את שני האגפים בקבוע \(\left|u\right|\), נשתמש בהומוגניות של מכפלה סקלרית ושל נורמה, ונקבל

\(\lim_{h\to0}\frac{F\left(a+hu\right)-F\left(a\right)}{\left|h\right|}-\frac{h}{\left|h\right|}DF\left(a\right)\cdot u=0\)

אם \(h\) שואף לאפס מימין, אנחנו מקבלים בדיוק את מה שרצינו: \(\lim_{h\to0^{+}}\frac{F\left(a+hu\right)-F\left(a\right)}{h}-DF\left(a\right)\cdot u=0\); אחרת, נכפול במינוס 1 ונקבל \(\lim_{h\to0^{-}}\frac{F\left(a+hu\right)-F\left(a\right)}{h}-DF\left(a\right)\cdot u=0\). המסקנה הסופית היא שאכן מתקיים \(\lim_{h\to0}\frac{F\left(a+hu\right)-F\left(a\right)}{\left|h\right|}=DF\left(a\right)\cdot u\).

אם כן, אם \(F\) היא גזירה, אז הנגזרת שלה נתונה בדיוק באמצעות הנגזרות החלקיות, מה שאומר שיש לנו עכשיו טכניקה פרקטית לחישוב נגזרת כללית על ידי רדוקציה לבעיה של חישוב נגזרת רגילה. מה שמפתיע הוא שההפך אינו נכון – ייתכן שכל הנגזרות החלקיות יהיו קיימות (או אפילו יותר מכך, כל הנגזרות המכוונות יהיו קיימות) ועדיין \(F\) לא תהיה גזירה. הגרדיאנט עדיין יהיה קיים, כמובן, אבל הוא לא יגדיר טרנספורמציה לינארית שמקרבת את \(F\) בצורה מוצלחת. הפתולוגיה הזו היא בדיוק הסיבה שבגללה הגדרנו נגזרת בצורה מוזרה שכזו במקום להתחיל מנגזרות חלקיות – התנאי של גזירות יותר חזק מהתנאי של קיום הנגזרות החלקיות. ההכללה לפונקציה \(F:\mathbb{R}^{n}\to\mathbb{R}^{m}\) קלה: \(F\) גזירה אם ורק אם כל הרכיבים שלה גזירים, ואם היא גזירה אז הנגזרת שלה היא המטריצה \(m\times n\) שהשורות שלה הן הגרדיאנטים של הרכיבים.

בואו נראה דוגמה לפונקציה \(f:\mathbb{R}^{2}\to\mathbb{R}\) שהגרדיאנט שלה קיים אבל היא לא גזירה:

\(f\left(x,y\right)=\begin{cases}0 & x=y=0\\\frac{x^{2}y}{x^{4}+y^{2}} & \mbox{else}\end{cases}\)

הרעיון כאן הוא ש-0 היא נקודה בעייתית עבור הפונקציה – הגדרנו את ערכה להיות 0 שם כי אם נקפיא את \(x\) או את \(y\) להיות 0 ונלך על הציר של המשתנה השני נקבל כל הזמן את הערך 0; אבל באותה מידה יכלנו להגדיר אותו להיות חצי, כי לאורך העקום \(\left(t,t^{2}\right)\) הערך של הפונקציה הוא \(\frac{1}{2}\). כלומר, אין דרך טובה להגדיר את \(f\) כך שתהיה רציפה בראשית הצירים, ולא קשה לראות שכמו עבור פונקציות ממשיות, גם במקרה שלנו גזירות של פונקציה בנקודה גוררת רציפות שלה בנקודה.

מצד שני, אפשר לחשב כל נגזרת מכוונת ב-\(\left(0,0\right)\) בלי קושי של ממש. בואו נעשה את זה לפי הגדרה. ניקח \(u=\left(a,b\right)\), ונחשב:

\(\lim_{h\to0}\frac{f\left(0+hu\right)-f\left(0\right)}{h}=\lim_{h\to0}\frac{\left(ha\right)^{2}\left(hb\right)}{\left(ha\right)^{4}+\left(hb\right)^{2}}\frac{1}{h}=\lim_{h\to0}\frac{a^{2}b}{h^{2}a^{4}+b^{2}}=\frac{a^{2}}{b}\)

כמובן, בהנחה ש-\(b\ne0\), אחרת נקבל \(0\). בפרט ברור שהנגזרות החלקיות בנקודה הזו הן 0. אז על פניו טרנספורמציית האפס אמורה להיות הנגזרת של הפונקציה; אבל מן הסתם היא לא עובדת, ולכן הפונקציה לא גזירה למרות שהנגזרות החלקיות קיימות. הלקח כאן הוא שהסתכלות "חד ממדית" על הפונקציה מפספסת אינפורמציה חשובה – אפשר לקחת פונקציה שהיא כמו הפיל בסיפור על הפיל והעיוורים; שאם נסתכל עליה מכיוון מסויים, נראה משהו אחד, אבל אם נסתכל עליה מכיוון אחר נראה משהו שונה לחלוטין, וכך גם עבור כל כיוון הסתכלות חד ממדי אפשרי. חייבים להסתכל על הכל "בבת אחת" כדי לא לפספס.

חישבתי את הנגזרות החלקיות בנקודה 0, אבל עבור נקודות אחרות אני יכול לחשב אותן על פי חוקי הגזירה של פונקציות ממשיות: נאמר, כדי לגזור את \(\frac{x^{2}y}{x^{4}+y^{2}}\) לפי \(x\) אני חושב על \(y\) בתור קבוע ומשתמש בכללי הגזירה של מנת פונקציות. אני מקבל \(\frac{2xy\left(x^{4}+y^{2}\right)-x^{2}y\left(4x^{3}\right)}{\left(x^{4}+y^{2}\right)^{2}}=\frac{2x^{5}y+2xy^{3}-4x^{5}y}{\left(x^{4}+y^{2}\right)^{2}}=\frac{2xy^{3}-2x^{5}y}{\left(x^{4}+y^{2}\right)^{2}}=\frac{2xy\left(y^{2}-x^{4}\right)}{\left(x^{4}+y^{2}\right)^{2}}\).

כששואפים ל-0 על צירי \(x,y\) מקבלים 0, אבל על הציר \(\left(2t,t^{2}\right)\) נקבל \(\frac{4t^{3}\left(t^{4}-16t^{4}\right)}{\left(3t^{4}\right)^{2}}=-5\frac{t^{7}}{t^{8}}=-\frac{5}{t}\)

והיצור הזה מתפוצץ כש-\(t\) שואף לאפס, כך שקיבלנו נגזרת חלקית לא רציפה. זה מרמז לנו מה בעייתי פה – נגזרות לא רציפות הן יצורים שמתנהגים בצורה מעצבנת. ואכן, מסתבר שתנאי מספיק לגזירות של פונקציה הוא שהנגזרות החלקיות שלה יהיו קיימות ורציפות. פונקציה כזו נקראת "גזירה ברציפות", ואומרים שהיא שייכת למחלקה \(C^{1}\) (באופן כללי, \(C^{k}\) היא מחלקת הפונקציות שגזירות \(k\) פעמים והנגזרות רציפות; ו-\(C^{\infty}\) היא מחלקת הפונקציות שגזירות מספר כלשהו של פעמים והנגזרות, מן הסתם, רציפות). לעתים קרובות נוח לנו מראש להגביל את הדיון רק לפונקציות שהן \(C^{1}\) ואז הכל מתנהג נחמד; אבל באופן כללי קיימים מקרים פתולוגיים שצריך להיות מודעים אליהם.

אז אם לסכם: אם \(F\) גזירה, אז נובע שכל הנגזרות החלקיות שלה קיימות – אבל זה לא אומר שהן רציפות. אם לעומת זאת כל הנגזרות החלקיות קיימות ורציפות, אז מובטח ש-\(F\) גזירה, אבל רק קיום הנגזרות החלקיות לא גורר רציפות. אם כן, הכרנו את הגיבורים של החלק הדיפרנציאלי של אנליזה וקטורית – הנגזרת והנגזרות החלקיות והמכוונות; וזמן טוב לעצור את הפוסט הזה הוא בדיוק אחרי ההוכחה שקיום נגזרות חלקיות רציפות גורר גזירות, כי זו לא הוכחה טריוויאלית.

פורמלית, הטענה שאני אוכיח היא זו: אם \(A\subseteq\mathbb{R}^{n}\) היא קבוצה פתוחה כך שלכל \(a\in A\) הנגזרות החלקיות של \(F\) קיימות ב-\(a\) ורציפות בה, אז \(F\) גזירה בכל נקודה של \(A\). "קבוצה פתוחה" היא קבוצה \(A\) כך שלכל \(a\in A\) קיים "כדור פתוח" סביב \(a\) שמוכל כולו ב-\(A\), כלומר יש \(\varepsilon>0\) כך ש\(\left|x-a\right|<\varepsilon\) גורר ש-\(x\in A\).

הרעיון הבסיסי פשוט: אם כל הנגזרות החלקיות של \(F\) קיימות, אנחנו יודעים בדיוק איך \(DF\left(a\right)\) אמור להיראות: \(DF\left(a\right)=\left(D_{1}F\left(a\right),\dots,D_{n}F\left(a\right)\right)\). לכן, בהינתן \(h\in\mathbb{R}^{n}\) כלשהו, \(DF\left(a\right)\cdot h=\sum D_{i}F\left(a\right)h_{i}\). היעד שלנו הוא להוכיח שמתקיים \(\lim_{h\to0}\frac{F\left(a+h\right)-F\left(a\right)-\sum D_{i}F\left(a\right)h_{i}}{\left|h\right|}=0\). אנחנו לא חייבים לטפל בכל \(h\) – מספיק לטפל בכל \(h\) שהוא קטן דיו כך שהכדור הפתוח ברדיוס \(h\) סביב \(a\) מוכל כולו ב-\(A\).

לשם כך אני ארצה לקבל תיאור אחר של \(F\left(a+h\right)-F\left(a\right)\), כזה שמשתמש בנגזרות החלקיות. האם זה מזכיר לכם משהו? זו סיטואציה דומה לזו של אחד מהמשפטים החשובים ביותר באינפי – משפט הערך הממוצע של לגראנז'. מכיוון שאני הולך להשתמש בו בהמשך, בואו נזכיר אותו. יש לנו פונקציה \(f:\left[a,b\right]\to\mathbb{R}\) שהיא גזירה לכל הפחות ב-\(\left(a,b\right)\) ורציפה על כל \(\left[a,b\right]\). השינוי הממוצע של \(f\) בכל הקטע הזה שווה בדיוק ל-\(\frac{f\left(b\right)-f\left(a\right)}{b-a}\). נגזרת, כזכור, היא תיאור של שינוי רגעי, ולכן כל עוד \(a,b\) מרוחקים זה מזה, לא מובטח שהנגזרת בנקודות הללו (אם היא בכלל קיימת) תתאר את השינוי הממוצע הזה. הקסם (ובעיני זה באמת קסם) הוא שקיימת בקטע נקודה שעבורה זה כן עובד: קיימת נקודה \(c\in\left(a,b\right)\) כך ש-\(\frac{f\left(b\right)-f\left(a\right)}{b-a}=f^{\prime}\left(c\right)\). דרך אחרת לחשוב על כך היא זו:\(f\left(b\right)-f\left(a\right)=\left(b-a\right)f^{\prime}\left(c\right)\), כלומר גודל השינוי של הפונקציה בקטע כולו יכול להיגזר מהשינוי הרגעי שלה ברגע נתון אחד – אבל כמובן, צריך לדעת איזה רגע.

הבעיה היא ש-\(F\left(a+h\right)-F\left(a\right)\) הוא לא ביטוי שאפשר להפעיל עליו ישירות את לגראנז', כי אנחנו לא ב-\(\mathbb{R}\) אלא ב-\(\mathbb{R}^{n}\). אבל כרגיל, אפשר לבצע מעין רדוקציה ל-\(\mathbb{R}\) על ידי פירוק הביטוי הזה לטור טלסקופי של איברים שכל אחד מהם יהיה חד-ממדי באופיו (טור טלסקופי הוא טור שכל האיברים בו מצמצמים זה את זה למעט הראשון והאחרון; למשל, אם נפתח את המכפלה \(\left(1+q+q^{2}+\dots q^{n}\right)\left(q-1\right)\) נקבל טור טלסקופי שאחרי צמצום יישאר ממנו רק \(q^{n+1}-1\), והופס קיבלנו את הנוסחה \(1+q+\dots+q^{n}=\frac{q^{n+1}-1}{q-1}\) לטור הנדסי).

בואו נכתוב את \(h\) במפורש רגע: \(h=\left(h_{1},h_{2},\dots,h_{n}\right)\). אפשר לתאר את \(h\) כסכום לפי הבסיס הסטנדרטי: \(h=\sum_{i=1}^{n}h_{i}e_{i}\). יהיה נוח לסמן "סכומים חלקיים" של \(a+h\) באופן הבא: \(p_{i}=a+\sum_{j=1}^{i}h_{j}e_{j}\) (כאשר \(p_{0}=a\), עם המוסכמה שלפיה הסכום הוא "ריק" אם האינדקס למעלה גדול מהערך ההתחלתי למטה). עכשיו קל לראות שמתקיים

\(F\left(a+h\right)-F\left(a\right)=F\left(p_{n}\right)-F\left(p_{n-1}\right)+F\left(p_{n-1}\right)-\dots-F\left(p_{1}\right)+F\left(p_{1}\right)-F\left(p_{0}\right)\)

זה טור טלסקופי שבו כל זוג של מחובר חיובי ואז שלילי, כלומר משהו מהצורה \(F\left(p_{i}\right)-F\left(p_{i-1}\right)\) מתאים לשני וקטורים שהם זהים, פרט לכך שקואורדינטה אחת במחובר החיובי היא \(h_{i}\) בעוד שמקבילתה במחובר השלילי היא 0; חשבו על כך כאילו אנחנו הולכים מהנקודה \(h\) אל הנקודה \(0\) "ציר אחד בכל פעם". אם אתם לא רואים את זה, ציירו את הנקודות \(\left(1,1,1\right),\left(0,1,1\right),\left(0,0,1\right),\left(0,0,0\right)\) והסתכלו על המסלול שעובר דרכן בסדר זה: תראו שקיבלנו קוביה שאנחנו הולכים על צלעות שלה. בואו נכתוב את הטור שוב, בסימון מקוצר:

אני הולך להשתמש בלגראנז' על \(F\left(p_{i}\right)-F\left(p_{i-1}\right)\), אבל מכיוון שהסימון אולי עדיין מבלבל, אני אכתוב את הכל במפורש בתור פונקציות ממשיות. נשתמש ב-\(t\) בתור משתנה שמייצג מספר ממשי. נגדיר \(f_{i}\left(t\right)=F\left(p_{i-1}+te_{i}\right)\) (כלומר, הרכיב ה-\(i\)-י הוא \(t\)). נסתכל על הקטע \(\left[0,h_{i}\right]\) (אם \(h_{i}\) שלילי אז צריך לכתוב את הקטע \(\left[h_{i},0\right]\), אבל זה לא באמת משנה). בגלל שבחרנו את \(h\) להיות קטן מספיק כך שהסביבה של \(a\) ברדיוס \(h\) מוכלת ב-\(A\), נקבל ש-\(F\left(p_{i-1}+te_{i}\right)\) מוגדרת לכל \(t\in\left[0,h_{i}\right]\), ומהנתון לגבי הנגזרות החלקיות, \(f_{i}\) היא גם גזירה ברציפות שם – כאן זה קריטי לחלוטין ש-\(f_{i}\) מקפיאה את כל הרכיבים למעט אחד.

עכשיו אפשר להשתמש בלגראנז' על \(f_{i}\) ולקבל שקיימת נקודה \(c_{i}\in\left[0,h_{i}\right]\) כך ש-\(f_{i}\left(h_{i}\right)-f_{i}\left(0\right)=h_{i}f_{i}^{\prime}\left(c_{i}\right)\). בואו נסמן ב-\(q_{i}\) את הנקודה המתאימה עבור \(F\), כלומר \(q_{i}=p_{i-1}+c_{i}e_{i}\). אז נקבל ש-\(F\left(p_{i}\right)-F\left(p_{i-1}\right)=D_{i}F\left(q_{i}\right)h_{i}\). הנה קיבלנו את הלגראנז' שלנו. אם נחזור אל הטור הטלסקופי ממקודם, קיבלנו ש-

\(F\left(a+h\right)-F\left(a\right)=\sum_{i=1}^{n}F\left(p_{i}\right)-F\left(p_{-1}\right)=\sum_{i=1}^{n}D_{i}F\left(q_{i}\right)h_{i}\)

נחזור עכשיו אל הגבול שאנחנו רוצים להוכיח:

\(\lim_{h\to0}\frac{F\left(a+h\right)-F\left(a\right)-\sum D_{i}F\left(a\right)h_{i}}{\left|h\right|}=0\)

נציב בו את מה שקיבלנו, ונקבל:

\(\lim_{h\to0}\frac{\sum D_{i}F\left(q_{i}\right)h_{i}-\sum D_{i}F\left(a\right)h_{i}}{\left|h\right|}=0\)

או, יותר פשוט

\(\lim_{h\to0}\sum\left(D_{i}F\left(q_{i}\right)-D_{i}F\left(a\right)\right)\frac{h_{i}}{\left|h\right|}=0\)

הנקודות \(q_{i}\) תלויות ב-\(h\); כאשר \(h\) שואף לאפס, הנקודות הללו שואפות ל-\(a\) (הוכיחו!). ומכיוון ש-\(D_{i}F\) רציפה, אז \(\lim_{q_{i}\to a}D_{i}F\left(q_{i}\right)=D_{i}F\left(a\right)\), כלומר הביטוי \(D_{i}F\left(q_{i}\right)-D_{i}F\left(a\right)\) שואף לאפס. הוא מוכפל בביטוי \(\frac{h_{i}}{\left|h\right|}\), שהוא כמובן חסום בערכו המוחלט על ידי \(1\) (כי \(\left|h\right|\) גדול מהערך המוחלט של כל אחד מהרכיבים של \(h\)). לכן קיבלנו שהגבול הוא אכן אפס, וזה מה שרצינו.

לסיכום, הכרנו את הנגזרת, ולמדנו איך לבדוק שהיא קיימת ולחשב אותה בצורה פשוטה יחסית, עבור מחלקה גדולה ויפה של פונקציות (\(C_{1}\)). בפוסט הבא נראה עוד דברים מגניבים שקשורים אליה.

אנליזה וקטורית – מבוא

בזמנו כתבתי בבלוג סדרת פוסטים על חשבון אינפיניטסימלי. הצגתי בסדרה הזו את שלושת המושגים הבסיסיים שעליהם החשבון האינפיניטסימלי נשען – הגבול, הנגזרת והאינטגרל – אבל לא הלכתי יותר מדי רחוק אחר כך (אפילו לנושא כמו טורים לא הגעתי).

בעקבות בקשה שהגיעה אלי, אני רוצה להתחיל להשלים חלק מהחורים שהשארתי. ספציפית, אני רוצה לטפל באנליזה וקטורית (אצלי "אנליזה וקטורית" היא דרך מקוצרת לומר "חשבון אינפיניטסימלי במספר משתנים; אני מודע לכך שלפעמים משתמשים בשם הזה כדי לתאר תחום ספציפי יותר). הרעיון הבסיסי של התחום הוא – יופי, אז יש לנו חשבון אינפיניטסימלי של פונקציות \(f:\mathbb{R}\to\mathbb{R}\) – פונקציות ממשיות במשתנה יחיד. זה לכשעצמו כבר תחום חזק ומועיל ביותר, אבל בעולם האמיתי יש לנו הרבה פונקציות מורכבות יותר – כאלו שמקבלות כמה משתנים, ואפילו מחזירות כמה ערכים; באופן כללי, פונקציות \(f:\mathbb{R}^{n}\to\mathbb{R}^{m}\). האם ניתן להכליל את מושגי הגבול, הנגזרת והאינטגרל גם עבורם? התשובה היא כמובן "כן", והתוצאה היא אחד התחומים החשובים ביותר במתמטיקה, וכזה שיש לו אינסוף שימושים יישומיים (למשל, בלי התחום הזה אין פיזיקה).

כפי שאתם ודאי מנחשים, אני הולך להניח שאתם כבר מכירים חשבון אינפיניטסימלי של פונקציות ממשיות במשתנה יחיד. אם אתם לא מכירים – נסו לקרוא את סדרת הפוסטים שלי (או לקחת ספר לימוד). אולי קצת פחות ברור כרגע הוא תחום נוסף שאני אניח שאתם כבר מכירים – אלגברה לינארית בסיסית. הסיבות לכך יתבררו עוד מעט.

בפוסט הזה אני רוצה לתת סקירה כללית של הנושאים שאנחנו מדברים עליהם, בלי להיכנס יותר מדי לפורמליזם. ראשית נתחיל עם הצגת שדה המשחק, שהוא כאמור פונקציות \(f:\mathbb{R}^{n}\to\mathbb{R}^{m}\) מכיוון שזו דרך הצגה מאוד כללית, הרבה פעמים כשאני ארצה לתת דוגמה קונקרטית, אני אלך למקרה הלא טריוויאלי הראשון: פונקציה ממשית בשני משתנים, \(f:\mathbb{R}^{2}\to\mathbb{R}\). למשל \(f\left(x,y\right)=x+y\) או \(f\left(x,y\right)=\sin x\cos y\) וכדומה. ויזואליזציה נחמדה לפונקציה שכזו היא בתור גובה פני השטח במפה: לכל קואורדינטת \(\left(x,y\right)\) מותאם גובה \(f\left(x,y\right)\) שהוא מספר ממשי. זה נראה ככה (תמונה באדיבות ויקיפדיה האנגלית):

Three-dimensional_graph

כלומר, מין הר שכזה. עכשיו אפשר לנסח שתי שאלות על היצור הזה: ראשית, נניח שאנחנו נמצאים בנקודה מסויימת; כמה תלול ההר באותה נקודה? שנית, בואו ניקח שטח תחום כלשהו מההר – מה הנפח שלו? כלומר, כמה סלעים יש בפנים? על השאלה הראשונה עונים באמצעות נגזרות, ועל השאלה השניה באמצעות אינטגרלים. רק שהסיפור יותר מסובך כאן מאשר במימד אחד. למשל, הביטו על האוכף הזה (שוב, תודה לויקיפדיה האנגלית):

Saddle_point

במרכז האוכף, מה קורה? האם אנחנו עולים או יורדים? ובאיזה קצב? נראה שזה תלוי בכיוון שאנחנו הולכים בו. כבר אי אפשר לדבר על נגזרת רגילה, צריך לדבר על "נגזרת עבור כיוון מסויים" – נגזרת מכוונת. אבל מתברר שיש גם דרך לדבר בצורה כלשהי על "הנגזרת לכל הכיוונים בבת אחת", פשוט לא נקבל מספר כמו קודם אלא טרנספורמציה לינארית. מעט בעייתי להסביר את זה בלי להיכנס לפורמליזם (שאכנס אליו בפוסט הבא), אבל זהו הרעיון: בפונקציות ממשיות במשתנה יחיד, הנגזרת של פונקציה \(f\) בנקודה מסויימת הייתה בסך הכל מספר ממשי ("המספר הנגזר"). המספר הזה נתן לנו את "קצב השינוי הרגעי" של הפונקציה באותה נקודה, אבל יש גם דרך התבוננות גאומטרית על זה: הנגזרת בנקודה נתנה לנו את שיפוע המשיק לגרף הפונקציה באותה נקודה. אבל מה זה "משיק"? זה קו ישר שעובר דרך הנקודה הזו ו"נראה בערך כמו הפונקציה" באותה נקודה. עכשיו בואו ניקח את הרעיון הזה צעד קדימה. קו ישר הוא טרנספורמציה לינארית: הוא פונקציה מהצורה \(T\left(x\right)=ax+b\), ואנחנו יכולים בלי הגבלת הכלליות להתייחס לנקודה שבה אנו מחשבים את הפונקציה בתור ראשית הצירים כדי לקבל ש-\(b=0\), כלומר \(T\left(x\right)=ax\) כאשר \(a\) הוא המספר הנגזר של \(f\) בנקודה 0 הזו (\(a=f^{\prime}\left(0\right)\)). אפשר להוכיח שבמובן מסויים, \(T\) הזו מהווה קירוב טוב ל-\(f\) בסביבות הנקודה 0. לקירוב הזה קוראים דיפרנציאל של \(f\) בנקודה 0.

מה שעושים באנליזה וקטורית הוא להכליל בראש ובראשונה את מושג הדיפרנציאל הזה. אם \(f:\mathbb{R}^{n}\to\mathbb{R}^{m}\) אז הדיפרנציאל של \(f\) בנקודה מסויימת יהיה טרנספורמציה לינארית \(T:\mathbb{R}^{n}\to\mathbb{R}^{m}\) שמהווה קירוב טוב ל-\(f\) באותה נקודה.

פרט למושג הדיפרנציאל, ניתן לדבר על מה שתיארתי קודם – נגזרות מכוונות. בפרט, נגזרות שמכוונות בכיוון הצירים של המשתנים. נגזרות כאלו נקראות נגזרות חלקיות של \(f\) והן חשובות בפני עצמן; בדרך כלל הן קשורות בקשר הדוק לדיפרנציאלים של הפונקציה, אבל ייתכנו דוגמאות פתולוגיות שבהן יש לפונקציה דיפרנציאל אבל אין נגזרות חלקיות, וההפך.

בשלב הזה אפשר להקים לתחיה דיונים מאינפי של פונקציות ממשיות – איך מחשבים את הדיפרנציאל הזה? (בעזרת אינפי של פונקציות ממשיות). האם מתקיים כלל השרשרת? (כן). האם אפשר להשתמש בו כדי למצוא נקודות מינימום ומקסימום? (כן). האם קיימת הכללה של קירוב טיילור עבור פונקציה בכמה משתנים? (כן). ויש גם דיון שבפונקציות ממשיות רגילות הוא כמעט טריוויאלי והופך למורכב ומעניין פי כמה וכמה בהקשר הזה – באילו תנאים קיימת הופכית מקומית לפונקציה דיפרנציאבילית? המשפט הרלוונטי (משפט הפונקציה ההפוכה) הוא ההוכחה ה"כבדה" הראשונה שצצה בתחום הזה, ומייד אפשר לתת לה שימוש יפה במשפט הפונקציות הסתומות, שהוא משהו שאין לו מקבילה באינפי של משתנה יחיד, שעוסק בשאלת היכולת שלנו "לחלץ" משתנה מתוך ביטוי; למשל, המשוואה \(x^{2}+y^{2}=1\) מגדירה בצורה כלשהי את \(x\) כפונקציה של \(y\), כפי שאפשר לראות על ידי החילוץ לדוגמה \(x=\sqrt{1-y^{2}}\) – אבל האם תמיד אפשר לבצע חילוץ שכזה? והאם הוא יחיד? (במקרה שלנו, כמובן, גם \(x=-\sqrt{1-y^{2}}\) עובד) – זה מה שמשפט הפונקציות הסתומות מתעסק בו.

ואז מגיעים לאינטגרלים והכל משתגע.

יש שתי הצגות של מה שאדבר עליו עכשיו. אתחיל מזו ה"קלאסית" ואז אזכיר ברמז את המודרנית יותר. אני מקווה שגם בפוסטים העניינים יתנהלו כך.

על פניו, ההכללה של אינטגרל רימן לממדים גבוהים יותר היא טבעית יחסית. אינטגרל רימן התקבל מסדרת קירובים באמצעות מלבנים? אז עכשיו ניקח קירובים באמצעות קוביות וכן הלאה. זה אכן הרעיון הבסיסי, והוא מניב בדו ותלת מימד את מה שנקראים "אינטגרל כפול" ו"אינטגרל משולש", בהתאמה (ואפשר לדבר גם על ממדים גבוהים יותר). אבל חיש קל עולה השאלה איך מחשבים דבר כזה – והתשובה היא שבאמצעות אינטגרל "רגיל", כמובן; זה מה שנקרא משפט פוביני, שמראה איך אפשר (לרוב, לא תמיד) לחשב אינטגרל כפול באמצעות חישוב שני אינטגרלים רגילים, ואינטגרל משולש באמצעות חישוב שלושה – הבנתם את הרעיון.

זה עדיין לא מסיים את העניין, כי טכניקת אינטגרציה נפוצה מאוד – החלפת משתנים – הופכת לקריטית עוד יותר בממדים גבוהים. המשפט שמטפל באופן שבו ניתן לבצע החלפת משתנים הוא עוד תוצאה כבדה למדי.

אבל האינטגרלים לא נגמרים כאן. אפשר לעבור לדבר על סוג אחר של אינטגרלים – אינטגרל קווי ואינטגרל משטחי. וכאילו שאין די בצרות, יש שני סוגים של כל אחד מהאינטגרלים הללו. נדבר על אינטגרל קווי: הסוג הראשון עוסק בסיטואציה שבה יש לנו פונקציה סקלרית כלשהי על מרחב \(n\)-ממדי (\(f:\mathbb{R}^{n}\to\mathbb{R}\)) ואנחנו לא רוצים לחשב אינטגרל דו-ממדי שלה, אלא רוצים לשאול את השאלה מה האינטגרל ה"רגיל" שלה כשהוא נלקח על אובייקט חד ממדי – עקומה כלשהי שחיה ב-\(\mathbb{R}^{n}\). הסוג השני הוא אינטגרל של פונקציה וקטורית, כלומר פונקציה \(F:\mathbb{R}^{n}\to\mathbb{R}^{n}\). דוגמה אינטואיטיבית מאוד לעניין הזה, למי שמכיר פיזיקה, היא עבודה: אם אנחנו רוצים לחשב את השינוי באנרגיה הקינטית של גוף שנע בתוך שדה כוח כלשהו (זו הפונקציה \(F\)) במסלול מסויים (זו העקומה שעליה מבצעים את האינטגרל) צריך לחשב את האינטגרל הקווי של \(F\) על העקומה. עבור אינטגרל משטחי, הסיפור דומה, אבל במקום אינטגרציה על עקומה חד ממדית, אנחנו רוצים לבצע אינטגרציה על משטח דו ממדי.

ואז כדי לסיים את זה מגיעים כמה משפטים כבדים שמראים כל מני קשרים בין סוגי האינטגרלים הללו – משפט גרין, משפט גאוס, ומשפט סטוקס. בנפנוף ידיים פרוע, משפט גרין מראה שב-\(\mathbb{R}^{2}\), חישוב של אינטגרל כפול של פונקציה על תחום מסויים זהה לחישוב של אינטגרל קווי של פונקציה אחרת שמתקבלת ממנה, על השפה של אותו תחום. משפט גאוס עושה את אותו הדבר עבור \(\mathbb{R}^{3}\), עם המרה בין אינטגרל משולש ואינטגרל משטחי על שפת התחום שבו מבצעים את האינטגרציה המשולשת. משפט סטוקס נשאר ב-\(\mathbb{R}^{3}\) ומראה קשר דומה בין אינטגרל משטחי ובין אינטגרל קווי על השפה של המשטח.

כל העסק הזה נראה כמו בלאגן אחד גדול, והוא אכן כזה; למרבה המזל, המתמטיקה המודרנית מגיעה לעזרה. כדי להכליל את כל ערב-רב המושגים שתיארתי קודם, מכניסים לתמונה מושג שנקרא תבנית דיפרנציאלית, ובעזרתו אפשר להוכיח משפט שממנו גרין, גאוס וסטוקס הולכים להיגזר כמקרים פרטיים. המשפט הכללי נקרא (באופן ממש לא מבלבל) משפט סטוקס (זה "ה"משפט סטוקס; משפט סטוקס שתיארתי קודם נקרא "חוק סטוקס" או "משפט סטוקס הקלאסי" וכדומה כדי להבדיל ביניהם). הניסוח שלו הוא מאוד פשוט ונקי:

\(\int_{M}d\omega=\int_{\partial M}\omega\)

צריך לקרוא את זה כך: אם \(\omega\) היא תבנית דיפרנציאלית ו-\(M\) היא תחום כלשהו שמקיים כך וכך ("יריעה דיפרנציאלית קומפקטית מכוונת") אז האינטגרל של \(\omega\) על שפת \(M\) שווה לאינטגרל של הנגזרת של \(\omega\) על \(M\).

כמובן, בלי להבין את המושגים שנכללים בהגדרת המשפט אי אפשר להבין עד הסוף מה הולך כאן, אבל אני חושב שאפשר להעריך את הפשטות של התיאור הזה כבר כעת.

משפט סטוקס הזה הוא סוג של גביע קדוש בתחום – הוא מהווה הכללה של המשפט היסודי של החדו"א. גם בלי להבין את המושגים עד הסוף, אפשר לראות את זה די בקלות: באינטגרל "רגיל", התחום \(M\) שלנו הוא קטע \(\left[a,b\right]\). ה"שפה" של תחום כזה היא בסך הכל הנקודות \(\left\{ a,b\right\} \). אם \(F\) היא פונקציה כלשהי שאנחנו חושבים עליה כעל תבנית דיפרנציאלית (תבנית דיפרנציאלית היא הכללה של פונקציות), אז \(dF=f\) היא הנגזרת הרגילה שלה. לכן אנחנו מקבלים ש-\(\int_{a}^{b}f\) שווה ל"אינטגרל" של \(F\) על הנקודות \(\left\{ a,b\right\} \) – מה שיוצא \(F\left(b\right)-F\left(a\right)\). למה אחד מהם הוא חיובי והשני שלילי? זה נובע מהכיווניות של ה"יריעה" שכוללת את שתי הנקודות הללו; אסביר את הפרטים הטכניים כשאגיע אליהם, בתקווה.

אם כן, זה הרעיון הכללי ואלו הדברים שאני מקווה שיצא לי להציג (גם אם לא ברצף, ראו בפוסט הזה התחייבות כלשהי לעתיד). אני מקווה שיהיה מעניין לפחות כשם שיהיה שימושי.

על משחקים ומספרים (חלק ב': מספרים. וקצת משחקים)

בפוסט הקודם התחלתי לבנות קבוצה של מספרים שהמוטיבציה אליהם הגיעה איכשהו מתוך משחקים קומבינטוריים. כזכור, הבניה הייתה פשוטה להפליא: כל מספר מיוצג על ידי אובייקט מהצורה \(\left\{ L|R\right\} \) כאשר \(L,R\) הן קבוצות, וכלל הבניה שלנו הוא ש"מספר" הוא אובייקט כזה כך ש-\(L,R\) הן שתיהן קבוצות של מספרים וכל איבר של \(L\) קטן ממש מכל איבר של \(R\), כאשר "קטן" מוגדר באמצעות היחס \(y\le x\) אם ורק אם לא קיים \(x^{R}\le y\) ולא קיים \(x\le y^{L}\).

ההגדרה הפשוטה להפליא הזו יוצרת קבוצה אדירה של מספרים. אבל לפני שנצלול לעומק העניין, בואו נחשוב לרגע על הגדרות דומות לה שאנחנו מכירים מהמתמטיקה ה"רגילה". יש שתי הגדרות שקופצות מייד לראש – הגדרת הממשיים באמצעות חתכי דדקינד, והגדרת המספרים הסודרים בשיטה של ג'ון פון-נוימן.

המספרים של קונווי הם באופן כמעט מובהק הכללה של חתכי דדקינד (קונווי מתייחס לכך בעצמו, כמובן). כזכור, חתך דדקינד מתקבל מכך שאנחנו לוקחים את הרציונליים, \(\mathbb{Q}\), ומחלקים אותם לשתי קבוצות, \(L,R\), כך שכל איבר של \(L\) קטן מכל איבר של \(R\) (אפשר גם סתם לציין את \(L\) ולדרוש שהיא תהיה בעלת התכונה שאם \(x\in L\) ו-\(y\le x\) אז \(y\in L\)) ול-\(L\) אין איבר מקסימלי (תמיד אפשר להעביר את האיבר המקסימלי אל \(R\)). אינטואיטיבית הרעיון הוא שחתך כזה מגדיר את המספר הממשי שהוא הסופרמום של \(L\) (ואם הסופרמום הוא רציונלי, אז הוא יהיה האיבר המינימלי ב-\(R\)). המספר שחתך מגדיר הוא מה שתקוע בדיוק "בין" \(L,R\).

איך זה שונה ממה שקונווי עושה? ראשית, אצל דדקינד המספרים הרציונליים כבר קיימים; קונווי לא מניח קיום של שום דבר. שנית, אצל דדקינד \(L,R\) ביחד חייבות לכלול את כל הרציונליים ורק אותם, ואילו אצל קונווי הן יכולות להיות חלקיות ביותר, ויכולות גם לכלול מספרים לא רציונליים, כל עוד הם נבנו קודם. כך אצל קונווי אנחנו מקבלים ש-\(\left\{ -4|5,17\right\} \) הוא ייצוג שונה ל-0 (שהוגדר, כזכור, בתור \(\left\{ \ |\ \right\} \)) למרות שאין סיבה מיוחדת לומר שדווקא 0 הוא מה ש"תקוע" בין \(-4\) ובין 5 ו-17. עדיין, אם איברי \(L\) ישאפו למספר כלשהו מלמטה, ואברי \(R\) ישאפו למספר כלשהו מלמעלה, אז \(\left\{ L|R\right\} \) הולך לייצג את המספר הזה, ואנחנו ננצל את זה בקרוב.

ומה פון-נוימן עושה? הוא מגדיר מספרים סודרים בתור קבוצת כל המספרים הקטנים מהם. כך 0 הוא \(\emptyset\), ואילו \(1=\left\{ 0\right\} \), ו-\(2=\left\{ 0,1\right\} \) וכן הלאה. בצורה הזו נבנים כל המספרים הטבעיים, ואז אפשר להמשיך עם זה הלאה: \(\omega=\left\{ 0,1,2,\dots\right\} \) ו-\(\omega+1=\left\{ 0,1,2,\dots,\omega\right\} \) וכך עד אינסוף ומעבר לו. הרעיונות הללו מתורגמים בצורה מיידית לגישה של קונווי, אם משאירים את \(L\) ריקה ומסתכלים על \(R\): \(0=\left\{ \ |\ \right\} \) ו-\(1=\left\{ \ |0\right\} \) ו-\(2=\left\{ \ |0,1\right\} \) וכן הלאה; וגם פה אפשר להגדיר \(\omega=\left\{ \ |0,1,2,\dots\right\} \) ולהמשיך עם זה הלאה. אלא שאצל קונווי ה-\(\omega\) הזה חי באותו יקום כמו שאר המספרים, למשל \(\frac{1}{2}\), ולכן אפשר לחבר ולכפול אותם; ואפשר גם למצוא הופכי, כלומר קיים מספר שמתאים ל-\(\frac{1}{\omega}\) (והוא לא 0), כך שאנחנו מקבלים גם ייצוג פורמלי עבור אינפיניטסימלים; בקיצור, כיף חיים.

אבל לפני שנגיע לדברים הגרנדיוזיים הללו, אני צריך לפתור בעיה פשוטה – איפה \(\frac{1}{3}\)? טרם הצלחתי להגדיר אותו בכלל.

את מי כן הצלחתי להגדיר? את השלמים, וגם את \(\frac{1}{2}=\left\{ 0|1\right\} \) ואת \(\frac{1}{4}=\left\{ 0|\frac{1}{2}\right\} \) וכן הלאה עבור כל המספרים מהצורה \(\frac{1}{2^{n}}\). ומכיוון שיש לי גם חיבור, אז גם סכומים שלהם. זה טוב – זה ממש ממש טוב, מכיוון שלכל מספר ממשי קיים ייצוג בינארי, כלומר ייצוג בתור סכום של חזקות של 2 (כולל חזקות שליליות, כלומר \(\frac{1}{2^{n}}\)). בתור אימון, בואו נמצא את הייצוג הזה עבור \(\frac{1}{3}\).

איך בכלל מוצאים ייצוג בינארי עבור שבר? אולי יהיה לכם קל להיזכר קודם באופן שבו מבצעים חילוק ארוך בבסיס 10. אנחנו מחלקים את 1 ב-3: בתור התחלה, אנחנו בודקים כמה פעמים 3 נכנס ב-1 (0 פעמים) וכותבים את המספר 0, ואחריו את הנקודה העשרונית. עכשיו אנחנו לוקחים את השארית שלנו (שהיא 1, כי החילוק הניב מנה 0 ושארית 1). וכופלים אותה ב-10, כי 10 הוא בסיס הספירה שלנו. עכשיו אנחנו שוב מחלקים-עם-שארית את ה-10 הזה ב-3 ומקבלים מנה 3 ושארית 1. את המנה אנחנו כותבים בתור הספרה הבאה בייצוג, ואת 1 אנחנו שוב כופלים ב-10, וכן הלאה. כך מתקבל \(0.333\dots\).

עבור בסיס 2 ההבדל היחיד הוא שאנחנו כופלים ב-2 במקום ב-10. לכן הספרה שלפני הנקודה העשרונית עדיין תהיה 0; אחריה נקבל עוד 0 (כי אחרי כפל ב-2 נקבל 2 שהוא קטן מ-3). אחרי כפל נוסף ב-2 נקבל 4, ולכן אחרי חלוקה ב-3 נקבל מנה 1 ושארית 1. שוב הגענו למחזוריות (שארית 1) ולכן קל כבר לראות שנקבל את הייצוג הבינארי \(0.01010101\dots\). אם נכתוב את זה בתור טור, נקבל \(\frac{1}{4}+\frac{1}{16}+\frac{1}{64}+\dots\) – כלומר, כל פעם כופלים את החזקה ב-4. זה טור הנדסי פשוט מאוד ואם אתם עוד לא משוכנעים שאני צודק, קל מאוד לחשב את סכומו:

\(\frac{1}{4}+\frac{1}{16}+\frac{1}{64}+\dots=\frac{1}{4}\left(\sum_{n=0}^{\infty}\left(\frac{1}{4}\right)^{n}\right)=\frac{1}{4}\frac{1}{1-1/4}=\frac{1}{4}\frac{1}{3/4}=\frac{1}{3}\)

מסקנה: נגדיר את \(L\) שלנו להיות הקבוצה שכוללת את כל הסכומים החלקיים בפיתוח הזה: \(\frac{1}{4},\frac{1}{4}+\frac{1}{16},\dots\). אנחנו עדיין צריכים להגדיר את \(R\), כי לא לגמרי ברור לנו מה נקבל אם ניקח רק את \(L\) בזמן ש-\(R\) נותרת ריקה (התשובה, שאגיע אליה בהמשך, היא 1). בשביל \(R\) נראה לשאוף אל \(\frac{1}{3}\) "מלמעלה". לצורך כך נתחיל עם \(\frac{1}{2}\) ונתחיל להחסיר. אם \(\frac{1}{2}-x=\frac{1}{3}\) אז

\(x=\frac{1}{2}-\frac{1}{3}=\frac{1}{6}=\frac{1}{2}\cdot\frac{1}{3}=\frac{1}{2}\left(\frac{1}{4}+\frac{1}{16}+\dots\right)\)

מסקנה:

\(\frac{1}{3}=\frac{1}{2}-\left(\frac{1}{8}-\frac{1}{32}-\dots\right)\)

ולכן קיבלנו את ההגדרה של \(\frac{1}{3}\) כמספר-סטיל-קונווי: \(\frac{1}{3}=\left\{ \frac{1}{4},\frac{1}{4}+\frac{1}{16},\frac{1}{4}+\frac{1}{16}+\frac{1}{64},\dots|\frac{1}{2},\frac{1}{2}-\frac{1}{8},\frac{1}{2}-\frac{1}{8}-\frac{1}{32},\dots\right\} \)

את \(\frac{1}{3}\) עשיתי בפירוט, אבל אני מקווה שאתם כבר משוכנעים שאפשר לקבל כך כל מספר רציונלי. אבל אם אפשר לקבל כל מספר רציונלי, אפשר לקבל כל מספר ממשי, כי הרציונליים צפופים בממשיים; ולכן באמצעות המספרים שהם חזקות של 2 שבנינו עד כה, אפשר לקבל את כל המספרים הממשיים.

קונווי מציג את הבניה כמתרחשת ב"ימים". ביום הראשון בונים את 0; ביום השני את 1 ואת \(-1\); ביום השלישי את \(2\) ו-\(-2\) וגם את \(\frac{1}{2}\) ו-\(-\frac{1}{2}\) וכן הלאה. היום המעניין הבא בבניה הוא \(\omega\) (היום ה"אינסופי" הראשון) – ביום הזה מקבלים בבת אחת כל כל הממשיים שאינם חזקות של 2. אבל מקבלים בו יותר מזה – גם את \(\omega=\left\{ \ |0,1,2,\dots\right\} \) שתיארתי קודם.

ומה קורה אחר כך? ובכן, לכל מספר סודר יש יום בבניה שמתאים לו. ביום הזה ייבנה, באופן לא מפתיע, המספר הסודר הזה, אבל נבנים עוד דברים: למשל, מה זה \(\left\{ 0,1,2,\dots|\omega\right\} \)? זה מספר מוזר שאמור להיות גדול מכל הטבעיים אבל קטן מ-\(\omega\). זה משהו שלא קיים עבור סודרים; אנחנו קוראים בשם \(\omega\) לסודר הראשון שגדול מכל הטבעיים. אבל בבניה של קונווי המספר \(\left\{ 0,1,2,\dots|\omega\right\} \) הוא יצור חי וקיים, ואם חוקרים אותו קצת מגלים שהוא אמור להיות \(\omega-1\) (כלומר, זה מספר שאם מחברים לו 1 מקבלים את \(\omega\)). ואז אפשר לבנות את \(\omega-2=\left\{ 0,1,2,\dots|\omega-1\right\} \), וכן הלאה את \(\omega-n\) לכל \(n\) טבעי.

אוקיי, זה קצת מוזר.

זה לא לגמרי מוזר – האובייקט שקונווי בונה אמור להיות שדה, ולכן פעולת החיסור חייבת להיות מוגדרת עבור כל שני איברים שלו. עדיין, זה לא אינטואיטיבי למי שהתרגל לסודרים במתכונת הסטנדרטית שלהם.

בואו נמשיך עם זה קצת ונראה לאן נגיע. מה יהיה המספר \(\left\{ 0,1,2,\dots|\omega,\omega-1,\omega-2,\dots\right\} =\left\{ n|\omega-n\right\} \)? מצד אחד הוא גדול מכל הטבעיים, מצד שני הוא קטן מכל ה-\(\omega-n\)-ים האפשריים. ובכן, מתברר שהוא \(\frac{\omega}{2}\) – אם נחבר אותו לעצמו נקבל \(\omega\). על פי ההגדרה הפורמלית של החיבור, אם נסמן לרגע את המספר הזה בתור \(x\), נקבל \(\left\{ x,x+1,x+2,\dots|\omega+x,\omega+\left(x-1\right),\omega+\left(x-2\right),\dots\right\} =\left\{ x+n|\omega+\left(x-n\right)\right\} \); אז איך אפשר לדעת שהיצור הזה שווה ל-\(\omega=\left\{ 0,1,2,\dots|\ \right\} \)?

ובכן, זכרו את האופן שבו הוגדר שוויון – צריך להוכיח אי-שוויון דו כיווני. כלומר, להוכיח ש-\(2x\le\omega\) וגם \(\omega\le2x\). כדי שהדבר הראשון יתקיים אנחנו צריכים לוודא שאין "דוגמה נגדית" לאי השוויון – כלומר, שלא מתקיים \(\omega\le2x^{L}\) ולא מתקיים \(\omega^{R}\le2x\) (קחו רגע ונסו להזכיר לעצמכם למה דווקא שני אי השוויונים הללו). אי השוויון \(\omega\le2x^{L}\) הוא קל, כי כל איבר מהצורה \(2x^{L}\) הוא מהצורה \(x+n\) כאשר \(n\) טבעי, אבל אנחנו יודעים ש-\(x<\omega-n\) (מהגדרתו) ולכן נקבל ש-\(x+n<\omega\) (כמובן, אתם צריכים להאמין לכך שכללי האריתמטיקה מתקיימים, אבל לא לדאוג – קונווי מוכיח את זה). כעת, \(\omega^{R}\le2x\) עוד יותר קל כי אין בכלל איברים מהצורה \(\omega^{R}\). זה מוכיח ש-\(2x\le\omega\).

בשביל הכיוון השני צריך להוכיח שלא מתקיים \(2x\le\omega^{L}\) ושלא מתקיים \(2x^{R}\le\omega\). הראשון ברור – כל \(\omega^{L}\) הוא מספר טבעי \(n\), ואנו יודעים ש-\(x+n<2x\). עבור השני, זה נובע מכך שכל \(2x^{R}\) הוא מהצורה \(\omega+\left(x-n\right)\) כאשר אנו יודעים ש-\(n<x\) לכל \(n\) טבעי, ולכן (שוב, עם אמונה בכללי אריתמטיקה כלשהם) מקבלים את המסקנה.

כרגיל, הוידוא הזה היה קצת מציק. האם אין דרך יותר טבעית להסתכל על הגדרה כלשהי של מספר ולראות בקלות שהוא זהה למספר קיים? ובכן, יש, והגיע הזמן שנראה אותה. קונווי מכנה את הכלל הזה "כלל הפשטות", לא בגלל שהוא פשוט (הניסוח קצת מבלבל) אלא בגלל שהוא אומר שבהינתן מספר כללי \(\left\{ L|R\right\} \) ואנו רוצים לדעת לאיזה מהמספרים שקונווי בנה הוא שוה, אז המספר הנכון יהיה המספר הכי פשוט שמתאים, כאשר "פשטות" כאן נקבעת על פי ה"יום" שבו המספר נבנה אצל קונווי. אמרתי שזה מבלבל, נכון? אבל 0 פשוט יותר מ-1, ו-1 פשוט יותר מ-2 וכדומה. וכל המספרים הממשיים שנבנו ביום ה-\(\omega\) הם פשוטים באותה מידה, אבל מסובכים יותר מכל אלו שבאו לפניהם. הרעיון הוא שמספר "מסובך יותר" נבנה מתוך מספרים פשוטים יותר – הם יהיו האופציות שמופיעות באגף ימין ושמאל שלו.

הנה הניסוח המדויק של המשפט: אם \(x=\left\{ x^{L}|x^{R}\right\} \) ו-\(z\) הוא מספר כלשהו כך ש-\(x^{L}<z\) וגם \(z<x^{R}\) לכל \(x^{L},x^{R}\), אבל התכונה הזו לא מתקיימת על ידי אף אופציה של \(z\) (כלומר, לא על ידי אף \(z^{L}\) או \(z^{R}\)), אז \(x=z\).

ההוכחה די קלה, ודי דומה למה שעשינו לפני רגע. נוכיח ש-\(z\le x\). האפשרויות שצריך לשלול הן ש-\(x^{R}\le z\) (נשלל, כי ההנחה היא ש-\(z<x^{R}\)) וש-\(x\le z^{L}\). כדי לשלול את האפשרות הזו נרצה להראות שנובע ממנה ש-\(z^{L}\) מקיים את אותה תכונה כמו \(z\) המקורי, כלומר ש-\(x^{L}<z^{L}\) וגם \(z^{L}<x^{R}\). הראשון מבין שני אלו נובע מיד, כי \(x^{L}<x\); עבור השני, נשתמש בכך ש-\(z^{L}<z<x^{R}\).

נשאר להוכיח ש-\(x\le z\). כאן האפשרויות שצריך לשלול הן ש-\(z\le x^{L}\) (נשלל מייד כי \(x^{L}<z\)) וש-\(z^{R}\le x\); את זה שוללים באופן סימטרי לקודם. זה מסיים את המשפט.

עכשיו ברור מייד מיהו \(\left\{ x+n|\omega+\left(x-n\right)\right\} \): מצד אחד, \(\omega\) מתאים, כי הוא קטן מכל מי שבאגף ימין וגדול מכל מי שבאגף שמאל; מצד שני, כל האופציות של \(\omega\) הן טבעיים, וכולם קטנים ממישהו מאגף שמאל, כך שזה מסיים את הסיפור. עכשיו, באופן דומה, אפשר להסתכל על \(\left\{ n|\frac{\omega}{2}-n\right\} \) ולקבל שהוא שווה ל-\(\frac{\omega}{4}\), כי אם נסמן אותו ב-\(x\) ונחבר אותו עם עצמו, נקבל את \(\left\{ x+n|\frac{\omega}{2}+\left(x-n\right)\right\} \), וכאן בבירור \(\frac{\omega}{2}\) מתאים אבל אף מספר טבעי לא, וגם אף מספר מהצורה \(\omega-n\) לא, כי \(x<\frac{\omega}{2}\) ולכן נקבל ש-\(\frac{\omega}{2}+\left(x-n\right)<\frac{\omega}{2}+\frac{\omega}{2}-n=\omega-n\).

אז אנחנו יודעים להגדיר את \(\frac{\omega}{4}\), ובדרך דומה נקבל את \(\frac{\omega}{2^{n}}\) לכל \(n\) טבעי. וכבר ברור לנו איך מכאן מקבלים את \(\frac{\omega}{3}\) וכדומה.

עכשיו זה זמן טוב לעצור ולפרמל עוד יותר את ההגדרות, להוכיח שהחיבור והכפל אכן מתנהגים כמו שצריך, שאנחנו מקבלים שדה, וכדומה. אבל זו לא עבודה טריוויאלית וקונווי עושה אותה מצויין ב-On Numbers and Games, כך שאני ממליץ למי שהצלחתי לסקרן אותו לנסות ולקרוא את הספר. גם את הדיון המתבקש בשאלה האם הבניה של קונווי "טובה" יותר מהבניות הקיימות אני משאיר לספר – קונווי מדבר על יתרונות וחסרונות (ולא חורץ דין לשום כיוון, לתשומת לב הטרחנים המתמטיים). דבר אחד שקונווי מציין בתור יתרון ולדעתי הוא דווקא חסרון הוא האופן שבו נדרשת רק הגדרה אחת כדי לקבל את כל המספרים בבת אחת. מצד אחד, אין ספק שזה מגניב בצורה פסיכית; מצד שני, זה לא האופן שבו אני חושב על מספרים, ואני בהחלט חושב שיש יתרון בביצוע הפרדות חדות יחסית בין הטבעיים, השלמים, הרציונליים והממשיים, ובבניה של כל אחד מהם מתוך הקודמים על ידי טכניקות שונות. בשורה התחתונה לא הייתי הופך את המספרים של קונווי למשהו שאני מציג למי שרואה את בניית המספרים בפעם הראשונה, אבל זה בהחלט משהו שכדאי מאוד לראות מתישהו, ולא בשלב מתקדם מדי.

בואו נחזור קצת למשחקים, לסיום. ראשית, הנה שאלה מתבקשת: האם \(\omega\) וחבריו צצים מאליו גם בניתוח משחקים? התשובה חיובית, אבל המשחק צריך להיות אינסופי במובן כלשהו – לכל הפחות, צריך שיהיו אינסוף מהלכים התחלתיים אפשריים במשחק עבור אחד השחקנים (אפילו את \(\frac{1}{3}\) אי אפשר לקבל במשחק שבו יש רק מספר סופי של מהלכים). את \(\omega\) ספציפית אפשר לקבל על ידי לוח פשוט מאוד של הקנבוש – כזה שיש בו מגדל אינסופי של קווים שכולם בצבע של אליס. המהלך היחיד של אליס יסלק את כל המגדל חוץ מאשר מספר סופי של קווים שלו, כלומר יעביר אותנו לאחד מהמספרים הטבעיים, ולכן ברור שקיבלנו את \(\omega\).

עכשיו אני רוצה לדבר על משחקים קומבינטוריים שיש בהם מצבים שלא ניתנים לתיאור על ידי מספרים – כלומר, שנראה איך \(\left\{ L|R\right\} \) משמש גם בתור סימון של משחק. כבר אמרנו בפוסט הקודם ש-\(L\) היא קבוצת המהלכים של אליס ו-\(R\) הוא קבוצת המהלכים של בוב, כאשר כאן מהלך מזוהה עם המשחק החדש שהוא מייצר מתוך המשחק הקיים (כאן "משחק" מתבטא גם במצב הנוכחי של ה"לוח"). בשביל שליצור הזה נקרא מספר היה חייב להתקיים שכל איבר של \(L\) קטן מכל איבר של \(R\), אבל במשחק כמו \(\left\{ 1|-1\right\} \) זה לא קורה. המשמעות של המשחק הזה פשוטה – אם אליס מתחילה, היא יכולה לנצח תמיד, בלי תלות בבוב; ואם בוב מתחיל, הוא יכול לנצח תמיד, בלי תלות באליס ("לכפות נצחון"). זה בבירור לא מתאים למספרים שראינו עד כה: 0 תיאר משחק שבו מי שמתחיל, מפסיד, ואילו כל מספר אחר תיאר משחק שבו אחד משני השחקנים יכול לכפות נצחון (אם המספר חיובי, אליס יכולה לכפות נצחון, ואם הוא שלילי אז בוב יכול).

קונווי מסמן את זה כך: אם \(G\) הוא משחק, אז \(G>0\) אם אליס יכולה לכפות נצחון; \(G<0\) אם בוב יכול לכפות נצחון; \(G=0\) אם השחקן השני (לא זה שמתחיל) יכול לכפות נצחון; ו-\(G||0\) אם השחקן הראשון יכול לכפות נצחון: לסיטואציה כזו הוא קורא Fuzzy. הדרך הכי טובה להבין את ההתנהגות המוזרה שלה היא באמצעות משחק לדוגמה. במקרה הזה, וריאציה על הקנבוש. כזכור, בהקנבוש לאליס מותר למחוק רק קשתות אדומות, ולבוב מותר למחוק רק קשתות כחולות; בואו נהפוך את זה למעניין יותר על ידי הוספת קשתות שגם לאליס וגם לבוב מותר למחוק – ירוקות.

הנה משחק לדוגמה:

Hackenbush_8

כאן בבירור מי שמתחיל יכול לכפות נצחון, על ידי לקיחת ה"גבעול" הירוק, מה שהופך את המשחק הזה למטופש למדי. אבל כרגיל בעניינים כאלו, וריאציה קטנה הופכת אותו למעניין – מה אם היו לנו שני "פרחים"?

Hackenbush_9

עכשיו לקחת את הגבעול של אחד הפרחים זה מתכון בטוח להפסד, כי השחקן השני יקח את הגבעול של הפרח השני. לכן הקרב יתחולל בכלל ב"עלים" של הפרחים, והמפסיד יהיה מי שנשאר בלי עלים בכלל לקחת וחייב לקחת את אחד מהגבעולים. כלומר, קיבלנו את אותו משחק כמו המשחק הבא:

Hackenbush_10והמשחק הזה הוא \(-2\). אז אם נסמן ב-\(G\) את המשחק המקורי, קיבלנו ש-\(G+G=-2\), אבל אי אפשר להסיק מכך ש-\(G=-1\); אנחנו רואים שבהכרח משחקים שהם Fuzzy לא יתנהגו נחמד כמו מספרים. יותר מכך – אם נשנה את התצורה של העלים של \(G\) על ידי כך שנחליף בין הצבעים שלהם נקבל ש-\(G+G=2\), וזאת למרות ש-\(G\) עצמו לא השתנה ונותר משחק שבו המתחיל יכול לנצח בצעד הראשון שלו. זו הסיבה שקונווי משתמש בתיאור Fuzzy למשחקים כאלו – אנחנו יודעים שהם נמצאים בתוך מין "ענן" כזה סביב ציר המספרים, אבל המיקום המדויק שלהם תלוי בפרטים נוספים.

כמובן, בניתוח של רוב המשחקים סביר שיצוצו מצבים שהם Fuzzy, אחרת אלו משחקים די מוזרים – כאלו שהם מוטים מראש לטובת אחד מהשחקנים, ולא משנה אם הוא מתחיל או שני (או, עבור 0, משחקים שבהם מי שמתחיל מפסיד). בהקנבוש הרגיל זה לא קורה, כי המשחק מוטה: יש קשתות שהן רק של אליס וקשתות שהן רק של בוב, בלי קשר לשאלה מי משחק מתי. אם כן, אולי כדאי שנסתכל על משחק שאיננו מוטה בצורה הזו? למשל, נים, שכבר הזכרתי בפוסט הקודם אבל נמנעתי מלדבר עליו עד כה כי בניתוח שלו לא צצים המספרים הסוריאליסטיים כפי שהם צצים עם הקנבוש. כמובן, הדיכוטומיה נים-או-הקנבוש היא קצת שקרית; הקנבוש המוכלל, עם הקשתות הירוקות, כולל את נים בתור מקרה פרטי: משחק הקנבוש הוא בעצם נים אם כל הקשתות שלו ירוקות והוא מורכב ממספר מסלולים זרים (אין "התפצלות").

למי מכם שלא מכירים את נים או זוכרים אותו, יש לי פוסט על הנושא שגם נותן ניתוח יפה של האסטרטגיות במשחק. הפעם אני רוצה להתמקד באספקט ה"מספרי" של המשחק. בואו נמשיך לנקוט בגישה של קונווי, ונסמן ב-\(*n\) את המשחק שמתאים לנים בעל ערימה אחת עם \(n\) גפרורים (קונווי קורא להם Nimbers, אבל בעברית זה כבר לא עובד – "מספנים"?). פורמלית, \(*0=\left\{ \ |\ \right\} \) ו-\(*1=\left\{ *0\ |*0\right\} \) ובאופן כללי \(*n=\left\{ *0,*1,\dots*\left(n-1\right)|*0,*1,\dots*\left(n-1\right)\right\} \).

ה"מספרים" הללו מתנהגים בצורה מוזרה, כמובן. בתור התחלה, קל לראות שמתקיים \(*n+*n=*0\) (חיבור, כזכור, הוא מה שמקבלים אם לוקחים את שני המשחקים ושמים אותם זה ליד זה, כך שכל אחד בתורו יכול לבחור באיזה משחק לשחק). כלומר, מי שמתחיל לשחק על משחק מהצורה \(*n+*n\) מפסיד, כי הצד השני יכול לבצע "תמונת ראי" לכל מה שהוא עושה על המשחק המקביל (דהיינו, בכל רגע נתון במשחק, אחרי שהשחקן הראשון ביצע מהלך השני יכול לעשות מהלך שבסופו עדיין יהיו שתי ערימות מאותו גודל). לעומת זאת, אם \(n\ne k\) אז \(*n+*k\) הוא משחק שבו השחקן הראשון מנצח תמיד (מהלך הפתיחה המבריק הוא לאזן את גדלי שתי הערימות), כלומר \(*n+*k\) הוא משחק Fuzzy ואינו ניתן לתיאור בידי מספר רגיל. אבל מה המספרנים שמתאים לו? ובכן, אין לי כרגע סט כללים נחמד, אבל בואו נלך בעקבות קונווי ונראה כמה דוגמאות.

בתור התחלה, מהו \(*1+*2\)? אנחנו רוצים למצוא ערימה שלישית שאם נשים ליד שני אלו, נקבל משחק שערכו 0. ברור שלהוסיף ערימה מגודל 1 או 2 לא יעבוד, כי המתחיל יסלק את הערימה מהגודל יוצא הדופן ונישאר עם שתי ערימות מאוזנות (משחק שבו המתחיל מפסיד, ומכאן שהמתחיל במשחק המקורי ניצח). לעומת זאת ערימה מגודל 3 תעבוד – לא משנה מה מהלך הפתיחה של השחקן הראשון, השחקן השני יוכל להביא אותנו למצב של שתי ערימות מאוזנות. 4 כבר לא מתאים כי לשחקן הראשון יש מהלך פתיחה של צמצום ערימת ה-4 לערימת 3; באופן דומה גם כל גודל הגדול מ-4 לא יעבוד. מכאן שערימה בגודל 3 היא המועמד המתאים היחיד כאן, וקיבלנו ש-\(*1+*2=*3\).

כמובן, כבר אנחנו רואים שקורה כאן משהו מוזר. השוויון שלעיל נובע מכך ש-\(*1+*2+*3=0\), ומכך ש-\(*3=-*3\); אבל באותה המידה היינו יכולים לכתוב גם \(*2+*3=*1\). אז תשכחו מחוקי החשבון הרגילים.

בואו ננסה עוד דוגמה שיש אצל קונווי: \(*1+*4+*5\). גם כאן הטענה היא שמי שמתחיל, מפסיד. למה? סילוק ערימת ה-1 בוודאי מוביל להפסיד. הקטנה של ערימת ה-4 ל-2 או 3 תאפשר לשחקן השני להעיף את ערימת ה-5 ולהעביר את המשחק ל-1,2,3 שכבר ראינו שהמתחיל מפסיד בו, והקטנה של ערימת ה-4 ל-1 תיצור שתי ערימות זהות. אותו דבר קורה עם 5 – הקטנה שלה ל-4 תיצור שתי ערימות זהות, והקטנה רצינית יותר תיצור את \(1,2,3\). קיבלנו ש-\(*1+*4=*5\).

כאן זו נקודה טובה לעצור – בינתיים. מן הסתם אני רק מגרד את קצה הקרחון של התחום הזה, אבל בעיה עיקרית היא שקשה לי להתחרות עם קונווי; שני הספרים שאני מסתמך עליהם הם מופת של כתיבה, ואני ממליץ לכם לקרוא אותם אם התעניינתם במה שהוצג עד כה. כאמור, On Numbers and Games הוא המתמטי-פורמלי יותר, בזמן ש-Winning Ways הוא יותר קליל באופיו, אבל שניהם מאוד מומלצים.

על משחקים ומספרים (חלק א': משחקים. וקצת מספרים)

בראשית ימי הבלוג, חלק מהפוסטים הראשונים שפרסמתי עסקו או בתורת המשחקים, או בבנייה השיטתית של מערכות המספרים המרכזיות במתמטיקה (הטבעיים, השלמים, הרציונליים, הממשיים והמרוכבים). אני רוצה עכשיו לחזור לנושאים הללו באופן שאיכשהו מצליח לחבר את שניהם, בהתבסס על שני ספרים שכתב המתמטיקאי ג'ון קונווי – הראשון, On Numbers and Games, והשני (שאותו כתב עם עוד אנשים), Winning Ways for your Mathematical Plays. בשני הספרים הללו יש ניתוחים של סוגים מסויימים של משחקים לשני שחקנים, ומה שכל כך יפה בזה הוא שבאופן טבעי למדי, מהניתוחים הללו צצה לה מערכת מספרים יפה ומעניינת במיוחד, שאבריה מכונים לפעמים (לא על ידי קונווי בספרים אלו) "מספרים סוריאליסטיים". מערכת המספרים הזו כוללת בתוכה את המספרים הממשיים, אבל גם איברים נוספים – למשל, את כל המספרים הסודרים. אבל יותר מזה – גם הופכיים עבור המספרים הסודרים, שזה כבר בוודאי נשמע מוזר לחלקכם, ועוד כל מני דברים מעניינים. מה שבאמת יפה הוא שהמערכת הזו מתקבלת על ידי הגדרה פשוטה ביותר, שאציג מייד עכשיו כדי לא לעשות טיזינג מיותר:

אם \(L,R\) הן שתי קבוצות של מספרים כך שאין איבר של \(L\) הגדול או שווה לאיבר של \(R\) אז \(\left\{ L|R\right\} \) הוא מספר. כל המספרים נבנים בצורה זו.

זו ההגדרה, אבל מה הולך כאן? למה אלו מספרים? איך מקבלים פה מספרים ממשיים? איך מקבלים את \(\pi\)? מה זו השטות הזו שיש לסודרים הופכי? מה למען ג'ון פון-נוימן הקשר למשחקים? הרבה שאלות, ואענה על כולן. יהיה כיף; זה נושא שחביב עלי מאוד ואני בטוח שגם אלו מכם שלא מכירים הרבה מתמטיקה יוכלו ליהנות ממנו. כמובן, אני הולך לחפף; אני ממליץ על קריאת הספרים למי שלא יהיה מרוצה מהדילוגים שלי (מבין שניהם, On Numbers and Games הוא המתמטי-פורמלי יותר, לטוב ולרע, אבל גם הוא כתוב בצורה קלילה יחסית).

בואו נתחיל מלדבר על משחקים. משחק, אצלנו, תמיד יהיה משחק לשני שחקנים, שאקרא להם אליס ובוב או שמאל וימין (אליס תהיה שמאל, בוב יהיה ימין, ונהיה לטובת אליס). אנחנו מניחים שבמשחק יש ידיעה שלמה – אין מידע חסוי (כמו שיש למשל ב"צוללות") או אלמנטים אקראיים (כמו הטלות קוביה בשש-בש, שאפשר לחשוב עליהן בתור סוג של מידע חסוי). עד כאן סטנדרטי, ומוביל למשחקים שנקראים "משחקים דמויי-שחמט". אבל אנחנו מגבילים את עצמנו עוד יותר – אין תוצאות תיקו, והמשחקים תמיד מתנהלים באופן הבא: אחד השחקנים מבצע מהלך, ואז השחקן השני מבצע מהלך, וכן הלאה לסירוגין, עד אשר שחקן כלשהו לא יכול לבצע מהלך חוקי כלשהו ואז הוא מפסיד. דבר כזה לא קורה בשחמט. בשחמט, שחקן מפסיד אם המלך שלו מאויים ואין לו דרך להגן עליו; בהחלט ייתכן שתהיה סיטואציה שבה שחקן כלשהו לא יכול לבצע אף מהלך חוקי אבל לא להפסיד – אם כל מהלך שהשחקן יבצע יגרום למלך שלו להיות מאויים, אסור לו לבצע אף מהלך. לסיטואציה הזו קוראים "פט" והיא נחשבת לתיקו. כך שאנחנו רואים שהוצאנו את שחמט מהמשחק. אל תדאגו, יש עוד מספיק משחקים מעניינים לדבר עליהם.

ההנחה האחרונה שלנו היא שהמשחקים הם סופיים – כלומר, שתמיד אחרי מספר סופי של מהלכים המשחק יסתיים בניצחון של אחד השחקנים. זה לא אומר שמספר המהלכים החוקיים של כל שחקן בכל שלב חייב להיות סופי; בהחלט ייתכנו משחקים שבהם יש סיטוצאיות שבהם השחקנים יכולים לבצע אינסוף מהלכים.

בבלוג כבר דיברתי על מספר משחקים שמתאימים לכל הדרישות הללו – נים וצ'ומפ הן שתי דוגמאות (צריך קצת להיזהר עם ההגדרה של מתי אין יותר פעולה חוקית). עם זאת, אני לא אדבר על המשחקים הללו (לפחות לא כרגע) כי הם מסובכים מדי. בשלב הראשון אני רוצה להראות איך ניתוח של משחקים מוביל להגדרה של מספרים סוריאליסטיים, אבל בניתוח של משחק כמו נים יווצרו עוד כל מני דברים שאינם מספרים בכלל. לכן אני בוחר להתחיל ממשחק שאולי נראה קצת מוזר במבט ראשון אבל הוא מתאים בול בתור מבוא לנושא (ולכן הוא מה שמופיע ראשון גם ב-Winning Ways) – הקנבוש (Hackenbush).

"לוח המשחק" בהקנבוש הוא ציור שכולל "קרקע" בצבע ירוק, ועוד כל מני קווים בצבעי אדום וכחול ("קו" אצלנו הוא קו ישר – אם הקו "נשבר" לשני חלקים בזוויות שונות, אלו שני קווים שונים מבחינתנו). מכל קו אפשר להגיע דרך קווים אחרים אל הקרקע – אין קו "מנותק". המשחק מתנהל כך: אליס בתורה בוחרת קו אדום כלשהו ומוחקת אותו מהלוח. בוב, בדומה, בוחר קו כחול ומוחק מהלוח. אם מחיקת קו כזו גרמה לניתוק של חלק מהקווים מן הקרקע, כל הקווים המנותקים נמחקים. אליס מפסידה אם תורה לשחק ולא נותרו קווים אדומים, ובוב מפסיד אם תורו ולא נותרו קווים כחולים. הנה לוח לדוגמא:

Hackenbush basicבפועל יותר נוח לדבר על גרף מאשר על "ציור" – ובכן, לוח הקנבוש הוא גרף שבו הקשתות צבועות באדום וכחול, וחלק מהצמתים מסומנים כ"מחוברים לקרקע", ואפשר למחוק קשתות, ואחרי מחיקת קשת מוחקים את כל הצמתים שהפכו למנותקים מהקרקע ואת כל הקשתות שמחוברות אליהם.

מה שנחמד בהקנבוש הוא שניתן לכל לוח משחק להתאים מספר שאומר לאיזה שחקן יש יתרון. אם המספר יהיה חיובי אז היתרון יהיה של אליס, אם הוא יהיה שלילי היתרון יהיה של בוב, ואם הוא יהיה 0 זה אומר שמי שמתחיל, מפסיד (כלומר, היתרון הוא אצל השחקן שלא מתחיל). מה שעוד יותר נחמד הוא שהיתרון הזה לאו דווקא יהיה מספר שלם, ושעוד מעט נבין גם את ההגיון שמאחורי זה.

אני אאמץ את שיטת הסימון הבאה לתיאור לוח הקנבוש: אני אכתוב אותו בתור \(\left\{ L|R\right\} \) כאשר \(L\) תהיה רשימת הלוחות שיכולים להתקבל מהלוח הנוכחי אחרי מהלך שאליס תבצע, ואילו \(R\) תהיה רשימת הלוחות שיכולים להתקבל מהנוכחי אחרי מהלך שבוב יבצע. בואו נתחיל מהסיטואציה הכי פשוטה: לוח ריק. מה שאני אצייר רק בתור קו ירוק ותו לא. במקרה הזה, אין לא לאליס ולא לבוב מהלכים חוקיים, כלומר המצב הוא \(\left\{ \ |\ \right\} \). מי מבין השניים שמתחיל, מפסיד מייד כי אין לו מה לעשות, ואז השני מנצח. לכן אסמן \(\left\{ \ |\ \right\} =0\) (זוהי הגדרה של 0, אם תרצו).

נתבונן כעת על לוח שכולל קו אדום יחיד ותו לא:

Hackenbush_1אם אליס מתחילה לשחק, אז המהלך היחיד שלה הוא למחוק את הקו האדום, מה שמעביר אותנו ללוח ריק שאנחנו כבר מכירים – זה 0. לעומת זאת, אם בוב מתחיל לשחק אין לו מהלכים חוקיים בכלל והוא מייד מפסיד. לכן אסמן את הלוח הזה ב-\(\left\{ 0|\ \right\} \). אינטואיטיבית, אליס מובילה כאן על בוב במהלך אחד (כי יש לה קו אחד יותר מאשר יש לו) ולכן נסמן \(\left\{ 0|\ \right\} =1\). באופן דומה, הלוח שבו יש קו יחיד שהוא כחול מתאים לסימון \(\left\{ \ |0\right\} \), ומכיוון שהוא מתאר יתרון של מהלך אחד של בוב על אליס, נסמן אותו במספר שלילי (כלומר, אליס בחיסרון של מהלך אחד מול בוב), כלומר \(\left\{ \ |0\right\} =-1\).

קל לנחש איך אפשר להמשיך מכאן: לוח שבו יש \(n\) קווים אדומים (שכולם מחוברים לקרקע) ואף קו כחול מתאים ל-\(\left\{ n-1|\ \right\} =n\) ולוח שבו יש \(n\) קווים כחולים ואף קו אדום מתאים ל-\(\left\{ \ |-\left(n-1\right)\right\} =-n\). כבר קיבלנו את כל המספרים השלמים, אבל עד כה טרם ראינו משהו מתוחכם.

בואו נסתכל עכשיו על לוח שבו יש קו אדום וקו כחול אחד, ששניהם מחוברים לקרקע:

Hackenbush_2הלוח הזה מתאים ל-\(\left\{ -1|1\right\} \), כי המהלך היחיד של אליס ישאיר קו כחול יחיד, והמהלך היחיד של בוב ישאיר קו אדום יחיד, ואת שתי הסיטואציות הללו כבר ניתחנו ונתנו להן שמות. המשחק הזה הוא עוד דוגמה למשחק שבו המתחיל מפסיד, מה שקראנו לו 0. כלומר, אני רוצה לסמן \(\left\{ -1|1\right\} =0\). מצד שני, הסימון \(0\) כבר שמור ללוח אחר, \(\left\{ \ |\ \right\} \). אלו שני לוחות שונים, אבל בשורה התחתונה המשחק שהם מגדירים הוא זהה באספקט שמעניין אותנו, שהוא מה גודל היתרון שיש לשחקן אחד על פני השני. לכן אפשר לומר ש-\(\left\{ \ |\ \right\} \) ו-\(\left\{ -1|1\right\} \) הם שני ייצוגים שונים של אותו מספר ולהתייחס אליהם כשווים. למי שנפנוף הידיים הזה מפריע לו – אל דאגה, בהמשך ניתן הגדרה פורמלית של השוויון הזה.

דרך מעניינת אחרת לחשוב על המשחק הזה הוא בתור שני משחקים נפרדים שבמקרה יושבים אחד ליד השני:

Hackenbush_3באופן כללי אפשר לחשוב על "הרכבה" של משחק מתוך כמה משחקים בלתי תלויים זה בזה, כשהחוקים הם המתבקשים: כל שחקן, בתורו, בוחר את אחד מלוחות המשחק ומבצע צעד אחד באותו לוח. מפסיד השחקן שבתורו לא יכול לבצע מהלך באף לוח. כעת מתבקש להגדיר חיבור של משחקים בתור "המשחק שמתקבל מההרכבה הזו". במקרה שלנו, נקבל ש-\(1+\left(-1\right)=0\) – לא מפתיע! (ושוב, לא לדאוג, הגדרות פורמליות יגיעו בהמשך).

עכשיו בואו נעבור למשהו שונה ממה שראינו עד כה: לוח שבו יש קו אדום אחד שמחובר לקרקע, ומעליו יש קו כחול:

Hackenbush_4כאן בבירור זה משחק "אטומי" שלא ניתן לפרק לתת-משחקים פשוטים יותר שאחר כך מחברים, כי שני הקווים הם לא בלתי תלויים זה בזה – אם אליס תסיר את הקו האדום, אז היא תגרום גם למחיקת הקו הכחול, ובוב יפסיד. לכן המהלך היחיד של אליס מעביר את הלוח למצב 0, בעוד המהלך היחיד של בוב מעביר את הלוח למצב 1 (קו אדום בודד לאליס). כלומר, המשחק הזה הוא \(\left\{ 0|1\right\} \). לאיזה ערך מספרי הוא מתאים?

בבירור הערך המספרי הזה צריך להיות חיובי, הרי לאליס יש יתרון במשחק הזה. אבל כמה גדול היתרון? האם זה יתרון של מהלך אחד, כמו שהיה במשחק שבו לאליס היה קו אדום יחיד ולבוב כלום (או, למשל, שני קווים אדומים לאליס וקו כחול אחד לבוב)? ובכן, לא, זה יתרון קטן יותר, כי בכל זאת אם בוב מתחיל הפעם הוא יצליח לשרוד עד שלאליס לא יישארו קווים בעצמה (בעוד שבמשחק עם יתרון 1, הוא ישרוד רק עד שלאליס יישאר קו אחד). אז כמה? אני טוען שהיתרון הוא בדיוק \(\frac{1}{2}\), כלומר ש-\(\left\{ 0|1\right\} =\frac{1}{2}\). אבל איך להוכיח דבר כזה?

ובכן, \(\frac{1}{2}+\frac{1}{2}=1\), או בניסוח אחר \(\frac{1}{2}+\frac{1}{2}+\left(-1\right)=0\). יותר מכך: אם \(x\) הוא מספר ממשי כלשהו כך ש-\(x+x+\left(-1\right)=0\) אז נובע מכך ש-\(x=\frac{1}{2}\). אז כדי להוכיח ש-\(\left\{ 0|1\right\} =\frac{1}{2}\) (בהנחה – שלא הוכחתי – שאכן המשחק הזה מתואר על ידי מספר ממשי) די לי להוכיח ש-\(\left\{ 0|1\right\} +\left\{ 0|1\right\} +\left\{ \ |0\right\} =0\) – כלומר, שהמשחק הבא:

Hackenbush_5הוא כזה שבו מי שמתחיל, מפסיד (בפרט, שנדרשים שני עותקים של \(\left\{ 0|1\right\} \) כדי "לקזז" את \(\left\{ \ |0\right\} \)).

כדי לראות שמי שמתחיל במשחק מפסיד, בואו פשוט נחשוב איך משחק כזה יתנהל. נניח שאליס מתחילה. היא חייבת לקחת את אחד משני הקווים האדומים שלה. בוב יקח את הכחול שמעל הקו האדום השני. אליס תיקח את האדום האחרון שלה. בוב יקח את הכחול האחרון שלו. הופס! אליס הפסידה.

נניח שבוב מתחיל: אם הוא לוקח את הכחול המבודד שלו, אז אליס לוקחת אדום ומעבירה את המשחק למצב \(\left\{ 0|1\right\} \) שבו בוב תמיד מפסיד. אם כן, לא שווה לבוב לקחת את הכחול המבודד שלו. הוא ייקח את הכחול שמעל אחד מהקווים האדומים, אבל אז אליס תיקח את הקו האדום השני ותשאיר לבוב רק את הכחול המבודד שלו. הוא ייקח אותו, אליס תיקח את האדום השני שלה והופס! בוב הפסיד.

אם כן, \(\left\{ 0|1\right\} =\frac{1}{2}\). רוצים לנחש למה יהיה שווה \(\left\{ 0|\frac{1}{2}\right\} \)? מן הסתם \(\frac{1}{4}\) נראה כמו בחירה הגיונית. לשם כך צריך להראות ש-\(\left\{ 0|\frac{1}{2}\right\} +\left\{ 0|\frac{1}{2}\right\} +\left\{ 0|1\right\} =0\). נסו לשחק את המשחק ולראות מה קורה.

Hackenbush_6שימו לב ללוח שמייצג את \(\left\{ 0|\frac{1}{2}\right\} \): קו אדום, ומעליו שני קווים כחולים. אם נדקדק בהגדרה הפורמלית, הלוח הזה הוא בעצם \(\left\{ 0|\frac{1}{2},1\right\} \): לאליס יש רק אפשרות אחת, של סילוק הקו האדום; בעוד שלבוב יש שתי אפשרויות, לסלק את הקו הכחול העליון (ולעבור אל \(\frac{1}{2}\) או את הקו הכחול התחתון (ולעבור ל-1), אבל שוב – נראה עוד מעט ש-\(\left\{ 0|\frac{1}{2},1\right\} =\left\{ 0|\frac{1}{2}\right\} \).

עכשיו כבר ברור שעל ידי הוספה של עוד ועוד קווים כחולים למעלה נוכל לקבל גם את \(\frac{1}{8}\), ואת \(\frac{1}{16}\), וכן הלאה וכן הלאה – כל שבר מהצורה \(\frac{1}{2^{n}}\). זה מוביל אותנו בצורה טבעית לשתי שאלות: ראשית, מה קורה אם מוסיפים למעלה לא רק קווים כחולים אלא גם אדומים? ושנית, האם אפשר לקבל איכשהו שברים עם מכנה שאינו חזקה של 2?

נתחיל מהשאלה הראשונה עם הלוח הזה:

Hackenbush_7מה המהלכים האפשריים בלוח? אליס יכול להעיף את הקו התחתון, ולהישאר עם 0, או להעיף את הקו העליון ולהישאר עם \(\frac{1}{2}\). בוב יכול להעיף רק את הקו האמצעי ולהישאר עם \(1\). כלומר, אנחנו ב-\(\left\{ 0,\frac{1}{2}|1\right\} \). אם כבר יש לכם אינטואיציה לא רעה לגבי מה שהולך כאן, כנראה תנחשו שהמצב הזה שווה ל-\(\left\{ \frac{1}{2}|1\right\} =\frac{3}{4}\). כלומר, לא נראה שנקבל משהו ממש חדש מהוספה של קווים אדומים על כחולים על אדומים על כחולים וכן הלאה. כדי להגיע לשבר עם מכנה שונה מחזקה של 2, למשל \(\frac{1}{3}\), נצטרך משהו שונה לגמרי.

אבל בואו נעזוב את זה לרגע, ונעבור לנסיון להבין את הדקויות של הסימון המוזר שבו אנחנו משתמשים. על פניו, כדי להבין מה המספר שמיוצג על ידי \(\left\{ L|R\right\} \), אנחנו נוקטים בשיטה הבאה: מוצאים את המספר הגדול ביותר ב-\(L\) והקטן ביותר ב-\(R\) ומחשבים את הממוצע החשבוני שלהם. זה המקום הראשון שבו האינטואיציה שלנו לא עובדת – האמת היא שהסיטואציה מסובכת יותר. הנה דוגמה פשוטה: \(\left\{ -1|2\right\} \). לכאורה, המשחק הזה אמור להתאים לערך המספרי \(\frac{1}{2}\), שנמצא באמצע הדרך בין \(-1\) ובין \(2\); אבל אם תחשבו שניה, ברור שהמשחק הזה הוא 0. למה? כי אם אליס מתחילה, המהלך היחיד שלה מעביר את המשחק ל-\(-1\), שהוא משחק שבו בוב מנצח בודאות; ואם בוב מתחיל, המהלך היחיד שלו מעביר את המשחק ל-\(2\), שבו אליס מנצחת בודאות. אז יש לנו משחק שבו מי שמתחיל, מפסיד: כבר אמרנו שזה המשחק 0 (ו-\(\frac{1}{2}\) הוא משחק שבו אליס מנצחת). בקיצור, לא משנה כמה חזק מבחינת אליס המצב שבוב מעביר אליו את המשחק, כל עוד אליס מעבירה את המשחק למצב שהוא מפסיד מבחינתה.

לכן יש לנו כמה שאלות שחייבים לענות עליהן לפני שממשיכים:

  1. מתי בעצם ביטוי כמו \(\left\{ L|R\right\} \) מגדיר מספר?
  2. איך מגדירים מספר חדש מתוך מספרים קיימים?
  3. איך בודקים ששני ביטויים שונים מגדירים את אותו המספר?
  4. מה הכלל שמאפשר לנו למצוא את המספר שמתאים לביטוי \(\left\{ L|R\right\} \)?

בואו נשכח לרגע ממשחקים ונעבור להגדרות פורמליות. תשובה לשתי השאלות הראשונות מתקבלת מייד מההגדרה שנתתי בראשית הפוסט, ועכשיו נשחק איתה:

אם \(L,R\) הן שתי קבוצות של מספרים כך שאין איבר של \(L\) הגדול או שווה לאיבר של \(R\) אז \(\left\{ L|R\right\} \) הוא מספר. כל המספרים נבנים בצורה זו.

זו דוגמה להגדרה אינדוקטיבית (או רקורסיבית, מה שבא לכם): אנחנו מתארים איך לבנות מספרים חדשים מתוך מספרים שכבר קיימים. נקודה שחשוב לי להדגיש, לפני שנתחיל להשתמש בה כדי לייצר מספרים, היא שההגדרה הזו עדיין לא מאפשרת לנו לראות ש-0 ו-\(\left\{ -1|1\right\} \) הם אותו מספר; לשם כך נצטרך לתת הגדרה מפורשת של שוויון, שתבוא בהמשך.

עוד דבר שכמובן חסר הוא הגדרה של המושג "גדול" כאן. כדי לתאר אותו, סימון: אם \(x=\left\{ L|R\right\} \) אני משתמש בסימון \(x^{L}\) כדי לתאר "איבר כלשהו מתוך \(L\)" וב-\(x^{R}\) כדי לתאר "איבר כלשהו מתוך \(R\)". האינטואיציה תהיה תמיד ש-\(x^{R}\) הם מספרים שגדולים מ-\(x\) ואילו \(x^{L}\) הם מספרים שקטנים מ-\(x\) (אבל לא בהכרח כל המספרים הגדולים/קטנים מ-\(x\)). תחת האינטואיציה הזו, מתי \(x\ge y\)? ובכן, אם לא קיים מספר שגדול מ-\(x\) אבל קטן מ-\(y\), ולא קיים מספר שקטן מ-\(y\) אבל גדול מ-\(x\).

פורמלית, נגדיר ש-\(x\ge y\) אם לא קיים \(x^{R}\le y\) ולא קיים \(x\le y^{L}\). גם זו הגדרה אינדוקטיבית, אבל נראה שהכל יסתדר לנו. באופן מתבקש נגדיר שוויון של מספרים על פי ההגדרה הזו: \(x=y\) אם \(x\le y\) וגם \(y\le x\).

אם כן, איך אפשר "לעבוד" עם ההגדרה כדי לייצר מספרים? ההתחלה נראית קשה – הרי אין לנו שום מספר שהוגדר עד כה, מאיפה נתחיל? ובכן, מהמצב שבו \(L=R=\emptyset\) – שתי הקבוצות ריקות. מכיוון ששתי הקבוצות ריקות, התנאי של "אין איבר של \(L\) הגדול או שווה לאיבר של \(R\)" מתקיים באופן ריק, וקיבלנו מספר, שאנו מסמנים \(0=\left\{ \ |\ \right\} \).

מה עכשיו? אפשר "לשתול" את 0 הזה בתוך אגף ימין או שמאל, אבל לא שניהם: \(\left\{ 0|0\right\} \) הוא לא מספר, כי \(0\le0\) (בדקו זאת!). לכן אנחנו יכולים לבנות רק שני מספרים חדשים בינתיים: \(\left\{ \ |0\right\} \) ו-\(\left\{ 0|\ \right\} \), שנסמן \(-1\) ו-\(1\), בהתאמה. העובדה שהם מספרים נובעת מכך שתנאי ה-"אין איבר של \(L\) הגדול או שווה לאיבר של \(R\)" עדיין מתקיים באופן ריק. עכשיו בואו ננסה להבין מי גדול ממי.

ראשית, לא ייתכן ש-\(\left\{ \ |0\right\} \ge0\) כי קיים באגף ימין של \(\left\{ \ |0\right\} \) איבר 0 כך ש-\(0\le0\). ההפך כן עובד, ולכן אנחנו מקבלים ש-\(-1\le0\). באופן סימטרי מקבלים ש-\(0\le1\). כמו כן מקבלים בקלות ש-\(-1\le1\) על ידי בדיקה ישירה, בלי הסתמכות על טרנזיטיביות או משהו דומה.

נמשיך ונגדיר \(2=\left\{ 1|\ \right\} \). עכשיו מעניין לבדוק האם \(1\ge2\) מתקיים. בואו נעשה את זה פורמלית. אני שואל את עצמי שתי שאלות. ראשית, האם קיים \(1^{R}\le2\)? לא, מכיוון שה-\(R\) של 1 הוא קבוצה ריקה. שנית, האם קיים \(1\le2^{L}\)? ובכן, כן, כי \(1\) הוא איבר מהצורה \(2^{L}\). מכאן מקבלים שלא מתקיים \(1\ge2\).

ומה עם \(1\le2\)? כאן הבדיקה הפוכה. ראשית, האם קיים \(2^{R}\le1\)? לא, כי \(R\) של 2 ריק. והאם קיים \(2\le1^{L}\)? לא, כי ב-\(1^{L}\) יש רק את 0, ולא מתקיים \(2\le0\). כדי לראות את זה, צריך לבצע אינדוקטיבית את הבדיקה גם עבור \(2\le0\); מכיוון ש-\(0\le2^{L}\) מתקיים עבור הבחירה של 1 בתוך האיבר מ-\(L\) של 2, מקבלים ש-\(2\le0\) לא מתקיים, כנדרש.

כמו שהבנתם, אין מנוס מכל מני בדיקות קטנות וקטנוניות כדי לוודא דברים עם ההגדרות הללו – זה לא באמת שונה ממה שקורה בהגדרות בסיסיות אחרות. מכאן ואילך לא אטרח להוכיח את רוב הטענות שלי, אבל אתם יכולים לבדוק אותן בתור תרגיל.

עכשיו אפשר לראות למה \(\left\{ -1|1\right\} =0\), כלומר למה יש לנו שני ייצוגים שונים לאותו מספר (או, אם להיות ממש פורמליים, שני מספרים שונים שמתקיים עבורם יחס השווין; אבל זו צורת חשיבה שגויה, כי למשל עבור מספרים רציונליים כולנו מסכימים ש-\(\frac{1}{2}\) ו-\(\frac{2}{4}\) הם שני ייצוגים שונים של אותו מספר). הם פשוט מקיימים \(\left\{ -1|1\right\} \le0\) (כי הסיכוי היחיד של זה לא להתקיים הוא אם \(-1>0\)) וגם \(0\le\left\{ -1|1\right\} \) (כי הסיכוי היחיד של זה לא להתקיים הוא אם \(0>1\)). באותו אופן בדיוק מקבלים גם ש-\(\left\{ -1|2\right\} =0\) ובאופן כללי שאם \(L\) כוללת כולה מספרים קטנים מ-0 ו-\(R\) כולה מספרים גדולים מ-0, אז \(\left\{ L|R\right\} \) הוא 0. זה אמור להיות שכנוע פורמלי עבורכם, אבל האינטואיציה כבר אמורה להיות ברורה לכם בזכות הגישה ה"משחקית" שהצגתי קודם.

קיבלנו את המספרים השלמים. בואו נגדיר חיבור! ההגדרה די אינטואיטיבית: \(x+y\triangleq\left\{ x^{L}+y,x+y^{L}|x^{R}+y,x+y^{R}\right\} \). כמו קודם, צריך קצת עבודת הכנה כדי שאפשר יהיה להתחיל להשתמש בה – למשל, לראות קודם כל ש-\(0+0=0\), ואז ש-\(0+x=x\) לכל מספר \(x\), באופן אינדוקטיבי, וכן הלאה – אבל מהר מאוד אפשר כבר לראות דברים בסגנון \(1+\left(-1\right)=0\) ו-\(1+1=2\) וכדומה. ועכשיו אפשר להתחיל לדבר על מספרים כמו \(\left\{ 0|1\right\} \) ולהוכיח ש-\(\left\{ 0|1\right\} +\left\{ 0|1\right\} =1\), מה שנותן לנו הצדקה לסימון \(\left\{ 0|1\right\} =\frac{1}{2}\). שימו לב – כפי שאיימתי, אני מדלג בקלילות מעל ההוכחה הזו, שדווקא דורשת עבודה.

בהינתן חיבור, חיסור מוגדר על ידי חיבור עם הנגדי – כאן הגדרת הנגדי היא פשוטה: \(-x=\left\{ -x^{R}|-x^{L}\right\} \). קחו רגע לחשוב למה זה נכון.

טוב, אם יש לנו חיבור, צריך גם כפל, נכון? ההגדרה המתבקשת לכפל היא \(xy\triangleq\left\{ x^{L}y,xy^{L}|x^{R}y,xy^{R}\right\} \). ההגדרה הזו לא עובדת. למעשה, היא נכשלת בצורה מחפירה לחלוטין שבוודאי תשעשע אתכם אם תבינו בעצמכם למה. אז קחו רגע לחשוב ואל תקראו את השורה הבאה.

חשבתם? אוקיי. ההגדרה לא עובדת פשוט כי זו ההגדרה של חיבור. אותו דבר בדיוק. רק הסימבול שבו אני משתמש (או ליתר דיוק, לא משתמש, כי כפל מתואר כאן בלי סימבול) שונה.

אז צריך הגדרה אחרת. וההגדרה של קונווי היא לא פשוטה, אבל הוא מסביר אותה יפה בספר. אני רק אביא אותה כאן לצורך שלמות:

\(xy\triangleq\left\{ x^{L}y+xy^{L}-x^{L}y^{L},x^{R}y+xy^{R}-x^{R}y^{R}|x^{L}y+xy^{R}-x^{L}y^{R},x^{R}y+xy^{L}-x^{R}y^{L}\right\} \)

עכשיו יש לנו את כל ההגדרות הבסיסיות ואת האינטואיציה הראשונית, ואפשר להתחיל להתקדם אל היעד הנכסף הבא שלנו: המספר \(\frac{1}{3}\)! זאת, בפוסט הבא.

משפט קלייני – הוכחה נוספת

אולי המשפט המרכזי בסדרת הפוסטים שלי על שפות רגולריות היה משפט קלייני. כזכור, שפה רגולרית היא שפה שקיים אוטומט סופי דטרמיניסטי שמקבל אותה, אבל משפט קלייני נתן אפיון שונה לגמרי עבורה, שאפשר לנו להבין מה המבנה הכללי של אוסף השפות הרגולריות. כזכור, הוא אמר שהשפות הרגולריות הן בדיוק השפות שמתקבלות על ידי פעולות האיחוד, השרשור וסגור-קלייני ("הפעולות הרגולריות"), מתוך אוסף בסיס של שפות שכלל את השפה הריקה, השפה שהמילה היחידה בה היא המילה הריקה, ולכל אות \(\sigma\in\Sigma\), השפה \(\left\{ \sigma\right\} \).

ההוכחה הייתה נפלאה, לטעמי. הרעיון היה להתחיל מאוטומט \(A\) ולהגדיר שפות שאיכשהו ממדלות חישובים ב-\(A\): השפה \(L_{i,j}^{k}\) תיארה את כל המילים שמעבירות את האוטומט מהמצב \(q_{i}\) למצב \(q_{j}\) בלי לעבור במצב עם אינדקס גדול מ-\(k\) בתוך החישוב הזה. את השפות הללו היה ניתן לתאר בצורה רקורסיבית באמצעות הפעולות הרגולריות, כשתנאי הבסיס של הרקורסיה היו שפות פשוטות במיוחד שמתקבלות משפות הבסיס על ידי פעולות רגולריות.

עכשיו אני רוצה לתת הוכחה קצת שונה.

כמובן, שאלה מתבקשת תמיד כשנותנים הוכחה נוספת למשהו שכבר הוכחנו היא – למה? למה בכלל לטרוח להוכיח משהו שוב? אנחנו כבר יודעים שהוא נכון! אז למה למה למה?

ובכן, כי זה מגניב.

וגם, כי זה נותן לנו עוד נקודת מבט מעניינת, וקצת יותר כללית, על המשפט ומה שהוא אומר. מה שאני אעשה יהיה להוכיח את המשפט לא עבור אוטומטים סופיים דטרמיניסטיים, אלא עבור סוג מוכלל שלהם, והמשפט שאוכיח יהיה יותר כללי מאשר משפט קלייני הרגיל. ובנוסף לכל זה, ההוכחה עצמה היא מאוד טבעית ומתבקשת – מתחילים מאוטומט מוכלל שכזה, ואז באופן איטרטיבי מעיפים ממנו מצבים ומתקנים את האוטומט בהתאם; איכשהו בסוף נגיע לאוטומט טריוויאלי שכולל תיאור "מיידי" של השפה. בהמשך הדיבור המעורפל הזה יתברר.

לאוטומט רגיל יש פונקציית מעברים שמקבלת את המצב הנוכחי ואות מ-\(\Sigma\), ומחזירה את המצב שעוברים עליו. מבחינה רעיונית, אנחנו "אוכלים" את האות הזו מהקצה הימני של הקלט תוך כדי ביצוע המעבר. כבר ראינו הרחבה של המודל הרגיל שבו את האות מ-\(\Sigma\) מחליפה המילה הריקה, ואז האינטואיטיציה הייתה שביצענו מעבר אבל לא אכלנו כלום מהקלט. אם כן, בואו ניקח את הרעיון הזה צעד אחד קדימה ונגדיר פונקציית מעברים שיכולה לקבל כל מילה שהיא: \(\delta:Q\times\Sigma^{*}\to2^{Q}\). שימו לב שאני מצהיר מראש שהפונקציה הזו מתארת אוטומט אי דטרמיניסטי: עבור זוג של מצב ומילה, ייתכן שעוברים ליותר ממצב אחד, וייתכן גם שלא עוברים לשום מצב עבורה.

איך נראה "חישוב" באוטומט כזה? ובכן, זה לא כזה מסובך: בכל צעד חישוב "מנחשים" מילה \(w\) כלשהי שהיא רישא של הקלט הנוכחי, "אוכלים" אותה מהקלט, ועוברים למצב כלשהו מתוך \(\delta\left(q,w\right)\), כאשר \(q\) הוא המצב הנוכחי. להגדיר את פונקציית המעברים המורחבת מבחינה פורמלית זה עניין קצת מעצבן ולא ניכנס אליו – תחת זאת, בואו נראה עוד דרך לחשוב על האוטומט הזה.

בתיאור הרגיל של אוטומט, אנחנו מציירים אותו בתור גרף שבו הצמתים הם מצבי האוטומט, ויש קשת ממצב אחד לאחר עם סימונים שהם האותיות שמעבירות את המצב הראשון לשני. בהכללה שלי אפשר לחשוב שיש קשת בין כל זוג מצבים (וגם בין מצב לעצמו), ולכל קשת כזו יש סימון שהוא שפה (שיכולה להיות גם השפה הריקה, למשל, ובמצב הזה אני אתייחס לכך כאילו פשוט אין קשת). פורמלית, לכל זוג מצבים \(q_{i},q_{j}\) קיימת שפה \(L_{ij}\subseteq\Sigma^{*}\) שמכילה את כל המילים שמעבירות בצעד יחיד את \(q_{i}\) אל \(q_{j}\): \(L_{ij}=\left\{ w\in\Sigma^{*}\ |\ q_{j}\in\delta\left(q_{i},w\right)\right\} \). אפשר להגדיר את השפה שהאוטומט מקבל בצורה הבאה: לכל מסלול \(q_{i_{1}}\to q_{i_{2}}\to\dots\to q_{i_{k}}\) כך שהמצב הראשון בו הוא התחלתי והמצב האחרון בו הוא מקבל, נסתכל על השרשור \(L_{i_{1}i_{2}}L_{i_{2}i_{3}}\cdots L_{i_{k-1}i_{k}}\). נאחד את כל השרשורים הללו, לכל (אולי אינסוף) המסלולים ממצב התחלתי למצב מקבל – קיבלנו את שפת האוטומט.

המודל הזה כמובן חזק בצורה פסיכית. כל שפה \(L\) ניתן לקבל על ידי אוטומט טריוויאלי לגמרי, עם מצב התחלתי \(q_{0}\), מצב מקבל יחיד \(q_{f}\), ומעבר \(\delta\left(q_{0},L\right)=q_{f}\). למעשה, זו הפואנטה – בגישת "צמצום האוטומט" שתיארתי קודם, אנחנו נתחיל מאוטומט כללי ונצטמצם בסוף לאוטומט טריוויאלי שכזה. עדיין, אם המודל חזק כל כך, מה הטעם בו? מה למדנו ממנו?

ובכן, זה פשוט. הנה הגרסה המורחבת של קלייני: השפה שמתקבלת על ידי אוטומט נתון כלשהו מהמודל הזה נמצאת בקבוצה האינדוקטיבית שנוצרת על ידי הפעולות הרגולריות, כשקבוצת שפות הבסיס כוללת בדיוק את השפות \(L_{ij}\) עבור האוטומט הזה. למה זו גרסה מורחבת של קלייני? כי כל אוטומט סופי רגיל הוא כזה שהשפות \(L_{ij}\) שלו כוללות לכל היותר את כל השפות מהצורה \(\left\{ \sigma\right\} \), את השפה \(\left\{ \varepsilon\right\} \) (למשל, במעבר ממצב לעצמו, או אם יש לנו מסעי-\(\varepsilon\)) ואת השפה \(\emptyset\) (כשיש זוג מצבים שאין בכלל מעבר מהראשון אל השני), ואיחודים שלהן (למשל, אם \(\delta\left(q,a\right)=p\) וגם \(\delta\left(q,b\right)=p\) ואלו המעברים היחידים שמעבירים את \(q\) אל \(p\) אז נקבל ש-\(L_{qp}=\left\{ a,b\right\} \)). זה בדיוק הבסיס שלנו במשפט קלייני ה"רגיל".

נעבור להוכחת המשפט עצמו. בואו ניקח אוטומט מוכלל \(A\) כלשהו. נסמן את מצביו ב-\(Q=\left\{ q_{1},q_{2},\dots,q_{n}\right\} \). נוסיף שני מצבים מיוחדים \(q_{s},q_{f}\) כך ש-\(q_{s}\) יהיה המצב ההתחלתי היחיד, \(q_{f}\) יהיה המצב המקבל היחיד, ויהיה מעבר-\(\varepsilon\) מ-\(q_{s}\) לכל מצב התחלתי ב-\(A\) ומכל מצב מקבל ב-\(A\) ל-\(q_{f}\). הרעיון עכשיו יהיה להעיף באופן סדרתי את הצמתים \(q_{1},q_{2},\dots,q_{n}\) מהאוטומט, כך שאחרי כל העפה אנחנו מתקנים את הסימונים על הקשתות שנותרו באוטומט בצורה שמבטיחה שנקבל אוטומט שקול (כלומר, שמקבל את אותה שפה). אחרי שנעיף את כל הצמתים הללו נישאר רק עם \(q_{s},q_{f}\), והקשת מ-\(q_{s}\) אל \(q_{f}\) תקודד בדיוק את השפה שלנו (שאר הקשתות בגרף לא ישפיעו; הקשת מ-\(q_{f}\) אל \(q_{s}\) היא עם הסימון \(\emptyset\) והקשתות מהצמתים לעצמם הן עם הסימון \(\left\{ \varepsilon\right\} \)). לכן כל מה שאנחנו צריכים לעשות כדי להוכיח את המשפט הוא להראות איך כל "תיקון סימוני קשתות" ניתן לביצוע עם הסימונים הנוכחיים שעל הקשתות והפעולות הרגולריות. כאן זה כבר תרגיל נחמד שאפשר לתת לסטודנטים לאוטומטים והם יצליחו לפתור בעצמם; אבל בואו נעשה אותו במפורש. כפי שתראו, זה מאוד מזכיר את הבניה שבה השתמשנו בהוכחת משפט קלייני המקורי.

נניח שאנחנו רוצים להעיף את הצומת \(q_{i}\). זה יחסל את כל המסלולים שעוברים דרך \(q_{i}\). מכיוון ש-\(q_{i}\) הוא לא המצב ההתחלתי או הסופי, אנחנו מתעניינים מלכתחילה רק במסלולים ש-\(q_{i}\) מופיע במהלכם, כלומר שיש צומת שנכנסים ממנו אל \(q_{i}\) וצומת שיוצאים מ-\(q_{i}\) אליו. נרצה, אם כן, לחבר את כל הצמתים שנכנסים ל-\(q_{i}\) אל כל הצמתים שיוצאים מ-\(q_{i}\).

בואו ניקח שני צמתים כאלו: צומת \(q_{j}\) כך שיש קשת \(q_{j}\to q_{i}\), וצומת \(q_{k}\) כך שיש קשת \(q_{i}\to q_{k}\) (זכרו שאצלנו בעצם יש קשת מכל צומת לכל צומת, אבל היא עשויה להיות מסומנת בשפה הריקה ואם תבדקו, תראו שזה שקול לכך שלא תהיה קשת). אנחנו רוצים "להוסיף" קשת מ-\(q_{j}\) אל \(q_{k}\), אבל כמובן שאולי כבר יש כזו – השפה \(L_{jk}\) מתארת את הסימון שלה. אז אנחנו רוצים לבנות \(L_{jk}^{\prime}\) "מתוקנת".

מה השפה המתוקנת צריכה לכלול? את כל המילים שמעבירות את \(q_{j}\) אל \(q_{k}\) באופן ישיר, כלומר את \(L_{jk}\), וכמו כן את כל המילים שמעבירות את \(q_{j}\) אל \(q_{k}\) באמצעות שימוש במצב הביניים \(q_{i}\). נאיבית אפשר לחשוב שהמילים הללו הן בדיוק \(L_{ji}\cdot L_{ik}\), כלומר שרשור של מילה שמעבירה אותנו מ-\(q_{j}\) אל \(q_{i}\) ואז מ-\(q_{i}\) אל \(q_{k}\); אבל זכרו שאנחנו עשויים להישאר ב-\(q_{i}\) במשך מספר צעדים שבהם נלך מ-\(q_{i}\) אל עצמה. מכאן שהשפה היא \(L_{ji}\cdot L_{ii}^{*}\cdot L_{ik}\), וקיבלנו ש-\(L_{jk}^{\prime}=L_{jk}\cup L_{ji}\cdot L_{ii}^{*}\cdot L_{ik}\). זה מסיים את ההוכחה, ובצורה מאוד נחמדה – אנחנו רואים בדיוק איך כל שלוש הפעולות הרגולריות באות לידי ביטוי באותה משוואה.

שאלה מעניינת אחת עולה מכל העניין הזה. משפט קלייני נותן לנו, דה פקטו, דרך לבנות ביטוי רגולרי עבור שפה בהינתן האוטומט שלה – ביטוי רגולרי די מסובך, אבל ביטוי רגולרי. האם הביטוי שנקבל מתוך ההוכחה ה"חדשה" שונה מהותית מאשר הביטוי שנקבל מההוכחה ה"ישנה"? התשובה היא כן ולא. כן, כי אכן אנחנו עשויים לקבל ביטויים שונים (ושימו לב ששתי ההוכחות היו תלויות בסדר כלשהו על מצבי האוטומט, וסדרים שונים יניבו ביטויים רגולריים שונים). לא, כי ישנן מניפולציות סינטקטיות מסויימות שניתן לבצע על הביטויים הרגולריים כדי לקבל מתוך האחד את השני. זה מביא אותנו לתחום שאני לא הולך להיכנס אליו בפוסטים הללו כי לטעמי הוא יותר מדי טכני מכדי להצדיק פוסטים מעניינים – הבדיקה עד כמה שני ביטויים רגולריים הם שקולים, על פי סוג המניפולציות הסינטקטיות שמעבירות אחד אל השני (ככל שנדרשות יותר פעולות מתוחכמות יותר כך השקילות היא פחות "ברורה").

אם כן, ההוכחה לא נותנת לנו שום דבר חדש לגמרי – אבל מה אכפת לי, היא ממש יפה.

למת הניפוח לשפות רגולריות – גרסה מלאה

הצגתי כאן בעבר את למת הניפוח לשפות רגולריות, ואני רוצה לחזור עכשיו לנושא ולהציג גרסה נוספת, מוכללת, של הלמה – גרסה שהיא חזקה מספיק כדי לתת לנו תוצאת "אם ורק אם". כזכור, למת הניפוח נתנה לנו תנאי הכרחי לכך ששפה תהיה רגולרית: דהיינו, אם השפה לא קיימה את הלמה, זו הייתה הוכחה שהשפה אינה רגולרית. הבעיה הייתה שהיו שפות שקיימו את הלמה למרות שהן לא רגולריות. הגרסה שאני אציג עכשיו לא סובלת מהבעיה הזו – שפה היא רגולרית אם ורק אם היא מקיימת את הלמה; אבל כמובן, הניסוח של הלמה מורכב הרבה יותר מאשר קודם, ולכן יהיה יותר קשה להראות ששפה לא מקיימת אותה. העניין שלי בתוצאה הזו, אם כן, הוא יחסית תיאורטי; כדי להראות ששפה היא לא רגולרית עדיין אנסה קודם כל להשתמש בלמה ה"רגילה". אגב, לי כל זה מזכיר את משפט רייס בחישוביות; גם לו יש גרסה פשוטה שהיא חד כיוונית, וגרסה יותר מעניינת שהיא אם ורק אם.

הפוסט הזה, מן הסתם, מניח שאתם כבר מכירים את למת הניפוח, ולכן אצלול ישר לעומק הסיפור. אם אתם מאבדים אותי, נסו לקרוא שוב את הפוסט הקודם.

הניסוח הכללי של הלמה לא קל לעיכול, אז בואו ניזכר לרגע מה קרה בניסוח הפשוט ואיך הגענו אליו. \(L\) מקיימת את הלמה אם קיים מספר טבעי \(n\) כך שכל מילה \(z\in L\) המקיימת \(\left|z\right|\ge n\) ניתנת לפירוק \(z=uvw\) כך ש-\(\left|uv\right|\le n\) ו-\(\left|v\right|\ge1\) ו-\(uv^{i}w\in L\) לכל \(i\ge0\). למה זה עובד? כי לוקחים את \(n\) להיות מספר המצבים באוטומט עבור \(L\) ומסתכלים על ריצה שמקבלת את \(z\). כבר אחרי \(n\) הצעדים הראשונים של הריצה יהיה מצב שחוזר על עצמו; מסמנים ב-\(u\) את מה שקראנו עד להגעה הראשונה למצב, ב-\(v\) את מה שקראנו כדי לעבור מהמצב אל עצמו, וב-\(w\) את יתר המילה. התנאי של ה-\(\left|uv\right|\le n\) נובע מכך שההגעה השניה שלנו למצב הזה היא במסגרת \(n\) הצעדים הראשונים.

אם כן, הרכיב המרכזי בהוכחה הוא העניין הזה של "ביצעת יותר מ-\(n\) צעדים? קבל מעגל!". הנקודה החשובה היא שזה בכלל לא חשוב מתי הצעדים הללו מתבצעים – בהתחלה, באמצע, בסוף, עם פער ביניהם, בלי פער ביניהם – אם ניקח את ריצת האוטומט על מילה, ו"נעצור כדי להציץ" את הריצה \(n+1\) פעמים, אז יהיו שתי הצצות כאלו לפחות שיראו שהאוטומט באותו מצב בדיוק (ב-\(n\) צעדים יש \(n+1\) "הצצות": המצב בהתחלה והמצב אחרי כל צעד). אם זיהינו שתי הצצות שבהן האוטומט היה באותו מצב בדיוק, אז אפשר לקחת את כל הריצה בין שתיהן (לא רק את ההצצות בין שתיהן; את כל הריצה) ולשכפל אותה \(i\) פעמים.

אז הנה ניסוח כללי יותר מאשר קודם: אם \(L\) רגולרית אז קיים \(n\) כך שלכל \(z\in L\) ולכל פירוק \(z=uv_{1}v_{2}\dots v_{n}w\) שלה כך ש-\(\left|v_{i}\right|\ge1\) לכל \(1\le i\le n\), קיימים זוג אינדקסים \(0\le k_{1}<k_{2}\le n\) כך ש-\(uv_{1}\dots\left(v_{k_{1}+1}\dots v_{k_{2}}\right)^{i}\dots v_{n}w\in L\) לכל \(i\ge0\). זו בבירור הכללה של הלמה הרגילה: אם אני בוחר \(u=\varepsilon\) ו-\(v_{i}=z_{i}\) (כלומר, ה-\(v\)-ים הם בדיוק \(n\) האותיות הראשונות ב-\(z\)) אני אקבל את הלמה הרגילה (כאשר מי שאני קורא לו \(v\) בלמה הרגילה יהיו האותיות \(z_{k_{1}}\dots z_{k_{2}}\)).

הניסוח הזה הוא עדיין לא אם ורק אם. כדי לקבל משהו שהוא אם ורק אם, צריך להוסיף עוד דבר אחד: במקום לדבר רק על המילים ב-\(z\), צריך לדבר על כל המילים, כולל כאלו שאינן בשפה. הנה הניסוח הכללי ביותר, שהוא אם-ורק-אם:

אם \(L\) רגולרית אז קיים \(n\) כך שלכל \(z\) ולכל פירוק \(z=uv_{1}v_{2}\dots v_{n}w\) שלה כך ש-\(\left|v_{i}\right|\ge1\) לכל \(1\le i\le n\), קיימים זוג אינדקסים \(0\le k_{1}<k_{2}\le n\) כך שלכל \(i\ge0\) מתקיים ש- \(z\in L\iff uv_{1}\dots\left(v_{k_{1}+1}\dots v_{k_{2}}\right)^{i}\dots v_{n}w\in L\).

במילים אחרות, עבור הפירוק הנתון, או שכל הניפוחים שלו יהיו ב-\(L\), או שאף אחד מהם לא יהיה ב-\(L\). זה לא כל כך מפתיע שאם \(L\) רגולרית אז התכונה הזו מתקיימת: זכרו מה ניפוח עושה בפועל – הוא לוקח ריצה קיימת של אוטומט, ומשנה את מספר הפעמים שבהן אנחנו רצים על מקטע מיותר של הריצה – כזה שבתחילתו ובסופו אנחנו בדיוק באותו מצב, ולכן בין אם נשמוט אותו לגמרי ובין אם נחזור עליו אינספור פעמים – הריצה עצמה תישאר אותו דבר. המצב הסופי שנגיע אליו יהיה אותו דבר – או שהוא יהיה תמיד מקבל, או שהוא יהיה תמיד לא מקבל (אני מניח, כמובן, שהאוטומט שלנו דטרמיניסטי).

מה שמעניין הוא שהתנאי הזה הוא גם מספיק, כלומר שאם הוא מתקיים, אז \(L\) רגולרית. ולמעשה, אפילו אפשר להחליש אותו קצת ולהתייחס רק למקרה שבו \(i=0\). כלומר, הנה המשפט שאני רוצה להוכיח:

בהינתן שפה \(L\), אם קיים \(n\) כך שלכל \(z\) ולכל פירוק \(z=uv_{1}v_{2}\dots v_{n}w\) שלה כך ש-\(\left|v_{i}\right|\ge1\) לכל \(1\le i\le n\), קיימים זוג אינדקסים \(0\le k_{1}<k_{2}\le n\) כך שמתקיים \(z\in L\iff uv_{1}\dots v_{k_{1}}v_{k2+1}\dots v_{n}w\in L\), אז \(L\) רגולרית.

כאן \(uv_{1}\dots v_{k_{1}}v_{k2+1}\dots v_{n}w\) זו פשוט דרך קומפקטית לכתוב \(uv_{1}\dots\left(v_{k_{1}+1}\dots v_{k_{2}}\right)^{0}\dots v_{n}w\).

מעכשיו אקרא לדבר הזה "התכונה". שימו לב שהתכונה הזו תלויה בפרמטר שמאפיין אותה – \(n\). מכאן ואילך גם הוא יהיה קבוע.

למה שהתכונה הזו תהיה שקולה לכך ששפה היא רגולרית? איך בכלל אפשר להראות שהשפה היא רגולרית? נבנה לה אוטומט? ובכן, לא. בואו ניזכר בקריטריון נטול אוטומטים לכך ששפה היא רגולרית: אם משפט מייהיל-נרוד חל עליה. כלומר, אם יש ליחס השקילות \(R_{L}\) רק מספר סופי של מחלקות שקילות, או באופן שקול – אם קיים רק מספר סופי של שפות מהצורה \(u^{-1}L\) (כזכור, \(u^{-1}L\triangleq\left\{ v\in\Sigma^{*}\ |\ uv\in L\right\} \) ).

מה שהתכונה של למת הניפוח נותנת לנו הוא עוד משהו שהוא מעין-סופי שכזה. בניסוח מילולי התכונה אומרת "לכל מילה מאורך גדול מ-\(n\) אפשר למצוא מילה קצרה יותר כך ששתיהן ביחד ב-\(L\) או לא ב-\(L\)". אם חוזרים על התהליך הזה מספיק פעמים מגיעים אל מילה מאורך לכל היותר \(n\) שגורלה זהה לגורל המילה המקורית שהתחלנו ממנה. זה אומר שהשפה \(L\) שלנו מאופיינת במובן מסויים על פי המילים עד גודל \(n\) ששייכות אליה. אם נצליח להוכיח ששתי שפות שונות \(L_{1},L_{2}\) ששתיהן מקיימות את התכונה עבור אותו קבוע \(n\) לא יכולות להיות מאופיינות על ידי אותה קבוצה של מילים-עד-גודל \(n\), נלמד מזה משהו מעניין מאוד: שיש רק מספר סופי של שפות שמקיימות את התכונה עבור \(n\) (אגב, אני מזהיר מראש שאני משקר כדי לתת לכם אינטואיציה: אלו לא "מילים-עד-גודל \(n\)" אלא "מילים-עד-גודל \(N\) שהוא מספר שונה לגמרי ועוד נבין בהמשך איך מגיעים אליו אבל סבלנות חברים").

זה מתווה לנו את האסטרטגיה להוכחה: השלב הראשון, הקל, יהיה להוכיח שאם \(L\) מקיימת את התכונה עבור הקבוע \(n\), אז גם \(u^{-1}L\) מקיימת את התכונה עבור אותו קבוע \(n\). השלב השני, הקשה יותר, יהיה להוכיח את מה שדיברתי עליו בפסקה הקודמת. אחרי שנסיים את שני השלבים הללו, משפט מייהיל-נרוד מסיים את העבודה: יש רק מספר סופי של שפות שמקיימות את התכונה עבור \(n\), וכל \(u^{-1}L\) מקיימת את התכונה עבור \(n\), אז יש רק מספר סופי של שפות מהצורה \(u^{-1}L\).

נתחיל עם השלב הקל. אנחנו מניחים ש-\(L\) מקיימת את התכונה עבור \(n\). בואו ניקח \(u\in\Sigma^{*}\) כלשהו ונוכיח שגם \(u^{-1}L\) מקיימת את התכונה. כלומר, ניקח \(z\in u^{-1}L\) ופירוק \(z=xv_{1}v_{2}\dots v_{n}y\) של \(z\). מה שאנחנו צריכים לעשות הוא למצוא זוג אינדקסים כך שאפשר להשמיט את ה-\(v\)-ים שביניהם ולקבל מילה ששקולה ל-\(z\) מבחינת שייכות ל-\(u^{-1}L\).

כעת, מכיוון ש-\(z\in u^{-1}L\), נובע מכך ש-\(uz\in L\). אז אפשר להשתמש בתכונה על \(uz\): ניקח את הפירוק \(z=uxv_{1}\dots v_{n}y\) ונמצא שני אינדקסים עבורו. שימו לב כמה העסק פשוט – את ה-\(u\) שבתחילת המילה אנחנו דוחפים לאיזור של ה"לא מעניין, אין צורך למחוק מכאן דברים", והכל ממשיך כרגיל. אנחנו מקבלים שקיימים \(k_{1},k_{2}\) כך ש-\(uz\in L\iff uxv_{1}\dots v_{k_{1}}v_{k2+1}\dots v_{n}y\in L\); המסקנה המיידית היא ש-\(z\in u^{-1}L\iff xv_{1}\dots v_{k_{1}}v_{k2+1}\dots v_{n}y\in u^{-1}L\), וזה מה שרצינו להראות. אז זה היה קל.

בואו נעבור לחלק הקשה. בשביל החלק הקשה, אני הולך לשלוף שפן מהכובע: משפט רמזי. יש לי פוסט בנושא, אבל הנה הרעיון הבסיסי, בכמה ניסוחים, עבור מי שלא מכיר חלק מהטרמינולוגיות:

לכל זוג מספרים \(r,s\) טבעיים קיים מספר \(R\left(r,s\right)\) כך שבכל קבוצה עם לפחות \(R\left(r,s\right)\) אנשים שכל זוג מביניהם הם או אויבים או חברים, קיימת קבוצה מגודל \(r\) שכולם בה חברים, או קבוצה מגודל \(s\) שכולם בה אויבים.

לכל זוג מספרים \(r,s\) טבעיים קיים מספר \(R\left(r,s\right)\) כך שבכל גרף מלא עם לפחות \(R\left(r,s\right)\) שקשתותיו צבועות באדום או כחול, קיימת קבוצה של \(r\) צמתים שכל הקשתות ביניהם אדומות, או \(s\) צמתים שכל הקשתות ביניהם כחולות.

לכל זוג מספרים \(r,s\) טבעיים קיים מספר \(R\left(r,s\right)\) כך שבכל גרף עם לפחות \(R\left(r,s\right)\) קודקודים קיים קליק מגודל \(r\) או קבוצה בלתי תלויה מגודל \(s\). זה הניסוח שבו אני אשתמש בהמשך, ואני מקווה שהוא ברור עכשיו (קליק היא קבוצה של צמתים כך שבין כל זוג מביניהם קיימת קשת; קבוצה בלתי תלויה היא קבוצת צמתים כך שלכל זוג מביניהם אין קשת).

יופי, איך זה קשור בכלל?

בואו ניקח את \(N=R\left(n+1,n+1\right)\). אני רוצה לטעון שאם יש לי שתי שפות \(L_{1},L_{2}\), כך ש:

  1. \(L_{1},L_{2}\) מקיימות את התכונה עבור \(n\).
  2. \(L_{1},L_{2}\) מסכימות על כל המילים עד גודל \(N-1\), דהיינו \(\left\{ w\in L_{1}\ |\ \left|w\right|\le N-1\right\} =\left\{ w\in L_{2}\ |\ \left|w\right|\le N-1\right\} \).

אז מתקיים \(L_{1}=L_{2}\). זה מסיים את ההוכחה, כי יש רק מספר סופי של קבוצות מילים עד גודל \(N-1\) (יש בדיוק \(2^{N-1}\) כאלו).

כלומר, אנחנו רוצים להוכיח ש-\(w\in L_{1}\iff w\in L_{2}\) לכל \(w\in\Sigma^{*}\). ההוכחה תהיה באינדוקציה על האורך של \(w\). הבסיס נתון לנו, עד \(\left|w\right|=N-1\). לכן אפשר להניח ש-\(\left|w\right|\ge N\). בואו נסמן את \(N-1\) האותיות הראשונות של \(w\) במפורש: \(w=a_{1}a_{2}\dots a_{N-1}w^{\prime}\). עכשיו אפשר להגדיר את הגרף שעליו נפעיל את משפט רמזי שלנו. הצמתים יהיו פשוט המספרים \(V=\left\{ 0,2,\dots,N-1\right\} \) (ולכן הגרף גדול מספיק כדי שנוכל להפעיל עליו את משפט רמזי). הקשתות יהיו בין זוגות אינדקסים שעבורם התכונה של \(n\) מתקיימת ביחס ל-\(L_{1}\), כלומר

\(E=\left\{ \left(i,j\right)\ |\ 0\le i<j\le N-1,\ a_{1}a_{2}\dots a_{i}a_{j+1}\dots a_{N-1}w^{\prime}\in L_{1}\right\} \)

קרוב לודאי שאתם מרגישים שיש פה חוסר סימטריה מוזר – השתמשתי ב-\(L_{1}\), אבל מה עם \(L_{2}\)? ובכן, שימו לב שהייתי יכול באותה מידה בדיוק להשתמש ב-\(L_{2}\) ולקבל את אותה \(E\), בזכות הנחת האינדוקציה (כי אנחנו כבר משוכנעים ש-\(L_{1},L_{2}\) זהות על כל מילה ארוכה פחות מ-\(w\)).

עכשיו אפשר להשתמש במשפט רמזי. נקבל שקיימת קבוצה \(U\) של \(n+1\) מספרים \(F=\left\{ i_{0},i_{1},\dots,i_{n}\right\} \), כך שכל זוג מספרים מהקבוצה שייך ל-\(E\), או שכל זוג מספרים מהקבוצה לא שייך ל-\(E\).

כעת סוף סוף אפשר להשתמש בנתון הנוסף שלנו, לפיו \(L_{1},L_{2}\) מקיימות את התכונה עבור \(n\). אנחנו רוצים להשתמש בתכונה עבור \(w\), כמובן, אבל בשביל זה אנחנו קודם כל צריכים להציג פירוק של \(w\): הפירוק יתבסס על קבוצת האינדקסים שמשפט רמזי נתן לנו. נגדיר \(w=xv_{1}v_{2}\dots v_{n}y\) כך ש-\(v_{1}=a_{i_{0}}\dots a_{i_{1}}\) ו-\(v_{2}=a_{i_{1}}\dots a_{i_{2}}\) וכן הלאה עד \(v_{n}=a_{i_{n-1}}\dots a_{i_{n}}\).

עכשיו צריך להבדיל בין שני המקרים של משפט רמזי.

במקרה הראשון, שבו כל זוג איברים מ-\(U\) מחוברים בקשת, אנחנו יודעים שלכל \(i<j\) כך ש-\(i,j\in U\) נקבל ש-\(xv_{1}v_{2}\dots v_{i}\dots v_{j+1}\dots v_{n}\in L_{1}\) וגם \(xv_{1}v_{2}\dots v_{i}\dots v_{j+1}\dots v_{n}\in L_{2}\). זו בעצם דרך "לסדר" את התכונה – התכונה הרי אומרת רק שקיימים זוג אינדקסים שעבורם אנחנו מקבלים מילה שגורלה זהה לזה של \(w\). עכשיו אנחנו אומרים שהמשחק הזה מכור מראש – לכל זוג אינדקסים שנבחר, התוצאה תהיה תמיד זהה – שייכות לשפה. רואים איך זה מסיים?

עדיין, בואו נכתוב את זה באופן מפורש. מכיוון ש-\(L_{1}\) מקיימת את התכונה, קיימים \(k_{1},k_{2}\) כך ש-\(w\in L_{1}\iff xv_{1}\dots v_{k_{1}}\dots v_{k_{2}+1}\dots v_{n}\in L_{1}\). מכיוון שאגף ימין מתקיים, אנחנו מקבלים ש-\(w\in L_{1}\). באותו אופן בדיוק, מכיוון ש-\(L_{2}\) מקיימת את התכונה, קיימים \(t_{1},t_{2}\) (אולי שונים מ-\(k_{1},k_{2}\) – כל הפואנטה היא שזה לא משנה, בשביל זה היינו צריכים את רמזי) כך ש-\(w\in L_{2}\iff xv_{1}\dots v_{t_{1}}\dots v_{t_{2}+1}\dots v_{n}\in L_{2}\), וקיבלנו שגם \(w\in L_{2}\). המקרה השני של משפט רמזי הוא אותו הדבר, רק שנקבל הפעם ש-\(w\notin L_{1}\) וגם \(w\notin L_{2}\). סך הכל קיבלנו את מה שרצינו: \(w\in L_{1}\iff w\in L_{2}\). זה מסיים את ההוכחה.

לא מגניב? מגניב. שימושי? שאלה טובה. רוצים להציע בתגובות שפות שקשה להוכיח שהן רגולריות אלא אם משתמשים בלמה הזו?

משפט מייהיל-נרוד – נקודת מבט נוספת, ואלגוריתמי מינימיזציה

בכל הנושא של תורת השפות הפורמליות, המשפט החביב עלי הוא משפט מייהיל-נרוד. כל כך חביב עלי, שבפוסט הזה אני הולך להציג אותו שוב, ובצורה שונה מזו שבה הצגתי אותו בפוסט הקודם שלי בנושא. שתי נקודות המבט על המשפט הן דואליות באופיין (הן אומרות את אותו הדבר, אבל כל אחת מסתכלת על הדבר הזה מנקודת מבט שונה ואפילו מנוגדת קצת), וזו שאציג עכשיו תהיה שימושית בהמשך, עם עוד כמה תוצאות יפות שאני רוצה להראות. בפרט, היא תהיה שימושית כדי לטפל בבעיה שעד כה לא התייחסתי אליה – איך אפשר למצוא בפועל את האוטומט המינימלי עבור שפה שמשפט מייהיל-נרוד מבטיח את קיומו. אראה שני אלגוריתמים שעושים את זה – הראשון הוא נחמד ואינטואיטיבי יחסית, והשני הוא משהו פסיכי לחלוטין: כשראיתי אותו בפעם הראשונה התגובה שלי הייתה "מה, לעזאזל?!". הטיזר הזה מספיק לכם כדי שיתחשק לכם לראות איך אני מנסח מחדש את כל המונחים של נרוד בלשון אחרת? אחלה.

נתחיל בתזכורת מה הולך במשפט מייהיל-נרוד. בהינתן שפה \(L\) כלשהי מעל \(\Sigma^{*}\), הגדרנו יחס שקילות \(R_{L}\) מעל \(\Sigma^{*}\): \(xR_{L}y\) אם ורק אם לא קיימת "סיפא מפרידה" של \(x,y\) ביחס ל-\(L\), כלומר לכל \(z\in\Sigma^{*}\) מתקיים \(xz\in L\iff yz\in L\). סימנו את אוסף מחלקות השקילות של היחס הזה ב-\(\Sigma^{*}/R_{L}\), והמשפט אמר ש-\(L\) רגולרית אם ורק אם מספר מחלקות השקילות של היחס הוא סופי. האינטואיציה היא שניתן לבנות אוטומט (לאו דווקא סופי) עבור \(L\) שמצביו הם בדיוק \(\Sigma^{*}/R_{L}\), המצב ההתחלתי שלו הוא \(\left[\varepsilon\right]\) (מחלקת השקילות של \(\varepsilon\)), מצביו המקבלים הם מהצורה \(\left[w\right]\) עבור כל \(w\in L\), ופונקציית המעברים שלו היא \(\delta\left(\left[w\right],\sigma\right)=\left[w\sigma\right]\). הוכחנו שהאוטומט הזה הוא בעל מספר המצבים המינימלי מבין כל האוטומטים עבור \(L\), ולכן \(L\) הייתה רגולרית אם ורק אם המספר המינימלי הזה היה סופי.

עכשיו בואו נתאר את כל העסק הזה מזווית ראייה אחרת. אני הולך להשתמש במושג שהזכרתי קודם אבל לא קיבל עד כה את הזרקור שמגיע לו – המושג של חלוקה של שפות. נתחיל הפעם דווקא עם חלוקה במילה בודדת, ועם סימון חדש כדי להציג את זה. אם \(w=uv\) היא מילה ש-\(u\) היא רישא שלה, אז אסמן \(u^{-1}w\triangleq v\). כלומר, \(u^{-1}w\) היא מה שמקבלים מ-\(w\) אחרי שמסלקים ממנו את הרישא \(u\). האינטואיציה לסימון הזה עם החזקה של המינוס 1 מגיעה מתורת החבורות, ולא אכביר עליה מילים. צריך להיזהר קצת עם הסימון – אם \(u\) איננה רישא של \(w\), אז אין שום משמעות לסימון \(u^{-1}w\) בהקשר שלנו. כמו כן, באופן דומה אפשר גם להגדיר \(wu^{-1}\) אבל לא אזדקק לסימון הזה ולכן לא אציג אותו בהמשך.

עכשיו, אם \(L\) היא שפה כלשהו, אפשר להכליל את פעולת החלוקה עבורה: להגדיר \(u^{-1}L\triangleq\left\{ u^{-1}w\ |\ w\in L\right\} \), כאשר המוסכמה כאן היא שאם \(u^{-1}w\) אינו מוגדר הוא אינו משתתף בקבוצה (מבחינה פורמלית הסימון שלי לא תקין והייתי צריך להוסיף במפורש את התנאי ש-\(u\) היא רישא של \(w\), אבל אני בכוונה משתמש פה בסימון לא תקין – מה שנקרא Abuse of notation – כי חשוב לי להדגיש שככה זה עובד במתמטיקה – יותר חשובה לנו נוחות הסימון כל עוד כולם מבינים את הכוונה, מאשר נוקדנות ברמת הסימונים). גם את זה אפשר להכליל ולקבל חלוקה משמאל של שפות כדי שהגדרתי אותה פעם: \(L_{2}^{-1}L_{1}\triangleq\left\{ u^{-1}w\ |\ u\in L_{2},\in L_{1}\right\} \), אבל לא אזדקק לסימון הזה יותר מדי הפעם.

עכשיו אפשר לנסח את משפט מייהיל-נרוד בטרמינולוגיה החדשה שלנו: שפה \(L\) היא רגולרית אם ורק אם הקבוצה \(\left\{ u^{-1}L\ |\ u\in\Sigma^{*}\right\} \) סופית; וגודל הקבוצה שווה למספר המצבים באוטומט סופי דטרמיניסטי מינימלי עבור \(L\).

במבט ראשון אולי לא ברור מה הקשר, אבל במבט שני די ברור שזה בדיוק אותו דבר: דרך אחרת ושקולה לנסח את הטענה ש-\(xR_{L}y\) היא לומר ש-\(x^{-1}L=y^{-1}L\) – כלומר, שאוסף כל המילים \(z\) כך ש-\(xz\in L\) שווה לאוסף כל המילים כך ש-\(yz\in L\). אז עד כה לא עשיתי כלום חוץ מאשר הצבעה על העובדה (הנחמדה) שאפשר לנסח את המשפט בעזרת מושג החלוקה, במקום להזדקק למחלקות שקילות.

עכשיו בואו נכניס אוטומטים לתמונה. ניקח אוטומט סופי דטרמיניסטי כלשהו \(A=\left(Q,\Sigma,q_{0},\delta,F\right)\). עכשיו, לכל מצב \(q\in Q\) בואו נסמן ב-\(L_{q}\) את שפת כל המילים שאם אנחנו נמצאים ב-\(q\) וקוראים אותן, נגיע למצב מקבל: \(L_{q}\triangleq\left\{ w\in\Sigma^{*}\ |\ \hat{\delta}\left(q,w\right)\in F\right\} \). בבירור \(L\left(A\right)=L_{q_{0}}\) (אם זה לא ברור נסו להסביר לעצמכם את ההגדרה). עכשיו, לפני שנמשיך, אני רוצה להציג סימון שיחסוך לי את הצורך לכתוב \(\hat{\delta}\) עם סוגריים כל הזמן: במקום לכתוב \(\hat{\delta}\left(q,w\right)\) אני אכתוב \(q\cdot w\). פורמלית, אפשר לחשוב על זה כאילו \(w\) פועלת על \(q\), למי שמכיר את המושג הזה (כאן זו פעולה של המונואיד \(\Sigma^{*}\) על הקבוצה \(Q\), למי שמכיר את ההגדרות). התכונה שמעניינת אותנו כאן היא ש-\(q\cdot\left(uv\right)=\left(q\cdot u\right)\cdot v\) (מה שהוכחתי בעבר בתור \(\hat{\delta}\left(q_{0},uv\right)=\hat{\delta}\left(\hat{\delta}\left(q_{0},u\right),v\right)\)) ובגללה בחרתי את הסימון בצורה שבה בחרתי (נראה לי בהתחלה יותר טבעי לסמן \(w\cdot q\), אבל אני רוצה להימנע מזוועות כמו \(\left(uv\right)\cdot q=v\cdot\left(u\cdot q\right)\)). בסימון הזה, \(L_{q}\triangleq\left\{ w\in\Sigma^{*}\ |\ q\cdot w\in F\right\} \)

בואו נניח שכל המצבים ב-\(A\) ישיגים (לאוטומט כזה אקרא נגיש), כי קל להעיף מאוטומט מצבים לא ישיגים ומקבלים אוטומט שקול. זה אומר שלכל \(q\) קיימת מילה \(u\) כך ש-\(q=q_{0}\cdot u\). אני טוען ש-\(L_{q}=u^{-1}L\), ודי קל לראות את זה: \(w\in u^{-1}L\) אם ורק אם \(uw\in L\), אם ורק אם \(q_{0}\cdot uw\in F\), אם ורק אם \(\left(q_{0}\cdot u\right)\cdot w=q\cdot w\in F\), אם ורק אם \(w\in L_{q}\). באופן דומה, אם \(q=q_{0}\cdot v\) עבור \(v\ne u\) אז נקבל ש-\(L_{q}=v^{-1}L\) ולכן בפרט \(u^{-1}L=v^{-1}L\). המסקנה היא שהפונקציה \(f\left(q\right)=L_{q}\) היא פונקציה מ-\(Q\) על הקבוצה \(\left\{ u^{-1}L\ |\ u\in\Sigma^{*}\right\} \), כלומר הגודל של \(Q\) הוא לפחות כגודל הקבוצה הזו, ומכאן שמספר המצבים באוטומט שבונים בהוכחת מייהיל-נרוד הוא אכן מינימלי (כי מספר מצביו שווה לגודל הקבוצה \(\left\{ u^{-1}L\ |\ u\in\Sigma^{*}\right\} \)).

עכשיו, נניח שיש לנו שני מצבים \(q,p\) כך ש-\(L_{q}=L_{p}\). מה זה אומר? זה אומר ששני חישובים, שאחד מהם הגיע אל \(q\) והשני הגיע אל \(p\), יהיו משם והלאה שקולים במובן מסויים; אם נמשיך את שני החישובים על אותה מילה, או ששניהם יסתיימו בקבלה או ששניהם יסתיימו בדחיה (אבל זה ממש לא אומר שהחישובים יגיעו לאותם מצבים – ייתכן שלא יהיו להם מצבים משותפים בכלל). אינטואיטיבית זה אומר שאין לנו צורך בשני מצבים שונים עבור \(q,p\); אם החישוב מכאן והלאה הוא אותו הדבר, למה לא לאחד את שניהם למצב אחד?

בואו נחדד את מה שאני עושה. אגדיר יחס שקילות \(\equiv\) על \(Q\) באופן הבא: \(q\equiv p\) אם ורק אם \(L_{q}=L_{p}\). די קל לראות שזה יחס שקילות (כל יחס על קבוצה \(A\) שמוגדר באמצעות פונקציה \(f:A\to B\) כלשהי כך ש-\(a\equiv a^{\prime}\) אם ורק אם \(f\left(a\right)=f\left(a^{\prime}\right)\) הוא יחס שקילות). כעת אני טוען שקבוצת המנה \(Q/\equiv\) איזומורפית לקבוצת המנה \(\Sigma^{*}/R_{L}\), כאשר האיזומורפיזם נתון על ידי \(\left[w\right]_{R_{L}}\mapsto\left[q_{0}\cdot w\right]_{\equiv}\). להוכיח את זה – זה קצת סיפור. צריך להוכיח שהאיזומורפיזם הזה הוא באמת פונקציה; ושהיא חח"ע ועל.

כדי להוכיח שזו פונקציה צריך להוכיח שאין בהגדרה שלה תלות בנציג, כלומר שאם \(uR_{L}v\) אז \(q_{0}\cdot u\equiv q_{0}\cdot v\), כלומר ש-\(L_{q_{0}\cdot u}=L_{q_{0}\cdot v}\). נניח בשלילה שקיים \(z\) כך ש-\(z\in L_{q_{0}\cdot u}\) אבל \(z\notin L_{q_{0}\cdot v}\), אז \(\left(q_{0}\cdot u\right)\cdot z\in F\), כלומר \(uz\in L\), אבל \(vz\notin L\), בסתירה לכך ש-\(uR_{L}v\).

כדי להוכיח שהפונקציה היא חח"ע צריך להוכיח את הכיוון ההפוך – שאם \(L_{q_{0}\cdot u}=L_{q_{0}\cdot v}\) אז \(uR_{L}v\) – זה פשוט היפוך של הטיעון שנתתי קודם.

כדי להראות שהפונקציה היא על, ניקח מחלקת שקילות \(\left[q\right]_{\equiv}\) כלשהי. מכיוון שהנחתי שכל מצבי האוטומט ישיגים (בדיוק בשביל השלב הזה) הרי שקיים \(w\) כך ש-\(q=q_{0}\cdot w\), ולכן \(\left[w\right]_{R_{L}}\) הוא מקור של \(\left[q\right]_{\equiv}\), וסיימנו.

המסקנה היא שכדי לחשב את האוטומט המינימלי, מספיק לנו למצוא את מחלקות השקילות של \(\equiv\). אחרי שעשינו זאת, עדיין צריך להסביר מה יהיה המצב ההתחלתי שלנו, מי יהיו המצבים המקבלים ומה תהיה פונקציית המעברים. נלך על פי האיזומורפיזם שהצעתי: המצב ההתחלתי יהיה התמונה של \(\left[\varepsilon\right]_{R_{L}}\), כלומר \(\left[q_{0}\right]_{\equiv}\); התמונה של כל מצב מקבל \(\left[w\right]_{R_{L}}\) (כאשר \(w\in L\)) תהיה \(\left[q_{0}\cdot w\right]_{\equiv}\), ואנחנו יודעים ש-\(q_{0}\cdot w\in F\), כלומר המצבים המקבלים באוטומט שלנו יהיו מחלקות השקילות של מצבים מקבלים ב-\(Q\); ופונקציית המעברים תוגדר בתור \(\delta\left(\left[q\right]_{\equiv},\sigma\right)=\left[q\cdot\sigma\right]_{\equiv}\). זה נותן לנו את האוטומט האופטימלי של מייהיל-נרוד. כל מה שנשאר להסביר הוא איך מוצאים את מחלקות השקילות של \(\equiv\).

הדרך שבה אעשה זאת היא איטרטיבית – אני אתחיל מיחס שקילות שגוי, שהוא גס מדי – כלומר, כל מי שאמור להיות שקול אכן שקול, אבל יש גם איברים לא שקולים ב-\(\equiv\) שיהיו שקולים ביחס שלי. לאט לאט אני אלך ואעדן את היחס – כלומר, אם שני איברים לא היו שקולים, הם ימשיכו להיות כאלו, אבל בכל איטרציה אני אקח כמה איברים שהיו שקולים קודם ואפריד אותם זה מזה. נמשיך לבצע את זה עד שנגיע לאיטרציה שבה היחס לא השתנה, ואני אטען שאז הגעתי אל \(\equiv\). פורמלית, אבנה סדרה של יחסי שקילות \(\mathcal{Q}_{0},\mathcal{Q}_{1},\dots\) עד שאגיע למצב שבו \(\mathcal{Q}_{k}=\mathcal{Q}_{k+1}\), והטענה תהיה שאז \(\mathcal{Q}_{k}\) הוא בדיוק \(\equiv\), כלומר ש-\(q\mathcal{Q}_{k}p\) אם ורק אם \(L_{q}=L_{p}\).

הנה הצעה לגבי האופן שבו כדאי לאתחל:\(\mathcal{Q}_{0}=\left\{ Q\right\} \) (אני מתאר כאן את יחס השקילות בתור חלוקה של \(Q\)), כלומר כל האיברים יהיו שקולים זה לזה. מכאן והלאה אנחנו "מתקנים" כשאנחנו מוצאים דוגמאות נגדיות לכך שזוגות של מצבים הם שקולים. הדוגמה הנגדית הראשונה היא \(\varepsilon\). מן הסתם היא מפרידה בדיוק את אותם מצבים שהם מקבלים מאלו שאינם מקבלים (למה?) ולכן יותר הגיוני לאתחל \(\mathcal{Q}_{0}=\left\{ Q\backslash F,F\right\} \) במקום לאתחל עם קבוצה אחת. מכאן והלאה נפעל איטרטיבית: בהינתן \(\mathcal{Q}_{k}\) נחשב מתוכה את \(\mathcal{Q}_{k+1}\) שהיא קצת יותר מדוייקת מ-\(\mathcal{Q}_{k}\), עד שנגיע למצב שבו אין יותר שינויים.

עכשיו, בהינתן \(p,q\) שהם שקולים ב-\(\mathcal{Q}_{k}\), אני אבדוק אם קיים \(a\) כך ש-\(q\cdot a,p\cdot a\) לא שקולים ש-\(\mathcal{Q}_{k}\). אם קיים כזה, אני מפריד את \(p,q\) ב-\(\mathcal{Q}_{k+1}\). אם \(p,q\) היו שקולים ב-\(\mathcal{Q}_{k}\) ולא מצאתי \(a\) מפריד שכזה, אני ממשך לסמן אותם כשקולים. הניסוח המילולי הזה מסתיר מאחוריו סכנה כלשהי לסיטואציה לא מוגדרת היטב – שיהיו לי שלושה מצבים \(p,q,r\) כך ש-\(p,q\) אמורים להיות לא שקולים אבל \(p,r\) אמורים להיות שקולים וגם \(q,r\) אמורים להיות שקולים. אם זה מטריד אתכם קחו רגע כדי להוכיח שזה לא יכול לקרות, ולכן אנחנו מקבלים שגם \(\mathcal{Q}_{k+1}\) הוא יחס שקילות, וכזה שמעדן את \(\mathcal{Q}_{k}\). מכיוון שאלו יחס שקילות על קבוצה סופית וכל אחד מהם מעדן את קודמו, מתישהו בהכרח נגיע לנקודת שבת – \(\mathcal{Q}_{k}=\mathcal{Q}_{k+1}\), מה שמוכיח שהאלגוריתם תמיד מסתיים. נותר להוכיח שהתוצאה היא אכן יחס השקילות שאנחנו רוצים.

כיוון אחד קל. נוכיח באינדוקציה על \(t\) שאם עבור זוג מצבים כלשהו \(p,q\) מתקיים ש-\(L_{p}=L_{q}\) אז \(q\mathcal{Q}_{t}p\). עבור \(t=0\) זה בבירור עובד, כי אם \(q\) לא שקול ל-\(p\) ב-\(\mathcal{Q}_{0}\) אז בלי הגבלת הכלליות \(p\in F\) ו-\(q\notin F\), מה שאומר ש-\(\varepsilon\in L_{p}\) אבל \(\varepsilon\notin L_{q}\). כעת, נניח שזה עובד עבור \(t\) ונוכיח ל-\(t+1\): אם \(L_{p}=L_{q}\) אבל \(p,q\) לא שקולים ב-\(\mathcal{Q}_{t+1}\). הנחת האינדוקציה שלנו אומרת ש-\(p,q\) כן היו שקולים ב-\(\mathcal{Q}_{t}\), ולכן על פי אופן פעולת האלגוריתם, זה אומר שקיים \(a\) כך ש-\(p\cdot a\) ו-\(q\cdot a\) לא שקולים ב-\(\mathcal{Q}_{t}\); מכאן שבהכרח \(L_{q\cdot a}\ne L_{p\cdot a}\) (למה?). בלי הגבלת הכלליות נובע מכך שקיים \(z\) כך ש-\(z\in L_{q\cdot a}\) אבל \(z\notin L_{p\cdot a}\) – מכאן נובע ש-\(az\in L_{q}\) אבל \(az\notin L_{p}\), בסתירה לכך ש-\(L_{q}=L_{p}\), מה שמסיים את הכיוון הזה.

בכיוון השני, אני רוצה להוכיח שאם \(p\mathcal{Q}_{k}q\) אז \(L_{p}=L_{q}\). נניח שזה לא המצב, אז תהיה לי לפחות דוגמה נגדית אחת. דוגמה נגדית מורכבת משלושה דברים: זוג מצבים \(p,q\) כך ש-\(p\mathcal{Q}_{k}q\), וכמו כן מילה \(z\) כך ש-\(z\in L_{p}\) אבל \(z\notin L_{q}\). כדי שההוכחה תעבוד, אני לא סתם אסתכל על דוגמה נגדית אקראית, אלא אקח כזו שבה \(z\) הוא הקצר ביותר האפשרי – כלומר, שכל מילה קצרה יותר מ-\(z\) לא מופיעה באף דוגמה נגדית.

עכשיו אפשר לפרק את \(z\) באופן הבא: \(z=az^{\prime}\) (אני מניח ש-\(z\) הוא מאורך לפחות 1 – למה זה אפשרי?). נקבל ש-\(z^{\prime}\in L_{p\cdot a}\) אבל \(z^{\prime}\notin L_{q\cdot a}\). אני חותר לכך שזו סתירה למינימליות של האורך של \(z\); לצורך כך צריך להשתכנע שהשלשה \(p\cdot a,q\cdot a\)ו-\(z^{\prime}\) גם היא דוגמה נגדית, כלומר ש-\(p\cdot a\mathcal{Q}_{k}q\cdot a\). הסיבה שזה נכון היא שאם לא היה מתקיים ש-\(p\cdot a\mathcal{Q}_{k}q\cdot a\) אז האלגוריתם שלנו היה מפריד את \(p,q\) ב-\(\mathcal{Q}_{k+1}\) ובוודאי שלא היינו מקבלים \(\mathcal{Q}_{k}=\mathcal{Q}_{k+1}\). זה מסיים את הוכחת הנכונות של האלגוריתם. עכשיו לכו לתכנת אותו!

חזרתם? יופי. בואו נעבור לחלק המוזר של הפוסט – עוד אלגוריתם מינימזציה שלא ברור בכלל מאיפה הוא הגיע ולמה הוא עובד.

כדי שנוכל לתאר את האלגוריתם בצורה פשוטה, כמה סימונים חדשים. נסמן ב-\(A\) אוטומט סופי כלשהו (לאו דווקא דטרמיניסטי, אבל בלי מסעי-\(\varepsilon\)). נסמן ב-\(A_{\mbox{det}}\) את הדטרמיניזציה של \(A\) – האוטומט שמתקבל מאוטומט החזקה של \(A\) על ידי הסרת מצבים לא ישיגים (אסביר את זה בפירוט בהמשך). נסמן ב-\(A^{R}\) את ההיפוך של \(A\) – אוטומט שמתקבל מ-\(A\) על ידי היפוך כל כיווני הקשתות והחלפת תפקידי המצבים ההתחלתיים והמקבלים (כזכור, \(L\left(A^{R}\right)=\left(L\left(A\right)\right)^{R}\) כאשר \(L^{R}\) היא היפוך כל המילים ב-\(L\)), ונסמן ב-\(A_{\mbox{min}}\) את האוטומט הדטרמיניסטי המינימלי ששקול ל-\(A\). אז אני טוען שמתקיים:

\(A_{\mbox{min}}=\left(\left(\left(A^{R}\right)_{\mbox{det}}\right)^{R}\right)_{\mbox{det}}\)

במילים: כדי לקבל את האוטומט הדטרמיניסטי המינימלי ששקול ל-\(A\), פעלו כך: קודם כל הפכו את \(A\). בצעו דטרמיניזציה לתוצאה. הפכו את התוצאה ובצעו למה שקיבלתם דטרמיניזציה. הופס! קיבלתם את האוטומט המינימלי.

לא יודע מה אתכם, אני עדיין מרגיש שמשהו מאוד מוזר הולך פה גם בזמן שבו אני כותב את השורות הללו. בתקווה עד שאסיים לכתוב את הפוסט תהיה לכולנו אינטואיציה יותר טובה למה זה עובד, ולא סתם הוכחה פורמלית.

סיבה עיקרית לקושי שאני מרגיש ללא ספק נובעת מכך שאני רגיל לחשוב על דטרמיניזציה של אוטומט בתור משהו ש"מנפח" אותו, ולכן לא ייתכן ששתי דטרמיניזציות יקטינו את מספר המצבים ויתנו לנו אוטומט מינימלי. לכן חשוב להסביר מה זו בעצם הדטרמיניזציה הזו. בפוסט על אוטומט אי דטרמיניסטי הצגתי את ההוכחה שקיים לו אוטומט דטרמיניסטי שקול – מה שנקרא אוטומט חזקה. כל מצב של אוטומט החזקה הוא קבוצה של מצבים של האוטומט המקורי – אחרי קריאת \(w\) אנחנו מגיעים לקבוצת כל המצבים שיש ריצה על \(w\) באוטומט המקורי שמביאה אותו אליהם.

באופן הזה, הרבה פעמים אנחנו מקבלים מצבים מיותרים. דוגמה טריוויאלית היא מה שנקבל אם נבצע את הבניה הזו על אוטומט שהוא כבר דטרמיניסטי, המצבים היחידים שנזדקק להם בפועל הם קבוצות שהן סינגלטונים (למה?). כל שאר המצבים פשוט יהיו לא ישיגים מהמצב ההתחלתי. אז כשרוצים לבצע דטרמיניזציה בפועל של אוטומט, לא מתחילים מבניה של כל המצבים האפשריים (יש המון כאלו – 2 בחזקת מספר המצבים של האוטומט המקורי). פשוט מבצעים DFS מהמצב ההתחלתי, שהוא \(\left\{ q_{0}\right\} \). לכל אות מחשבים לאיזה מצב של אוטומט החזקה עוברים ממנו, ולכל מצב כזה מבצעים את אותו חישוב, וכדומה. התוצאה עשויה להיות אוטומט החזקה המלא, במקרה שבו כל המצבים שלו הם ישיגים; אבל לרוב היא תהיה הרבה יותר קטנה ולכן העניין הזה פרקטי בפועל. כאמור, אם \(A\) הוא אוטומט, אז אסמן ב-\(A_{\mbox{det}}\) את הדטרמיניזציה הזו שלו.

כדי לקבל אינטואיציה כלשהי לכך שזה עובד, בואו נראה דוגמת צעצוע. אני אקח אוטומט עבור שפת כל המילים מאורך אי-זוגי מעל \(\left\{ a,b\right\} \) ובכוונה האוטומט הזה יהיה לא מינימלי – במקום שני מצבים יהיו לו שלושה, כשבבירור אפשר לאחד את המצב הראשון והשלישי:

diagram005

הדבר הראשון שנעשה יהיה היפוך של האוטומט הזה. אני הופך את כיווני הקשתות, הופך כל מצב התחלתי למקבל, וכל מצב מקבל להתחלתי. כאן יש רק מצב מקבל אחד אז אני לא מקבל תופעה מוזרה של אוטומט עם כמה מצבים התחלתיים (כבר ראינו שאוטומט כזה הוא לגיטימי ושקול למודל הדטרמיניסטי):

diagram006

ועכשיו אני מבצע דטרמיניזציה:

diagram007הופס! קיבלנו רק שני מצבים במקום שלושה – איכשהו הדטרמיניזציה זיהתה ש-\(q_{0},q_{2}\) הם אותו הדבר מבחינתנו והם נדחסו למצב יחיד. למעשה, מה שקיבלנו הוא כבר אוטומט עבור השפה שלנו – לא צריך את ההיפוך והדטרמיניזציה הנוספים, והם גם לא משנים את האוטומט כלל (למה?).

כדי להבין למה כאן הספיק לנו רק "חצי" מהאלגוריתם, הנה המשפט הכללי שעליו אני מסתמך באלגוריתם. לפני כן, הגדרה אחרונה: נאמר שאוטומט \(A\) הוא קו-בלהבלה, כאשר במקום "בלהבלה" קחו את התכונה החביבה עליכם, אם \(A^{R}\) מקיים את בלהבלה. למשל, \(A\) הוא קו-דטרמיניסטי אם \(A^{R}\) הוא דטרמיניסטי; והוא קו-נגיש אם \(A^{R}\) נגיש, כלומר כל מצבי \(A^{R}\) ישיגים. הנה המשפט: אם \(A\) הוא קו-דטרמיניסטי וקו-נגיש, אז \(A_{\mbox{min}}=A_{\mbox{det}}\). מכאן יותר קל להבין מה קרה בנוסחה \(A_{\mbox{min}}=\left(\left(\left(A^{R}\right)_{\mbox{det}}\right)^{R}\right)_{\mbox{det}}\): החלק הפנימי, \(\left(\left(A^{R}\right)_{\mbox{det}}\right)^{R}\), הוא פשוט מה שצריך לעשות כדי לקבל מ-\(A\) שהתחלנו ממנו אוטומט שקול שהוא קו-דטרמיניסטי וקו-נגיש (שתי התכונות הללו מושגות בו זמנית על ידי ביצוע דטרמיניזציה). בדוגמת הצעצוע שנתתי, \(A\) שלי לא היה קו-דטרמיניסטי, אבל מה שכן היה נכון הוא ש-\(A^{R}\) קיבל את אותה שפה כמו \(A\) (כי מילה היא מאורך אי זוגי אם ורק אם ההיפוך שלה כזה), ואותו \(A^{R}\) דווקא כן מקיים את התכונה שהוא קו-דטרמיניסטי וקו-נגיש (כי \(A\) היה דטרמיניסטי ונגיש). לכן כשביצענו את הדטרמיניזציה של \(A^{R}\) קיבלנו אוטומט מינימלי עבור השפה של \(A^{R}\), ובמקרה שלנו זו הייתה השפה שאנחנו מחפשים.

אז הקסם הוא בכך שדטרמיניזציה של אוטומט עשויה, בתנאים נחמדים מסויימים, לבנות ממנו את האוטומט המינימלי. זה לא באמת מופרך, אם חושבים על זה לרגע. דטרמיניזציה בונה אוטומט חדש, שמצביו הם קבוצות של מצבים של האוטומט המקורי – זה בדיוק גם מה שעשינו באלגוריתם הקודם שהצגנו. אבל הסיטואציה בכל זאת שונה – הקבוצות שנקבל לא יהיו מחלקות השקילות של היחס \(\equiv\) (למשל, בדוגמה שלי, \(q_{0}\) מתקבץ יחד עם \(q_{2}\) למרות שאחד הוא מצב מקבל והשני איננו). יש בעיה מהותית לדבר בכלל על היחס \(\equiv\) כי הוא הוגדר עבור אוטומטים דטרמיניסטיים, אבל \(A\) שלנו עשוי להיות אי-דטרמיניסטי. לכן בואו נחזור לתיאור האוטומט המינימלי שנתתי בתחילת הפוסט – מצבי האוטומט הם השפות \(u^{-1}L\). כלומר, אני אראה התאמה חח"ע ועל בין מצבי \(A_{\mbox{det}}\) ובין השפות \(u^{-1}L\). האינטואיציה ברורה – לכל \(u\in\Sigma^{*}\), נעביר את המצב שאליו מגיעים על ידי קריאת \(u\) ב-\(A_{\mbox{det}}\) אל \(u^{-1}L\) (דהיינו, אם \(S=\hat{\delta}\left(q_{0},u\right)\), אז מבצעים \(S\mapsto u^{-1}L\)). כדי להיווכח בכך שההתאמה הזו היא בכלל פונקציה ושהיא חח"ע צריך להראות שלכל זוג מילים \(u,v\) מתקיים ש-\(\hat{\delta}\left(q_{0},u\right)=\hat{\delta}\left(q_{0},v\right)\) אם ורק אם \(u^{-1}L=v^{-1}L\) – אנחנו מקבלים את אותו הפלט. מרגע שהראיתי את זה, סיימתי, כי ההתאמה היא בבירור על (הרי התחלנו עם \(u\in\Sigma^{*}\) כלשהי, זה מבטיח שנוכל לכסות את כל ה-\(u^{-1}L\)-ים)

בכיוון אחד, אם \(\hat{\delta}\left(q_{0},u\right)=\hat{\delta}\left(q_{0},v\right)\) אז מן הסתם לכל הרחבה של החישוב באמצעות \(z\), אם יהיה חישוב מקבל באחד האוטומטים יהיה גם בשני. לכן \(uz\in L\iff vz\in L\) מה שמראה ש-\(u^{-1}L=v^{-1}L\). הכיוון המעניין הוא השני: אנו מניחים ש-\(u^{-1}L=v^{-1}L\) וצריכים להראות שהמצבים שאליהם \(A\) יכול להגיע על ידי קריאת \(u\) הם בדיוק המצבים שאליהם \(A\) יכול להגיע על ידי קריאת \(v\). כאן מן הסתם ייכנסו לפעולה התכונות שמאפיינות את \(A^{R}\).

בואו ניקח \(p\) כך שקיימת ריצה של \(A\) על \(u\) שמסתיימת ב-\(p\). האבחנה הראשונה שלנו היא שאפשר להמשיך את הריצה הזו ולהגיע למצב מקבל; זה נובע מכך ש-\(A^{R}\) הוא אוטומט ישיג, ולכן \(p\) ישיג ממצב התחלתי של \(A^{R}\) – כלומר, ב-\(A\) העסק מתהפך ואנחנו מקבלים שיש מצב מקבל של \(A\) שישיג מ-\(p\). כלומר, קיים \(z\) כך ש-\(uz\in L\), דהיינו \(z\in u^{-1}L=v^{-1}L\), ולכן גם \(vz\in L\). כלומר: קיימת ריצה של \(A\) על \(vz\) שמסתיימת במצב מקבל. עכשיו נכניס לתמונה את העובדה ש-\(A^{R}\) הוא דטרמיניסטי; בפרט זה אומר שקיים לו מצב התחלתי יחיד ולכן ל-\(A\) יש מצב מקבל יחיד, כלומר הריצה של \(A\) על \(vz\) מסתיימת באותו מצב כמו הריצה של \(A\) על \(uz\). בואו נסמן ב-\(p^{\prime}\) את המצב שאליו הריצה הזו מגיעה אחרי סיום קריאת \(v\).

מה למדנו? שב-\(A\) קיימים שני מצבים, \(p,p^{\prime}\), שעל ידי קריאת \(z\) ניתן לעבור מכל אחד מהם אל המצב המקבל היחיד של \(A\). זה אומר שב-\(A^{R}\), על ידי קריאת \(z^{R}\), אפשר להגיע גם ל-\(p\) וגם ל-\(p^{\prime}\). אבל הרי \(A^{R}\) הוא דטרמיניסטי, ולכן זה אפשרי רק אם \(p=p^{\prime}\). המסקנה: קיימת ריצה של \(A\) על \(v\) שמסתיימת ב-\(p\), ולכן \(\hat{\delta}\left(q_{0},u\right)\subseteq\hat{\delta}\left(q_{0},v\right)\). ההוכחה בכיוון השני זהה, וקיבלנו שהאיזומורפיזם שהגדרתי בין מצבי \(A_{\mbox{det}}\) ובין השפות \(u^{-1}L\) עובד. עדיין צריך להשתכנע ש-\(A_{\mbox{det}}\) זהה לאוטומט שבונים מתוך \(u^{-1}L\), אבל קל למדי לוודא את זה. סיימנו את הבניה הזו!

כמובן, נשאלת השאלה איזה מבין שני האלגוריתמים הוא עדיף. בשניהם זמן הריצה עשוי להיות אקספוננציאלי במספר המצבים (נסו למצוא דוגמאות נגדיות!) ולכן אין לי תשובה טובה – כנראה שכדאי לנסות להריץ אחד, ואם לא עובד מהר, לנסות את השני. יש גם שאלה של מה בעצם הקלט שלנו – אם נתון לנו אוטומט דטרמיניסטי, כנראה עדיף להפעיל את האלגוריתם הראשון; אם נתון אוטומט אי-דטרמיניסטי, אז כדי להפעיל את האלגוריתם הראשון ממילא יהיה צורך לבצע דטרמיניזציה, אז אפשר כבר לנסות ולהפעיל את האלגוריתם השני (ולבדוק אם יש לנו מזל והוא קו-נגיש וקו-דטרמיניסטי מראש). אבל אם אם זמן הריצה של האלגוריתם השני היה נחות מזה של הראשון זה לא היה כל כך אכפת לי – פשוט כי זה כל כך מגניב.

בעיות הכרעה עבור שפות פורמליות

כל מה שעשיתי עד כה בפוסטים על שפות פורמליות היה, במובן מסויים, "בתוך" המודלים שהצגתי – זה של אוטומט סופי עבור שפות רגולריות, וזה של דקדוקים חסרי הקשר ואוטומטי מחסנית עבור שפות חסרות הקשר. כל הדברים שעשיתי נעשו בעזרת המודלים הללו. אבל זה לא מה שקורה בעולם האמיתי – בעולם האמיתי, כשאנחנו באים להתעסק עם שפה רגולרית, אנחנו עושים את זה באמצעות שפת התכנות החביבה עלינו, מה שאומר שיש לנו יכולת להשתמש באלגוריתמים כלליים (בלשון פורמלית תיאורטית – יש לנו מכונת טיורינג). האוטומט הסופי הוא עבורנו דרך לייצג את השפה, ואנחנו מסוגלים להריץ אלגוריתמים ומניפולציות עליו כדי להפיק מידע על השפה. בדברים הללו אנחנו הולכים להתעסק בפוסט הזה.

נניח ש-\(L\) היא שפה פורמלית כלשהי (רגולרית או חסרת הקשר), אז הנה דברים שמעניין אותנו לדעת. האם \(L\) ריקה? האם \(L\) אינסופית? האם מילה \(w\) ספציפית שייכת ל-\(L\)? ונניח שנתונה שפה גם \(L^{\prime}\), האם \(L=L^{\prime}\)?

לפני שניגשים לפתור את הבעיות הללו צריך להבין איך \(L\) נתונה לנו בכלל. קלטים, במחשב, הם בסך הכל סדרה סופית של ביטים, שאנחנו מפענחים בצורה מסויימת. אנחנו צריכים ייצוג שהמחשב יודע לעבוד איתו, ולכן ייצוג של שפה באמצעות תיאור מילולי לא פורמלי ("\(L\) היא שפת כל המילים מאורך זוגי מעל \(\left\{ a,b\right\} \)") יהיה משהו שלמחשב יהיה קשה מאוד לעבוד איתו. אז בדרך כלל אנחנו מניחים שאם \(L\) רגולרית היא נתונה לנו בעזרת אוטומט סופי \(A\) (שמיוצג באופן דומה לזה שמייצגים בו גרף במחשב), ואם היא חסרת הקשר היא נתונה בעזרת דקדוק חסר הקשר \(G\). אפשר כמובן גם להציע דרכי תיאור אחרות, למשל ביטוי רגולרי; אבל אנחנו יודעים שאפשר להמיר כל ביטוי רגולרי לאוטומט מתאים, אז על פניו אנחנו לא מגבילים את הכלליות (כמובן שיש שאלה של סיבוכיות ההמרה של הביטוי הרגולרי לאוטומט וכדומה אבל לא אכנס לזה הפעם).

אני אנסה עכשיו לתת סיפור קונקרטי על משהו ספציפי אחד שיתן לנו תחושה כללית של למה מעניין לדבר על בעיות הכרעה, ומה הסכנות שצריך להיות מודעים להן. אני רוצה לדבר ספציפית על בעיית הריקנות של שפות רגולריות, בהקשר של אימות חומרה. אחת מהגישות שבהן נוקטים באימות חומרה היא מה שנקרא "בדיקות מודל" (Model Checking). בשיטה הזו, לוקחים רכיב חומרה כלשהו וממירים אותו לאוטומט סופי דטרמיניסטי; ה"מצבים" של האוטומט הם כל ההשמות האפשריות לרגיסטרים של רכיב החומרה (רגיסטר כאן הוא יחידת זכרון כלשהי שנמצאת בתוך הרכיב). ה"אותיות" שאותן קוראים הן ההשמות האפשריות לקלטים לרכיב החומרה הזה. אני לא אכנס להסברים יותר מפורטים כי זה ראוי לפוסט משל עצמו; השורה התחתונה היא שבסופו של דבר יש לנו ייצוג כלשהו של אוטומט שהמצבים שלו מתאימים למצבים שבהם הרכיב יכול להיות. עכשיו, אנחנו לרוב רוצים לבדוק תכונה כלשהי של הרכיב – למשל, "אם התקבל סיגנל של "בקשה", אז אחרי שלושה מחזורי שעון לכל היותר ייפלט סיגנל של "אישור". אחת הדרכים לעשות זאת היא כך: כותבים את הדרישה באמצעות לוגיקה פורמלית (נהוג להשתמש בסוג מסויים של לוגיקה טמפורלית לשם כך; זה נושא מעניין מאוד, כאמור). את הפסוק הלוגי הזה ממירים לאוטומט קטן שמצליח לתאר אותו בצורה כלשהי, ובונים מכפלה של האוטומט הקטן הזה יחד עם האוטומט שמתאר את כל המערכת. בסופו של דבר מתקבל אוטומט עם מצב מקבל יחיד, שכניסה אליו פירושו שהתכונה מופרת. עכשיו אנחנו לוקחים את האוטומט הזה ומריצים עליו בדיקת ריקנות. אם השפה של האוטומט ריקה, זה אומר שלא משנה מה הקלטים שהמעגל מקבל, התכונה שאנחנו בודקים לא מופרת בו; ואם השפה לא ריקה, אז כל מילה בה מהווה דוגמה נגדית לנכונות של התכונה, שעוזרת למתכנני המעגל להבין מה השתבש ומה לתקן.

זו דוגמה יפה מאוד, לטעמי, אבל היא גם שקר גדול, כי אלגוריתם הריקנות שאראה בהמשך לא יכול לטפל בה ביעילות. העניין הוא שהאוטומטים שנבנים באימות חומרה הם גדולים. ממש ממש גדולים. במובן זה שאוטומט עם \(2^{100}\) מצבים הוא משהו לא חריג ואפילו לא גדול במיוחד. מן הסתם הייצוג שלנו של האוטומטים הללו הוא קומפקטי בצורה כלשהי, אבל אלגוריתמים שזמן הריצה שלהם הוא, למשל, לינארי במספר מצבי האוטומט יהיו חסרי ערך עבור אוטומט כזה. לכן משתמשים בשיטות אחרות, שהן יותר היוריסטיות באופיין ולא תמיד עובדות, אבל בפועל מספקות תוצאות טובות. אני לא הולך לדבר על זה בכלל בפוסט הזה.

אוקיי, בואו נעבור עכשיו לפתרון בעיות.

אם \(A\) הוא אוטומט סופי דטרמיניסטי ונתונה לנו מילה כלשהי \(w\), אז אין דבר קל יותר מלבדוק אם \(w\in L\left(A\right)\): פשוט מבצעים סימולציה של ריצת \(A\) על \(w\) ובודקים אם הגענו למצב מקבל. אם \(A\) אינו דטרמיניסטי אפשר לבצע לו דטרמיניזציה (להמיר אותו לאוטומט דטרמיניסטי; אדבר בפוסט אחר על איך עושים את זה יעיל יחסית), אבל גם אפשר להריץ אותו כמו שהוא על המילה, כשבמקום לזכור את המצב שבו אנחנו נמצאים כרגע, אנחנו זוכרים את קבוצת המצבים שבהם אנחנו נמצאים כרגע בכל הריצות האפשריות של האוטומט. כבר דיברתי על זה בשעתו.

עבור דקדוק חסר הקשר \(G\) המצב קשה הרבה יותר. דקדוק שכזה הוא אי-דטרמיניסטי בצורה הרבה פחות נוחה – אם ננסה לבצע את כל הריצות האפשריות שלו ביחד נצטרך לזכור כמות הולכת וגדלה של דברים ונסתבך חיש קל. בעיה דומה תהיה גם אם ננסה לבצע את כל הריצות של אוטומט מחסנית – כמות התכנים האפשריים של המחסנית תלך ותגדל באופן לא בהכרח חסום. אז צריך לעשות משהו אחר. המשהו האחר הכללי הסטנדרטי נקרא אלגוריתם CYK ואתאר אותו בהמשך הפוסט, אחרי שנסיים עם הדברים הפשוטים.

נעבור אל בעיית הריקנות. כשחושבים על אוטומט בתור גרף, זו בעיה פשוטה למדי, כל עוד מספר מצבי האוטומט הוא סביר – אנחנו פשוט מבצעים אלגוריתם חיפוש רגיל בגרף (DFS או BFS) החל מהמצב ההתחלתי של האוטומט ובודקים אם אפשר להגיע אל מצב מקבל כלשהו. כאמור, אם יש יותר מדי מצבים באוטומט מכדי שאפשר יהיה לנקוט בגישה הזו אנחנו נזקקים לשיטות היוריסטיות מחוכמות יותר שלא אדבר עליהן פה.

ומה קורה בדקדוקים? המצב לא שונה בהרבה. האתגר פה הוא למצוא משתנים טרמינליים – משתנים שגוזרים מילה טרמינלית. למשתנים כאלו יש הגדרה רקורסיבית פשוטה: \(A\) הוא טרמינלי אם קיים כלל גזירה \(A\to\alpha\) כך ש-\(\alpha\) מורכבת כולה מטרמינלים וממשתנים טרמינליים. הגדרה כזו נותנת לנו מייד אלגוריתם איטרטיבי למציאת כל המשתנים הטרמינליים: מתחזקים קבוצה \(X\) של משתנים טרמינליים, שבהתחלה היא ריקה; בכל איטרציה עוברים על כל הגזירות \(A\to\alpha\) בדקדוק ובודקים אם \(\alpha\in\left(X\cup T\right)^{*}\). אם כן, מוסיפים את \(A\) ל-\(X\). ממשיכים כך עד שמגיעים לאיטרציה שבה לא התווסף כלום ל-\(X\), ואז מסיימים. עכשיו, כדי לבדוק אם שפת הדקדוק ריקה, פשוט בודקים אם \(S\) טרמינלי או לא.

נעבור לבעיית האינסופיות. מתי שפה של אוטומט היא אינסופית? ובכן, ברור שאם יש בשפה מילה שאפשר "לנפח" על פי למת הניפוח לשפות רגולריות אז השפה אינסופית כי היא כוללת את אינסוף הניפוחים של המילה. מתי מילה כזו קיימת באוטומט? כאשר יש ריצה על מילה ששייכת לשפה שמגיעה לאותו מצב פעמיים. אם ננסה לזקק מזה את המהות, נגיע לאבחנה הבאה: אם קיים בגרף של האוטומט מעגל שהוא מצד אחד ישיג מתוך המצב ההתחלתי, ומצב שני יש מצב מקבל שישיג ממנו – אז שפת האוטומט אינסופית. קל לראות שגם הכיוון ההפוך נכון, כי אם שפת האוטומט אינסופית יש בה מילים גדולות כרצוננו, ולכן תהיה מילה שאפשר להפעיל עליה את למת הניפוח.

עבור דקדוקים חסרי הקשר הסיטואציה דומה, אבל צריך להיות קצת יותר זהירים. אנחנו עדיין רוצים, באופן בסיסי, לחפש מעגל בגרף. נבנה גרף שצמתיו הם המשתנים של הדקדוק ויש קשת מ-\(A\) אל \(B\) אם קיימת בדקדוק גזירה \(A\to\alpha B\beta\). מעגל בגרף הזה פירושו שיש לנו משתנה שגוזר את עצמו: \(A\Rightarrow^{*}\gamma A\delta\). אבל גם אם מצאנו סיטואציה כזו, זה עדיין לא מבטיח לנו אינסוף מילים בשפה – אנחנו צריכים לדעת ש-\(A\) מסוגל לגזור מילה טרמינלית (אחרת חישוב ש-\(A\) משתתף בו לא הולך לייצר מילים בכלל), וש-\(\left|\gamma\delta\right|\ge1\) (אחרת \(A\) עשוי לגזור את עצמו שוב ושוב, אבל זה החישוב איתו ייצר רק מילה אחת). כדי להבטיח את אלו, אנחנו מראש מבטיחים שהדקדוק שלנו הוא "נקי" – מעיפים ממנו משתנים טרמינליים, וגם מסלקים ממנו כללי יחידה כמו \(A\to B\) וכללים מהצורה \(A\to\varepsilon\), כך שאנו מבטיחים שכל גזירה \(A\to\alpha B\beta\) היא כזו שגם מייצרת מסביב ל-\(B\) משהו שהולך להפוך לטרמינלים בסופו של דבר. זו המחשה טובה לכך שנוח הרבה יותר להפעיל אלגוריתמים אם אפשר להניח שהדקדוק שפועלים עליו עבר פישוט מתאים.

בואו נעבור עכשיו למי שהיא אולי הבעיה המרתקת ביותר מבין כל בעיות ההכרעה שאדבר עליהן בפוסט הזה – בעיית השקילות. נתונים שני אוטומטים \(A_{1},A_{2}\) ואנחנו רוצים לדעת האם \(L\left(A_{1}\right)=L\left(A_{2}\right)\). זה לחלוטין לא טריוויאלי. חשבו על סיטואציה שבה אנחנו רוצים לבנות רכיב חומרה; מצד אחד, יש לנו מודל \(A_{1}\) מאוד פשוט של הרכיב שמתאר את הפונקציה שהוא צריך לחשב, אבל ייתכן מאוד שמכל בחינה מעשית, המימוש של הרכיב הוא מאוד לא יעיל (מבחינת מספר שערים; מיקום שערים; צריכת חשמל; זמן ביצוע החישוב ועוד אינסוף שיקולים מורכבים שמהנדסי חומרה חייבים להתחשב בהם). מצד שני, יש לנו מימוש בפועל \(A_{2}\) שמהנדס חומרה עבד עליו מאוד קשה, אבל לכו תדעו עד אם הוא לא פספס משהו ואם אין באגים וכדומה. ועכשיו תחשבו שבלחיצת כפתור היה אפשר לבדוק אם \(A_{1}\) שקול ל-\(A_{2}\). זה סוג הקושי שמדובר עליו כאן. עבור תוכניות מחשב כלליות זה פשוט לא עובד – אין אלגוריתם שמסוגל לבדוק אם שתי תוכניות מחשב הן שקולות. אבל עבור אוטומטים זה כן עובד, ואפילו עובד בצורה פשוטה להחריד, מבחינה רעיונית (מבחינת החישוב – שוב, זה ייקח יותר מדי זמן בפועל בסיטואציות אמיתיות של בדיקת רכיבי חומרה, אבל זה לא אומר שזה לא מועיל בהקשרים אחרים).

איך אנחנו עושים את הקסם הזה? פשוט מאוד – רדוקציה לבעיה של בדיקת ריקנות. אם \(L_{1}=L\left(A_{1}\right)\) ו-\(L_{2}=L\left(A_{2}\right)\), נבנה אוטומט עבור ההפרש הסימטרי של \(L_{1}\) ו-\(L_{2}\) – אוסף המילים ששייכות לשפה אחת אבל לא לשניה. מן הסתם ההפרש הסימטרי ריק אם ורק אם השפות שוות. פורמלית, ההפרש הסימטרי הוא \(\left(L_{1}\backslash L_{2}\right)\cup\left(L_{2}\backslash L_{1}\right)=\left(L_{1}\cap\overline{L_{2}}\right)\cup\left(L_{2}\cap\overline{L_{1}}\right)\), ואלו תכונות סגור; בפועל פשוט בונים אוטומט מכפלה עם מצבים מקבלים \(\left(F_{1}\times\left(Q_{2}\backslash F_{2}\right)\right)\cup\left(\left(Q_{1}\backslash F_{1}\right)\times F_{2}\right)\).

האם אפשר לעשות משהו דומה עבור שפות חסרות הקשר? ובכן, התשובה היא חד משמעית לא. לא קיים אלגוריתם שבודק שקילות של שני דקדוקים חסרי הקשר. אבל למה? איך מוכיחים את זה? כאן אני חייב לגלוש קצת לתורה של בעיות לא כריעות. ספציפית, אני אציג בעיה לא כריעה אחת שבעזרתה אוכיח שהבעיות הקשורות לדקדוקים אינן כריעות. הבעיה הזו נקראת "בעיית ההתאמה של פוסט" ובקיצור PCP ויש לי עליה פוסט ייעודי שגם מוכיח שהיא לא כריעה. בפוסט הזה לא רק שלא אוכיח שהבעיה הזו לא כריעה, אלא גם לא אכנס לתיאור עמוק שלה, אלא ההפך – אציג ניסוח שקול שלה שהוא מאוד פשוט אבל עושה שימוש בטרמינולוגיה שאנחנו כבר מכירים ולא הנחתי אותה בפוסט ההוא. בניסוח שלי, בעיית ההתאמה של פוסט היא הדבר הבא: נתון לנו אלפבתים סופיים \(\Sigma\) ו-\(\Delta\) ונתונים שני הומומורפיזמים \(h:\Sigma\to\Delta^{*}\) ו-\(g:\Sigma\to\Delta^{*}\). השאלה: האם קיימת מילה \(w\in\Sigma^{*}\) כך ש-\(h\left(w\right)=g\left(w\right)\)? וזו, כאמור, בעיה לא כריעה.

כעת, בואו נתעסק בבעיה הבאה: נתונות שתי שפות חסרות הקשר \(L_{1},L_{2}\) (נתונות באמצעות דקדוקים, כרגיל). האם \(L_{1}\cap L_{2}=\emptyset\)? כלומר, האם יש מילה משותפת כלשהי לשתי השפות? אני אראה שאם אנחנו יודעים לפתור את הבעיה הזו באופן כללי, אז אנו גם יודעים לפתור את PCP. הרדוקציה היא פשוטה מאוד, למעשה – קחו רגע וראו אם תצליחו לחשוב עליה.

האלפבית שמעליו השפות שלו יוגדר יסומן בתור \(\Gamma=\Sigma\cup\Delta\), כלומר הוא כולל גם את האותיות של \(\Sigma\) וגם של \(\Delta\), ואני אניח בלי הגבלת הכלליות ש-\(\Sigma\cap\Delta=\emptyset\). עכשיו, אגדיר \(L_{1}=\left\{ w\#w^{R}\ |\ w\in\Gamma^{*}\right\} \) (אני מניח ש-\(\#\notin\Gamma\)) – מה שנקרא "שפת ראי מסומנת". קל לראות שזו שפה חסרת הקשר – כללי הדקדוק הם פשוט \(\left\{ S\to\sigma S\sigma\ |\ \sigma\in\Gamma\right\} \cup\left\{ S\to\#\right\} \). עכשיו, נגדיר את \(L_{2}\) כך: \(L_{2}=\left\{ u^{R}h\left(u\right)\#\left(v^{R}g\left(v\right)\right)^{R}\ |\ u,v\in\Sigma^{*}\right\} \). גם זו שפה חסרת הקשר, וקל לראות את זה עם תכונות סגור. ראשית, \(L=\left\{ w^{R}w^{\prime}\ |\ w\in\Sigma^{*}\right\} \) היא שפה חסרת הקשר עם דקדוק \(S\to\sigma S\sigma^{\prime}|\varepsilon\). שנית, נפעיל על \(L\) הומומורפיזם שעל אותיות ללא תג מחזיר את עצמן, ועל אותיות עם תג מחזיר את מה ש-\(h\) מחזירה על האות ללא תג, ונקבל את השפה \(\left\{ w^{R}h\left(w\right)\ |\ w\in\Sigma^{*}\right\} \). לבסוף נשרשר עם השפה הזו עם השפה שמכילה רק את \(\#\) ואת זה עם השפה שעליה עשינו את אותו תעלול רק עם \(g\).

קחו רגע לשכנע את עצמכם שאכן \(L_{1}\cap L_{2}\ne\emptyset\) אם ורק אם קיים \(w\) כך ש-\(h\left(w\right)=g\left(w\right)\); זה מסיים את ההוכחה.

עכשיו, בעזרת כללי דה-מורגן נקבל ש-\(L_{1}\cap L_{2}\ne\emptyset\) אם ורק אם \(\overline{L_{1}}\cup\overline{L_{2}}\ne\Sigma^{*}\). באופן כללי דבר כזה לא יעזור לנו במיוחד, כי זה ש-\(L_{1},L_{2}\) הן חסרות הקשר לא אומר שגם המשלימות שלהן כאלו, אבל במקרה שלנו זה דווקא נכון. אולי הדרך הקלה ביותר לראות זאת היא באמצעות האבחנה שאת \(L_{1},L_{2}\) אפשר לקבל עם אוטומט מחסנית דטרמיניסטי (מושג שטרם הגדרתי), אבל אפשר גם סתם לחשוב כמה דקות על איך לבנות אוטומטי מחסנית שמקבלים את \(\overline{L_{1}},\overline{L_{2}}\).

המסקנה? אם \(\overline{L_{1}},\overline{L_{2}}\) הן חסרות הקשר כך גם \(\overline{L_{1}}\cup\overline{L_{2}}\), ולכן קיבלנו שהבעיה הבאה אינה כריעה: בהינתן שפה חסרת הקשר \(L\), יש לבדוק האם \(L=\Sigma^{*}\). הבעיה הזו מכונה "בעיית האוניברסליות". העובדה שהיא לא כריעה מראה מייד שגם בדיקת שקילות של דקדוקים היא בעיה לא כריעה – כי אם בהינתן \(G_{1},G_{2}\) היינו יכולים לבדוק האם \(L\left(G_{1}\right)=L\left(G_{2}\right)\) היינו פותרים את בעיית האוניברסליות על ידי בדיקת שקילות לדקדוק שאנחנו יודעים שמייצר את \(\Sigma^{*}\). בעיה נוספת שמייד רואים שהיא לא כריעה היא בעיית ההכלה: בהינתן \(L_{1},L_{2}\), אם הייתה לנו דרך לבדוק האם \(L_{1}\subseteq L_{2}\) היינו יכולים לפתור את בעיית האוניברסליות על ידי בדיקה האם \(\Sigma^{*}\subseteq L\) (או לחילופין, היינו יכולים לבדוק האם \(L_{1}=L_{2}\) על ידי בדיקה האם \(L_{1}\subseteq L_{2}\) וגם \(L_{2}\subseteq L_{1}\)).

חוב אחד שלי שעדיין נשאר מפוסט קודם הוא השאלה האם בהינתן דקדוק \(G\) ניתן לקבוע אם הוא חד משמעי, או שקיימת מילה שקיימים לה שני עצי גזירה. בעיית ההתאמה של פוסט יכולה להיפתר גם על ידי אלגוריתם כזה: בהינתן \(h,g\) נבנה את הדקדוק \(G\) הבא: \(S\to A|B\) ו-\(A\to\sigma Ah\left(\sigma\right)|\varepsilon\) ו-\(B\to\sigma Bg\left(\sigma\right)|\varepsilon\). הדקדוק הזה מייצר מילים מהצורה \(w^{R}h\left(w\right)\) ו-\(w^{R}g\left(w\right)\). כל מילה מהצורה \(w^{R}h\left(w\right)\) נוצרת בצורה יחידה (ה-\(w^{R}\) שבהתחלה מבטיח את זה) וכך גם עבור \(w^{R}g\left(w\right)\); לכן הסיכוי היחיד של הדקדוק להיות רב-משמעי הוא שיתקיים \(w^{R}h\left(w\right)=w^{R}g\left(w\right)\) עבור \(w\) כלשהו, מה שגורר \(h\left(w\right)=g\left(w\right)\).

אם כן, אלו היו שלל בעיות הכרעה לא כריעות, וכעת אני רוצה לחזור ולסיים בנימה אופטימית – אלגוריתם CYK שבודק בהינתן \(w\) האם \(w\in L\) עבור שפה חסרת הקשר \(L\) כלשהי.

נתחיל מזה שלא סתם לוקחים דקדוק כלשהו עבור \(L\) – לוקחים דקדוק \(G\) בצורה הנורמלית של חומסקי, שכבר הזכרתי בעבר ואזכיר שוב – בצורה הנורמלית הזו כל כללי הגזירה בדקדוק הם מהצורה \(A\to a\) או \(A\to BC\). לכל שפה חסרת הקשר \(L\) קיים דקדוק בצורה הנורמלית של חומסקי שמקיים \(L\left(G\right)=L\backslash\left\{ \varepsilon\right\} \) (כלומר, אם המילה הריקה הייתה שייכת ל-\(L\), אז הדקדוק לא ידע לייצר אותה כי הצורה הנורמלית של חומסקי לא מאפשרת את זה). זה אומר שאם אנחנו רוצים לבדוק אם \(\varepsilon\in L\) צריך לבדוק באמצעות אלגוריתם אחר, אבל זה יחסית קל (זה שקול לבדיקה האם המשתנה \(S\) אפיס, כלומר יש לו סדרת גזירה שמסתיימת ב-\(\varepsilon\), וזו בדיקה דומה לבדיקה האם משתנה הוא טרמינלי).

אם כן, אנו מניחים ש-\(w\) הוא מאורך 1 לפחות. והנה הרעיון של האלגוריתם: אם \(A\Rightarrow^{*}w\) אז מתקיים בדיוק אחד משני דברים – או ש-\(\left|w\right|\) מאורך 1 וקיימת גזירה \(A\to w\) בדקדוק; או שקיים פירוק \(w=uv\) וגזירה \(A\to BC\) כך ש-\(B\Rightarrow^{*}u\) וגם \(C\Rightarrow^{*}v\). על בסיס האבחנה הזו אפשר לתת אלגוריתם רקורסיבי שבודק את התנאי הזה, על ידי בדיקת כל הפירוקים האפשריים של \(w\) מהצורה \(w=uv\), ועם תנאי עצירה עבור הסיטואציה שבה \(\left|w\right|=1\).

רק מה, האלגוריתם הרקורסיבי הזה עשוי לעשות עבודה כפולה, ולא מעט ממנה. לכן אנחנו נוקטים בגישה שמכונה תכנון דינמי, והיא בעצם שם מפוצץ ל"תזכור את תוצאות חישובי הביניים שלך ותשתמש בהן שוב אם צריך". לצורך כך, בואו נניח ש-\(w=\sigma_{1}\sigma_{2}\dots\sigma_{n}\). כעת אפשר לתאר תת-מילים של \(w\) באמצעות שני מספרים טבעיים – האורך שלה \(l\), והאינדקס שבו היא מתחילה \(i\). כעת אגדיר משתנים בוליאניים \(P_{l,i}^{\left(A\right)}\) שהרעיון הוא שהם יקבלו "אמת" אם ורק אם \(A\Rightarrow^{*}\sigma_{i}\sigma_{i+1}\dots\sigma_{i+\left(l-1\right)}\). אם \(S\) הוא המשתנה ההתחלתי של הדקדוק, הרי שהשאלה האם \(w\in L\) זהה לשאלה אם \(P_{n,1}^{\left(S\right)}\) הוא "אמת", אז מה שאנחנו רוצים הוא אלגוריתם לחישוב ה-\(P\)-ים הללו.

לא אתן כאן פסאודו-קוד מלא של האלגוריתם (אבל למי שזה מעניין אותו אני ממליץ לתכנת אותו), אבל הרעיון הכללי פשוט: ראשית נותנים את הערך "שקר" לכל ה-\(P\)-ים. כעת עוברים על כל הגזירות מהצורה \(A\to a\) בדקדוק ומשנים את \(P_{1,i}^{\left(A\right)}\) ל"אמת" לכל אינדקס \(i\) כך ש-\(\sigma_{i}=a\). זה תנאי ההתחלה שלנו.

עכשיו, לכל \(1<r\le n\) באופן סדרתי, ולכל משתנה \(A\), ולכל \(1\le i\le n-r\) אנחנו רוצים לחשב מהו \(P_{r,i}^{\left(A\right)}\) – כלומר, האם \(A\) יודע לגזור את תת-המילה \(\sigma_{i}\sigma_{i+1}\dots\sigma_{i+\left(r-1\right)}\). לצורך כך אנחנו עוברים על כל הגזירות מהצורה \(A\to BC\) של המשתנה \(A\); כעת, לכל אינדקס \(i\le j<n-r\) אנחנו בודקים האם שני המשתנים \(P_{j-i+1,i}^{\left(B\right)}\) ו-\(P_{n-r-j,j+1}^{\left(C\right)}\) הם "אמת" בו זמנית – אם כן, אז הופכים את \(P_{r,i}^{\left(A\right)}\) לאמת בעצמו. זה הסוף.

מה הסיבוכיות של האלגוריתם? מכיוון שכל \(P\) מחושב בדיוק פעם אחת, הקריאה ה"רקורסיבית" שדיברתי עליה לא באה לידי ביטוי באלגוריתם כלל (האלגוריתם הוא למעשה איטרטיבי, לא רקורסיבי). זה אומר שצריך בעיקר לבדוק כמה לולאות יש בו. שאלה אחרת היא ביחס למה מודדים את הסיבוכיות – כאן יש שני גורמים שונים. אחד הוא אורך המילה \(w\), שסימנו \(n\), והשני הוא גודל הדקדוק \(\left|G\right|\) (למשל, מספר כללי הגזירה שלו).

ובכן, אנחנו עוברים על כל ה"רמות" של ה-\(P\)-ים, החל מ-\(r=1\) ועד \(r=n\), כך שזו לולאה אחת מאורך \(n\); בכל מעבר כזה, אנחנו עוברים על כל ה-\(i\)-ים בתחום מ-1 ועד \(n-r\) – זו לולאה שניה שמספר האיטרציות בה חסום על ידי \(n\). כעת אנחנו עוברים על כל הגזירות הקיימות בדקדוק לכל המשתנים – חסום על ידי \(\left|G\right|\), ולכל גזירה כזו אנו מבצעים בדיקה שתלויה בבחירה של האינדקס \(i\le j<n-r\) – גם כן חסום על ידי \(n\). קיבלנו זמן ריצה של \(O\left(n^{3}\left|G\right|\right)\). שזה לא רע, גם אם לא נפלא כמו זמן הריצה \(O\left(n\right)\) של אוטומט סופי דטרמיניסטי על מילה. כמובן, במרבית היישומים הפרקטיים זה לא מספיק טוב, ומשתמשים באלגוריתמים פחות כלליים שמותאמים לדקדוקים יותר ספציפיים ויעילים – אבל זה נושא לדיון כשמדברים על פרסור שפות חסרות הקשר (למשל, בקומפילציה).

סיימנו! לטעמי עם הפוסט הזה גמרתי לכסות את נושאי הבסיס שבדרך כלל מציגים כמבוא לתורת השפות הפורמליות (אם כי דילגתי על דברים פה ושם – למשל צורות נורמליות). עם זאת, אני עדיין לא רוצה להיפרד; בפוסטים הבאים אדבר קצת על נושאים מתוחכמים יותר, ואחזור למשפטים קיימים ואתן להם הרחבות ועוד נקודות מבט. לדעתי החלק המגניב באמת רק מתחיל.

שפות חסרות הקשר – תכונות סגור

הפוסט הקודם שלי על שפות חסרות הקשר היה כבד יחסית, אז בואו נישאר הפעם במסגרת הדברים הקלילים. אני ממשיך עם ההקבלה שלנו לשפות רגולריות, והגענו לשלב שבו אנחנו מוכיחים כל מני תכונות סגור שונות ומשונות – פעולות שאפשר להפעיל על שפות חסרות הקשר בצורה שמבטיחה שהתוצאה היא עדיין חסרת הקשר. אלו כלים מאוד יעילים כדי להוכיח ששפה היא חסרת הקשר (או לא חסרת הקשר: מתחילים מהשפה החשודה ומגיעים מפעולות סגור לשפה שידוע שאינה חסרת הקשר, וזו הוכחה שהשפה המקורית לא הייתה חסרת הקשר).

הפעולות עצמן יהיו סטנדרטיות וזהות כמעט לגמרי למה שהופיע עבור שפות רגולריות, למעט הבדל מרכזי אחד שאציין כבר עכשיו: שפות חסרות הקשר אינן סגורות לחיתוך. קל מאוד לראות את זה: ראינו בפוסט הקודם ש-\(\left\{ a^{n}b^{n}c^{n}\ |\ n\in\mathbb{N}\right\} \) אינה חסרת הקשר, אבל מאוד קל לראות ש-\(\left\{ a^{n}b^{n}c^{k}\ |\ n,k\in\mathbb{N}\right\} \) ו-\(\left\{ a^{k}b^{n}c^{n}\ |\ n,k\in\mathbb{N}\right\} \) שתיהן חסרות הקשר והשפה ההיא מתקבלת בתור החיתוך שלהן (למה?). עדיין, מה האינטואיציה כאן? למה מה שהייתה תכונת סגור עבור שפות רגולריות היא לא כזו עכשיו? לטעמי לב העניין בכך שהמודלים שלנו עבור שפות חסרות הקשר הם אי-דטרמיניסטיים באופיים. או שיש לנו אוטומט מחסנית אי דטרמיניסטי (עדיין צריך לדבר על מה קורה עם אוטומט מחסנית דטרמיניסטי; אגלה כבר עכשיו בסוד שהוא חלש יותר מאוטומט מחסנית אי דטרמיניסטי) או שיש לנו דקדוק, שהוא מטבעו יצור אי דטרמיניסטי (בדרך כלל לכל משתנה יש יותר מגזירה אפשרית אחת).

הגישה האי-דטרמיניסטית לייצור/זיהוי מילה היא "מספיק שתהיה דרך כלשהי להגיע אל המילה כדי שהיא תהיה בשפה". כלומר, מספיק שדקדוק ייצר את המילה פעם אחת כדי שהיא תהיה בשפה; ומספיק שהאוטומט האי דטרמיניסטי יקבל את המילה באחד ממסלולי החישוב שלו כדי שזה ייקרא שהיא מתקבלת. אבל כשאנחנו מדברים על חיתוך, אנחנו בעצם רוצים להגיד "אסור לקבל את המילה אלא אם אנחנו מגיעים אליה בשתי דרכים שונות", ואת זה כבר קשה לנו לעשות. תחשבו רגע איך לעשות את זה בדקדוק ותראו שזה מאתגר; אבל למה עבור אוטומט זה קשה? למה הבניה הסטנדרטית של אוטומט מכפלה לא עובדת? פשוט מאוד: כי אוטומט מכפלה יצטרך לעבוד עם שתי מחסניות, אחת לכל אוטומט שהוא מסמלץ, אבל המודל שלנו מאפשר לעבוד רק עם מחסנית אחת (בהמשך נראה שאם מרשים שתי מחסניות הכוח של המודל קופץ בצורה קיצונית, הכי גבוה שרק אפשר – אל מכונת טיורינג). עם זאת, לא הכל אבוד: עדיין אפשר לבנות אוטומט מכפלה אם אחת משתי השפות אינה דורשת את המחסנית; במילים אחרות, אם אחת מהשפות היא רגולרית. לכן אמנם חיתוך של שתי שפות חסרות הקשר כלליות אינו תכונת סגור, אבל חיתוך של שפה חסרת הקשר עם שפה רגולרית היא כן תכונת סגור (ותכונה מועילה למדי).

אוטוטו נראה שאיחוד הוא כן תכונת סגור, ולכן מכך שחיתוך אינו תכונת סגור אנחנו לומדים גם שמשלים אינו יכול להיות תכונת סגור (כי אפשר לקבל חיתוך בעזרת משלים ואיחוד – כללי דה-מורגן). לכן אפשר להשתמש גם במשלים כדי לקבל אינטואיציה, אולי אפילו חזקה יותר (למשל, עבור מכונות טיורינג אי דטרמיניסטיות דווקא כן יש סגירות לחיתוך, אבל אין סגירות למשלים – בלשון פורמלית, \(\mbox{RE}\ne\mbox{coRE}\)). הבעיה במשלים היא דווקא לא בצורך שלנו לדחות מילים שהיו שייכות לשפה שאנחנו משלימים – את זה קל לעשות – הקושי הוא בלקבל דווקא את המילים שקודם לא היו בשפה (ולכן בדקדוק אין שום דבר שמייצר אותן, ובאוטומט מחסנית אין להן אף מסלול מקבל, אבל הרי גם למילים בשפה יכולים להיות מסלולים דוחים רבים אז סתם להחליף בין המצב המקבל והדוחה לא יעבוד).

אוקיי, אז זה מה שאינו תכונת סגור ושונה מאשר בשפות רגולריות. מה עם מה שכן?

שלוש הפעולות החביבות עלינו בשפות רגולריות היו איחוד, שרשור וסגור קלייני שכן משפט קלייני הראה שבעזרתן אפשר לבנות את כל השפות הרגולריות מתוך כל השפות הסופיות. נניח שיש לנו שתי שפות חסרות הקשר \(L_{1},L_{2}\) עם דקדוקים שמייצרים אותן \(G_{1}=\left(V_{1},T,S_{1},P_{1}\right)\) ו-\(G_{2}=\left(V_{2},T,S_{2},P_{2}\right)\) בהתאמה (אני מניח שקבוצת הטרמינלים \(T\) משותפת לשתי השפות, אחרת לוקחים את קבוצת האיחוד של הטרמינלים של שתיהן). אז דקדוק עבור האיחוד ייבנה על ידי הוספת משתנה התחלתי חדש \(S\) עם כללי הגזירה \(S\to S_{1}|S_{2}\) ולקיחת כל המשתנים וכללי הגזירה של שני הדקדוקים; דקדוק עבור השרשור ייבנה על ידי הוספת משתנה התחלתי חדש \(S\) וכלל הגזירה \(S\to S_{1}S_{2}\); ודקדוק עבור סגור קלייני של \(L_{1}\) ייבנה על ידי \(S\to SS_{1}|\varepsilon\). כבר עשיתי את זה בפוסט הפותח שלי על שפות חסרות הקשר אבל למה לא לעשות שוב. תרגיל נחמד זה להוכיח את הסגירויות הללו עם אוטומט מחסנית במקום עם דקדוק (מהר מאוד תגלו שקבלה על ידי ריקון מחסנית נוחה יותר מאשר קבלה עם מצבים מקבלים כשרוצים לכתוב את זה פורמלית).

התכונה הבאה היא הומומורפיזם. עבור שפות רגולריות הוכחתי אותה באינדוקציית מבנה כי היה לשפות הרגולריות מבנה אינדוקטיבי פשוט. אני לא מכיר מבנה דומה עבור שפות חסרות הקשר, אבל למרבה המזל, עם דקדוקים ההוכחה ממש קלה. נניח ש-\(h:\Sigma\to\Gamma\) הוא הומומורפיזם וניקח דקדוק \(G=\left(V,\Sigma,S,P\right)\). נבנה דקדוק \(G^{\prime}=\left(V\cup\Sigma,\Gamma,S,P\cup P^{\prime}\right)\) שהתעלול בו הוא שמי שהיו טרמינלים בדקדוק הקודם הם עכשיו גם כן משתנים, ונוסיף להם כללי גזירה: לכל \(\sigma\in\Sigma\) נוסיף את כלל הגזירה \(\sigma\to h\left(\sigma\right)\). עכשיו, קחו את עץ הגזירה של מילה בדקדוק הזה, והסירו ממנו את העלים – קיבלתם עץ גזירה של מילה בדקדוק המקורי. יחד עם העלים, מה שקורה הוא שכל טרמינל מוחלף בערך ההומומורפיזם עליו – מה שצריך להיות.

ההוכחה עבור הצבה דומה מאוד. כזכור, הצבה היא מעין הרחבה של הומומורפיזם כך שלכל אות מתאימים שפה, לא מילה. לכל \(\sigma\in\Sigma\) נסמן את השפה שההצבה מעבירה את \(\sigma\) אליה ב-\(L_{\sigma}\). כדי שתהיה לנו תקווה כלשהי לכך שהצבה תהיה תכונת סגור אנחנו חייבים לדרוש ש-\(L_{\sigma}\) תהיה חסרת הקשר (למה?) ולכן יש לה דקדוק \(\left(V_{\sigma},T_{\sigma},S_{\sigma},P_{\sigma}\right)\). נוסיף לדקדוק שלנו את כל המשתנים, הטרמינלים וכללי הגזירה של כל דקדוק כזה, ואת כלל הגזירה \(\sigma\to S_{\sigma}\). עכשיו תסבירו לעצמכם למה זה עובד.

עוד תכונת סגור של שפות רגולריות הייתה היפוך. לא קשה להראות (באינדוקציה…) שאם ניקח דקדוק ונהפוך את הכללים שלו (כלומר, נחליף כל כלל \(A\to\alpha\) ב-\(A\to\alpha^{R}\)) נקבל דקדוק עבור השפה ההפוכה. זה מעניין, כי קשה לי לראות דרך טובה להוכיח את התכונה הזו בעזרת אוטומט מחסנית (אני מניח שאפשר להפוך חישובים עם אוטומט מחסנית, אבל בגלל הצורך להתעסק עם המחסנית זה הופך להיות מאוד טרחני ומעצבן).

התכונה הבאה היא הומומורפיזם הפוך, וכאן העניינים קצת מסתבכים. כזכור, אם \(h:\Sigma\to\Delta\) הוא הומומורפיזם ו-\(L\subseteq\Delta^{*}\), אז מגדירים \(h^{-1}\left(L\right)=\left\{ w\in\Sigma:h\left(w\right)\in L\right\} \). המטרה שלנו היא להראות שאם \(L\) חסרת הקשר, כך גם \(h^{-1}\left(L\right)\). אבל את זה אני לא יודע לעשות עם דקדוקים, לשם שינוי. הומומורפיזם היה קל, כי כל אות גזרה את התמונה של האות הזו; אבל בהומומורפיזם הפוך אני צריך איכשהו לקבץ אותיות לקבוצות ולהמיר את כולן למקור שלהן, וזה כבר נשמע כמו דקדוק תלוי הקשר ולא חסר הקשר. נו טוב, לא חייבים ללכת עם הראש בקיר – אפשר במקום זה להשתמש באוטומט מחסנית.

עבור שפות רגולריות, ההוכחה הייתה ממש קלה. לקחנו אוטומט עבור \(L\) ובנינו אוטומט חדש עבור \(h^{-1}\left(L\right)\) שפעל כך – על כל אות \(\sigma\) הוא ביצע "סימולציה" של האוטומט המקורי על \(h\left(\sigma\right)\). זה היה קל במיוחד, כי לא באמת היה צריך לבצע את צעדי הסימולציה במפורש – כבר בזמן בניית האוטומט ידענו בודאות לאן הם יביאו אותנו והגדרנו את פונקציית המעברים בהתאם, כלומר הגדרנו \(\delta^{\prime}\left(q,\sigma\right)=\hat{\delta}\left(q,h\left(\sigma\right)\right)\). האם זה עדיין יעבוד? לא. למה לא? כי עכשיו תוצאת הסימולציה תלוייה בשני דברים: גם במצב שבו האוטומט נמצא, אבל גם בתוכן המחסנית. ותוכן המחסנית זה משהו שלא ידוע מראש כשבונים את קידוד האוטומט, ויש אינסוף תכנים אפשריים למחסנית כך שאי אפשר לכסות את כל המקרים. לא, הפעם הסימולציה תהיה חייבת להתבצע "צעד צעד". אם זה עדיין לא ברור למה, חשבו על הסיטואציה הבאה: \(h\left(0\right)=aaa\). אנחנו רוצים להריץ סימולציה על \(0\), כלומר להזין לאוטומט שאנחנו מסמלצים את \(aaa\) ולראות מה קורה, על ה-\(a\) הראשון האוטומט מרוקן את הסימן שהיה בראש המחסנית. זה אומר שהמשך החישוב תלוי לא רק ב-\(0\) שקראנו, במצב שהיינו בו ובמה שהיה אז בראש המחסנית, אלא גם במה שהיה מתחת לראש המחסנית. ומי יודע מה האוטומט עושה הלאה – אולי הוא מרוקן את המחסנית עם מסעי-\(\varepsilon\) עד שהוא מגיע בה לתו מסויים? כלומר, מה שיקרה הלאה תלוי בכל תוכן המחסנית, ואי אפשר להתכונן מראש לכל אינסוף המקרים האפשריים.

יש בעיה קטנה עם לבצע את הסימולציה "צעד צעד" – בכל צעד אנחנו קוראים לכל היותר תו קלט אחד, ואם עכשיו אני אמור לרוץ על \(aaa\), אני צריך "לזכור" את התווים הללו, ולהזין אותם אחד-אחד לאוטומט שאני מסמלץ. למרבה המזל, קל מאוד לעשות את זה – כל מה שאני צריך פה הוא כמות סופית של זכרון (עוד מעט אסביר למה, אם זה לא ברור) ולכן המצבים שלי יכולים לקודד את המידע הזה. באופן אינטואיטיבי, הסימולציה שלי תכלול את הרכיבים הבאים: את קבוצת המצבים של האוטומט שאני מסמלץ; המחסנית שלי גם כן תשמש את האוטומט הזה ואני לא אגע בה; ובנוסף לכך יהיה לי מין "חוצץ" בצד שזוכר מה מילת הקלט הנוכחית שאני רוצה להזין לסימולציה. אם החוצץ ריק, אני קורא אות חדשה מהקלט האמיתי שלי, מחשב את \(h\) עליה ומכניס לחוצץ. בפועל, החוצץ הזה ממומש עם קבוצת המצבים של האוטומט שאני בונה.

קרוב לודאי שאיבדתם אותי, אז בואו נסתכל על הבניה הפורמלית – אני מקווה שהיא תהיה ברורה יותר. בואו ניקח \(L\subseteq\Delta^{*}\) ואוטומט מחסנית בשבילה שמקבל על ידי ריקון: \(M=\left(Q,\Delta,\Gamma,q_{0},\perp,\delta,\emptyset\right)\). אני אבנה אוטומט חדש \(M^{\prime}\) שקבוצת המצבים שלו מוגדרת בצורה קצת מוזרה: \(\left\{ \left(q,w\right)\ |\ \exists\sigma\in\Sigma,u\in\Delta^{*}:h\left(\sigma\right)=uw\right\} \). פורמלית, המצבים שלי הם כל הזוגות של מצב מ-\(Q\) ומילה \(w\in\Delta^{*}\) שהיא סיפא של תמונה של \(h\) על אות כלשהי מ-\(\Sigma\). למה סיפות? הכי פשוט לראות דוגמה. נניח ש-\(h\left(0\right)=abca\). אז אחרי שהאוטומט שלי קורא \(0\), הוא יודע שהוא צריך להזין לאוטומט שהוא מסמלץ את \(abca\). עכשיו, אחרי שהוא מזין לאוטומט הזה את ה-\(a\) הראשון, הוא עדיין צריך לזכור את יתר הדברים שהוא רוצה להזין אליו – כלומר, המחרוזת \(bca\), שהיא סיפא של \(abca\). אחרי שהוא הזין את ה-\(b\) הוא נשאר עם \(ca\), וכן הלאה – הבנתם את העיקרון. בסופו של דבר הוא יישאר עם \(\varepsilon\) (שגם היא סיפא, של כל מילה) ואז הוא ידע שהגיע הזמן לקרוא אות חדשה מהקלט האמיתי שלו (או לסיים).

הנה פונקציית המעברים שלנו, כאשר אני מבדיל בין שני סוגי מעברים – כזה שבו "מטעינים את החוצץ" וכזה שבו מבצעים צעד סימולציה.

  1. \(\delta^{\prime}\left(\left(q,\varepsilon\right),a,A\right)=\left\{ \left(\left(q,h\left(a\right)\right),A\right)\right\} \) – שימו לב שלא נוגעים כאן במחסנית ושהצעד הזה מתקיים רק כאשר החוצץ ריק.
  2. \(\delta^{\prime}\left(\left(q,aw\right),\varepsilon,A\right)=\left\{ \left(\left(p,w\right),\alpha\right)\ |\ \left(p,\alpha\right)\in\delta\left(q,a,A\right)\right\} \) – שימו לב שכאן \(a\in\Gamma\cup\left\{ \varepsilon\right\} \), כלומר ייתכן לבצע צעד סימולציה של מסע-\(\varepsilon\) שלא משנה את תוכן החוצץ.

בואו נרפרף גם על ההוכחה שזה עובד, למרות שאני חושב שהבניה (אחרי שמבינים אותה) היא די משכנעת. הרעיון בהוכחה, כמו כמעט כל הוכחת "בניה" אחרת בנושא הזה, היא להראות שהסימולציה "מתנהגת כמו שאנחנו מצפים בכל הצעדים שלה". פורמלית, ש-\(\left[\left(q,\varepsilon\right),w,\alpha\right]\vdash_{M^{\prime}}^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\) אם ורק אם \(\left[q,h\left(w\right),\alpha\right]\vdash_{M}^{*}\left[p,\varepsilon,\beta\right]\) (כאן אני שם את שמו של האוטומט ליד ה-\(\vdash\) כדי שנדע על חישוב באיזה מהם מדובר). אם הראינו את זה, העובדה ש-\(L\left(M^{\prime}\right)=h^{-1}\left(L\left(M\right)\right)\) מתקבלת מייד על ידי בחירת \(\alpha=\perp,\beta=\varepsilon,q=q_{0}\), כי מצד אחד אם \(w\in L\left(M^{\prime}\right)\) אז נקבל ש-\(h\left(w\right)\in L\left(M\right)\) ולכן \(w\in h^{-1}\left(L\left(M\right)\right)\); ומצד שני אם \(w\in h^{-1}\left(L\left(M\right)\right)\) זה אומר ש-\(h\left(w\right)\in L\left(M\right)\) ולכן קיימת ריצה מקבלת של \(h\left(w\right)\) ב-\(L\left(M\right)\) וממנה אפשר לקבל ריצה מקבלת של \(w\) ב-\(L\left(M^{\prime}\right)\).

ההוכחה היא באינדוקציה על האורך של \(w\). עבור \(\left|w\right|=0\) נקבל שצריך להוכיח כי \(\left[\left(q,\varepsilon\right),\varepsilon,\alpha\right]\vdash_{M^{\prime}}^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\) אם ורק אם \(\left[q,\varepsilon,\alpha\right]\vdash_{M}^{*}\left[p,\varepsilon,\beta\right]\) – זה נראה אולי טריוויאלי, אבל בעצם זה לא ממש טריוויאלי – זה אומר ש-\(M^{\prime}\) מסמלץ כמו שצריך את מסעי ה-\(\varepsilon\) של \(M\). רק כדי להוכיח את הטענה הזו נצטרך עוד אינדוקציה, על אורך החישוב. אבל למי יש כוח אז נעזוב את זה.

עכשיו, נניח נכונות עבור מילים מאורך \(n\) ונוכיח עבור מילים מאורך \(n+1\). כאן ישתלם לנו לפרק חישובים לפי הצעד הראשון וכל מה שאחריו. כלומר, נניח ש-\(\left[\left(q,\varepsilon\right),aw,\alpha\right]\vdash_{M^{\prime}}^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\) עבור מילה \(aw\) כלשהי. מכיוון שבהתחלה החוצץ ריק, הצעד הראשון חייב להיות מהצורה 1. כלומר, אפשר לפרק את החישוב כך: \(\left[\left(q,\varepsilon\right),aw,\alpha\right]\vdash\left[\left(q,h\left(a\right)\right),w,\alpha\right]\vdash^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\). היינו רוצים להשתמש בהנחת האינדוקציה שלנו על \(\left[\left(q,h\left(a\right)\right),w,\alpha\right]\vdash^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\), אבל אי אפשר – כי הנחת האינדוקציה מתבססת על כך שהחוצץ ריק בקונפיגורציה השמאלית. לכן צריך להוכיח – שוב, באינדוקציה על אורך החישוב – ש-\(\left[\left(q,h\left(a\right),\varepsilon,\alpha\right)\right]\vdash_{M^{\prime}}^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\) אם ורק אם \(\left[q,h\left(a\right),\alpha\right]\vdash_{M}^{*}\left[p,\varepsilon,\beta\right]\). זה לא עד כדי כך קשה, כי המעברים היחידים האפשריים כל עוד החוצץ לא התרוקן הם מעברי \(\varepsilon\) (כי אין קלט). אחרי שסיימנו עם זה, ההמשך טבעי: נפרק את החישוב הראשוני שלנו לארבעה חלקים:

\(\left[\left(q,\varepsilon\right),aw,\alpha\right]\vdash\left[\left(q,h\left(a\right)\right),w,\alpha\right]\vdash^{*}\left[\left(s,\varepsilon\right),w,\gamma\right]\vdash^{*}\left[\left(p,\varepsilon\right),\varepsilon,\beta\right]\)

ובעזרת טענות העזר והנחת האינדוקציה רואים שזה מתקיים אם ורק אם ב-\(M\) מתקיים:

\(\left[q,aw,\alpha\right]\vdash^{*}\left[s,w,\gamma\right]\vdash^{*}\left[p,\varepsilon,\beta\right]\)

כפי שרצינו.

בפוסט הבא נגיע אל מה שהוא סיום חומר הבסיס שבדרך כלל מציגים בנושאים הללו – בעיות הכרעה!