אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 תרגיל בית מספר - 6להגשה עד 6ביוני בשעה 325:: קיראו בעיון את הנחיות העבודה וההגשה המופיעות באתר הקורס ,תחת התיקיה .assignmentsחריגה מההנחיות תגרור ירידת ציון /פסילת התרגיל. הנחיות ספציפיות לתרגיל זה: תשובות לשאלות 4 ,3 ,1א' ,ב' ,ו 5 -יש לממש בקובץ השלד ( )skeleton.pyהמצורף לתרגיל זה .אין לצרף לקובץ ה py-את הקוד ששימש לפתרון יתר השאלות .לא לשכוח לשנות את שם הקובץ למספר ת"ז שלכם לפני ההגשה ,אך להשאיר את הסיומת .py שימו לב שבקובץ השלד יש קוד שמבצע בדיקות של כמה מקרים פשוטים .היעזרו בקוד זה כדי לוודא נכונות הפלטים שלכם עבור אותם מקרים .פתרונות שלא עובדים נכון במקרים פשוטים אלו לא יתקבלו .כמובן ,על הקוד שלכם להיות נכון לכל קלט תקין ,ולא רק למקרים שבדוגמאות .אסור לשנות את כותרות הפונקציות או להוסיף ארגומנטים חדשים. תשובות לכל שאר השאלות יוגשו בקובץ docx ,docאו pdfיחיד. בסה"כ מגישים שני קבצים בלבד .עבור סטודנט שמספר ת"ז שלו הוא 012345678הקבצים שיש להגיש הם ( 012345678.docxאו .docאו ).pdfו.012345678.py - הקפידו לענות על כל מה שנשאלתם. במסמך התשובות ,תנו תשובות קולעות וברורות ,כנדרש בשאלה .מטרת הגבלת אורך התשובה היא כפולה: .1על מנת שנוכל לבדוק את התרגילים שלכם בזמן סביר. .2כדי להרגיל אתכם להבעת טיעונים באופן מתומצת ויעיל ,ללא פרטים חסרים מצד אחד אך ללא עודף בלתי הכרחי מצד שני .זוהי פרקטיקה חשובה במדעי המחשב. עמ' 1מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 שאלה 1 בשאלה זו תממשו מבנה נתונים שנקרא דו-תור ( double-ended queueאו בקיצור ,Dequeקריֶ :דק), התומך בפעולות הבאות: – head_insert הכנסה בראש הדו-תור – tail_insert הכנסה בזנב הדו-תור – head_remove מחיקה מראש הדו-תור – tail_remove מחיקה מזנב הדו-תור – head החזרת האיבר שבראש הדו-תור (או Noneאם הדו-תור ריק מאיברים) - tail החזרת האיבר שבזנב הדו-תור (או Noneאם הדו-תור ריק מאיברים) על כל הפעולות להתבצע בסיבוכיות זמן ) O(1במקרה הגרוע .אין להשתמש במימושים קיימים של ,Deque למשל .itertools.deque ממשו מחלקה בשם ,Dequeהכוללת את המתודות הנ"ל (וכמובן __ ,__initו ,__repr__ -ראו בהמשך). איברי הדו-תור צריכים להיות עצמים מהמחלקה Nodeשראיתם בכיתה .המחלקה Nodeוכותרות המתודות של המחלקה Dequeמופיעות בקובץ השלד שמסופק עם התרגיל. ממשו את המתודה __ __reprכך שתחזיר מחרוזת המכילה את איברי הדו-תור עם רווחים ביניהם (אך לא בהתחלה או בסוף) ,כאשר ראש התור יהיה האיבר השמאלי .מטרת הנחיה זו היא ליצור אחידות שתאפשר בדיקת הקוד שלכם ע"י הרצות. דוגמאות הרצה: )(>>> dq = Deque )>>> dq.head_insert(1 )>>> dq.head_insert(2 )>>> dq.head_insert(3 >>> dq 321 )>>> dq.tail_insert(4 >>> dq 3214 )(>>> dq.head_remove >>> dq 214 )(>>> dq.tail_remove >>> dq 21 )(>>> dq.head 2 )(>>> dq.tail 1 עמ' 2מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 שאלה 3 כזכור ,פקטור העומס של טבלת hashמוגדר כ ,α = n/m -כאשר mהוא גודל הטבלה ו n -הוא מספר האיברים בה .בד"כ ייקבע גודל הטבלה כתלות ב ,n -מתוך מטרה להגביל את .αלמשל ,אם m=½nאז .α=2 בשאלה זו נטפל במצב שבו איננו יודעים מראש כמה איברים צפויים להיכנס לטבלת ה hash -שלנו .פתרון אפשרי הוא להקצות טבלה בגודל כלשהו ,ובכל פעם ש α -גדל מעבר לערך מסוים ,להגדיל את הטבלה. פעולה כזו מכונה ,rehashוכרוכה במעבר על כל הטבלה והכנסת כל האיברים שלה לטבלה החדשה .כמובן, הדבר מצריך גם שינוי בפונקצית ה ,hash -כדי שתמפה ערכים לטווח האינדקסים של הטבלה החדשה. נניח שהתנגשויות מטופלות בשיטת השרשור ( ,)chainingשהגודל ההתחלתי של הטבלה הוא ,1ושמגדילים את הטבלה בכל פעם ש α -מגיע ל .1 -בכל אחד מהסעיפים הבאים מופיעה אסטרטגיה אפשרית לקביעת גודל הטבלה החדשה: א .בעת הגדלת הטבלה ,הגודל החדש יהיה .m+1 ב .בעת הגדלת הטבלה ,הגודל החדש יהיה .m+7 ג .בעת הגדלת הטבלה ,הגודל החדש יהיה .2m בכל סעיף ,נתחו את סיבוכיות הזמן הכוללת של סדרת Nהכנסות רצופות (כלומר Nהכנסות ,בזו אחר זו, ללא מחיקות) .תנו תשובה אסימפטוטית במונחי )…( Oכתלות ב .N -יש לתת נימוק קצר -שורה או שתיים. שאלה 2 א .ממשו גנרטור בעל החתימה ) take_only(it, predicate, nשמקבל איטרטור ,itופונקציה predicate יקט) .הגנרטור מייצר את המקבלת ארגומנט יחיד ומחזירה ( True/Falseפונקציה כזאת נקראת פְּ ֶר ִד ָ האיברים של itלפי סדרם אם הם עונים על התנאי .predicateכלומר take_onlyמייצר תת-סדרה של איברי itהמכילה רק איברים xעבורם .predicate(x)==Trueאם nאיברים רצופים אינם עונים לתנאי take_only ,מפסיק לייצר איברים וזורקת exceptionע"י .raise StopIterationלדוגמא: ))>>> list(take_only(iter(range(30)), lambda x: x%3==1 , 5 ][1, 4, 7, 10, 13, 16, 19, 22, 25, 28 ))>>> list(take_only(iter(range(30)),lambda x: x<10 or x%7==0 ,5 ][0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14 ב .ממשו גנרטור בעל החתימה ) blocks(it, kשמקבל איטרטור itומספר kומחזיר רשימות של איברים עוקבים מתוך itשאורכן .kלמשל ,שלושת האיברים הראשונים שיוחזרו ע"י blocksעם k=3הם: כאשר הם איברי .itאם itמייצר מס' איברים סופי שאינו מתחלק ב blocks ,k-יחזיר בלוק אחרון שאורכו קצר יותר מ .k-לדוגמא: ))>>> list(blocks(iter(range(10)),5 ]][[0, 1, 2, 3, 4], [5, 6, 7, 8, 9 ))>>> list(blocks(iter(range(10)),3 ]][[0, 1, 2], [3, 4, 5], [6, 7, 8], [9 שימו לב :בשני הסעיפים האיטרטורים שניתנים כקלט אינם בהכרח סופיים. עמ' 3מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 שאלה 4 מטרת השאלה היא לתרגל את העיקרון של אלגוריתם קארפ-רבין ,וכמו כן לצבור מיומנות בהבנת קוד חלקי שניתן לכם לפתרון בעיה מסויימת ,ולהשלים אותו. בשאלה זו נשוב לבעיה של חיפוש תת-מחרוזת משותפת באורך מקסימלי ,בה נתקלנו בתרגיל בית מס' ,5אך הפעם ננקוט גישה שונה .כשאנחנו מחפשים מחרוזת משותפת מקסימלית ,אנחנו מחפשים מחרוזות משותפות באורך הולך ועולה ,נסמן את האורך ב . -בשאלה זו נחזיק את תתי-המחרוזות בטבלת hash ונשתמש ב fingerprint-של אלגוריתם של Karp-Rabinבתור פונקצית ה .hash-ננצל את התכונות של אלגוריתם Karp-Rabinונגדיל באופן הדרגתי וביעילות את אורכי ה"חלונות" עבורם הfingerprints- מחושבים .להלן הסבר מפורט. נשים לב לתכונה הבאה של טביעות האצבע של אלגוריתם :Karp-Rabin עבור המחרוזת ,נסמן ב- את טביעת האצבע של החלון ניתן לחשב את מתוך באמצעות כלל הורנר ) (Horner’s ruleשהוזכר בהרצאות .לכן ,בהינתן ,נסמנה רשימת כל טביעות האצבע של חלונות באורך . ,ונוכל בקלות לחשב ממנה את (כל טביעות האצבע באורך ) .נמשיך להשתמש בסימונים שהגדרנו כאן לאורך השאלה. בקובץ השלד ישנה פונקציה find_longestשמבצעת חיפוש תת-מחרוזת משותפת מקסימלית של שתי מחרוזות .המימוש של find_longestמופיע כבר בקובץ ,והיא קוראת לפונקציות אחרות has_match :שגם המימוש שלה כבר מופיע ,ושתי הפונקציות – extend_fingerprints, make_hashtableעבורן המימוש חסר, ואתם מתבקשים להשלים אותו ,כמוסבר בהמשך .כאמור ,חלק ממטרת התרגיל היא לנסות ולהבין את הקוד שמומש כבר. .הפרמטרים לאורך התרגיל ,כשנחשב טביעות אצבע ,נשתמש בפרמטרים שונים מאלה שראינו בשיעור ,זאת על מנת שניתן יהיה להשתמש בטביעות האצבע כפונקציית hash ביעילות .לו היינו משתמשים ב- תאים. היינו נאלצים להשתמש בטבלת ענק עם סעיף א ממשו את הפונקציה ) .extend_fingerprints(text, fingers, l, basis, rהפונקציה מקבלת מחרוזת טקסט ) (textואת רשימת טביעות האצבע הפונקציה מחשבת את של הטקסט עבור חלונות באורך . – טביעות האצבע של הטקסט עבור חלונות באורך (זהו הפרמטר השלישי שמועבר לפונקציה) .על הפונקציה לחשב את ע"י הארכה של טביעות האצבע הנתונות ב- ,בזמן ) O(1עבור כל טביעת אצבע .הפונקציה אינה מחזירה ערך ,אלא מעדכנת את fingers כך שהרשימה תכיל את במקום את .טביעות האצבע מחושבות בבסיס ,basis מודולו ,rכפי שאנחנו מצפים מאלגוריתם .Karp-Rabin עמ' 4מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 שימו לב :כאשר גדל ב ,1 -אורך הרשימה משתנה – הוא קטן ב( 1 -מדוע?). דוגמת הרצה: ]>>> fingers = [0, 0, 0, 0, 0, 0 )>>> extend_fingerprints("hello", fingers, 1 >>> fingers ][104, 101, 108, 108, 111 )>>> extend_fingerprints("hello", fingers, 2 >>> fingers ][26725, 25964, 27756, 27759 )>>> extend_fingerprints("hello", fingers, 3 >>> fingers ][26016, 93342, 27813 סעיף ב של טקסט ממשו את הפונקציה ) .make_hashtable(fingers, table_sizeהפונקציה מקבלת את כלשהו (הטקסט ואורך החלון לא ידועים ואינם חשובים כאן) ומחזירה טבלת hashבגודל ,table_size כאשר תא jבטבלה מכיל את רשימת האינדקסים iשעבורם מתקיים ,fingers[i] == jמסודרים בסדר עולה .לדוגמא: )>>> make_hashtable([0, 0, 1, 2, 1, 2, 1, 2, 3, 3, 3, 0, 0], 4 ]][[0, 1, 11, 12], [2, 4, 6], [3, 5, 7], [8, 9, 10 אנחנו מניחים כאן שהטבלה גדולה מספיק כדי להכיל את טביעת האצבע המקסימלית. סעיף ג מה הסיבוכיות של has_matchכתלות בפרמטרים n2 ,n1ו ,l -שהם בהתאמה האורך של ,text1האורך של ,text2וגודל ה"חלון" הנוכחי? תנו תשובה במונחים של )…( ,Oוהסבירו במשפט או שניים. סעיף ד לתרגיל מצורפים שני קבצי טקסט wonderland.txt, looking_glass.txtהמכילים את תוכן הספרים ”“Alice’s Adventures in Wonderland ”“Through the Looking Glass, and What Alice Found There מאת לואיס קרול .השתמשו בפונקציה ( find_longestהמימוש של פונקציה זו נתון כבר כאמור) ,כדי למצוא את אורכה של תת-מחרוזת משותפת מקסימלית לשני הספרים הללו .כדי להימנע מהבדלים בין הטקסטים שנובעים מסגנון ועריכה נסיר מהטקסט חלק מסימני הפיסוק ורווחים ונהפוך אותיות גדולות לקטנות. השתמשו בפונקציה format_textהמצורפת לקובץ השלד כדי לנקות את הטקסטים ,וכתבו את התשובה הסופית במסמך הטקסט שאתם מגישים .אין לכלול בהגשה את הקוד ששימש אתכם בסעיף זה. עמ' 5מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 שאלה : צופן קיסר הינו שיטת הצפנה עתיקה בה השתמש יוליוס קיסר כדי להעביר בבטחה פקודות למפקדי צבאו. .האלגוריתם מחליף כל אות בטקסט באות אלגוריתם ההצפנה מקבל טקסט txtומפתח שנמצאת kמקומות ימינה ממנה באלפבית .ההזזה היא מעגלית ,כלומר kהאותיות האחרונות באלפבית מוחלפות ב k-האותיות הראשונות .בשרטוט מומחשת ההחלפה שמתבצעת עבור :k=3 … f e d c b a z y x … … i h g f e d c b a … לשם פשטות ,נניח כי ההצפנה משנה אותיות אנגליות קטנות בלבד ( ,)lowercaseוכי כל סימן שאינו כזה נשאר ללא שינוי .למשל ,עבור הטקסט ”! txt = ”attack at onceוהמפתח k=3נקבל.”dwwdfn dw rqfh!” : טקסט מוצפן קרוי .cipherקל יחסית לשבור צופן קיסר (כלומר לגלות את המפתח) ולשחזר את ההודעה המקורית מתוך ה – cipher -שהרי ישנם בסך הכל 26מפתחות אפשריים. בשאלה זו נכתוב קוד לשבירת צופן קיסר .כאשר אדם עובר על 26המפתחות האפשריים ,קל לו לזהות את המפתח הנכון משום שהטקסט שמתגלה מורכב ממילים תקינות באנגלית .עבור מחשב קשה יותר לזהות שהמילים בטקסט הינן מילים תקינות .לכן ננצל תכונה אחרת של הטקסט :כאשר נבחר במפתח הנכון, שכיחויות האותיות בטקסט המפוענח צריכה להיות דומה לשכיחות האותיות בשפה האנגלית. סעיף א כתבו פונקציה ) caesar(txt, kשמחזירה את הטקסט txtלאחר הצפנת קיסר עם מפתח .kנשים לב שע"י בחירה נכונה של kניתן להשתמש בפונק' caesarגם בשביל הפענוח .לדוגמא: )>>> caesar(“attack at once!”, 3 '!'dwwdfn dw rqfh )>>> caesar(caesar(“attack at once!”,3), 23 '!'attack at once סעיף ב כתבו פונקציה ) frequency(txtהמקבלת טקסט txtומחזירה מילון שכיחויות – מילון שבו המפתחות ( )keysהם אותיות האלפבית האנגלי והערכים ( )valuesהם השכיחות (מספר ההופעות היחסי) של האותיות בטקסט .השכיחות של אות שאינה מופיעה בטקסט מוגדרת כ .0-למשל ,עבור הטקסט "!:"attack at once )"!frequency("attack at once >>> {‘a’: 0.25, ‘c’: 0.166, ‘b’: 0.0, ‘e’: 0.0833, ‘d’: 0.0, ‘g’: 0.0, ‘f’: 0.0, ‘i’: 0.0, ‘h’: 0.0, ‘k’: 0.0833, ‘j’: 0.0, ‘m’: 0.0, ‘l’: 0.0, ‘o’: 0.0833, ‘n’: 0.0833, ‘q’: 0.0, ‘p’: 0.0, ‘s’: 0.0, ‘r’: 0.0, }‘u’: 0.0, ‘t’: 0.25, ‘w’: 0.0, ‘v’: 0.0, ‘y’: 0.0, ‘x’: 0.0, ‘z’: 0.0 עמ' 6מתוך 7 CC BY-NC-SA 3.0 אוניברסיטת תל אביב -בית הספר למדעי המחשב מבוא מורחב למדעי המחשב ,אביב 3102 סעיף ג בהינתן שני מילוני שכיחויות ( freq1, freq2כפי שהוגדרו בסעיף ב') המייצגים את השכיחויות בשני טקסטים ,t1, t2נגדיר את המרחק בין המילונים באופן הבא: המרחק שהגדרנו אולי נראה משונה ,אך למעשה מדובר בבחירה די טבעית .נבחן תכונות של המרחק: המדד נותן משקל גדול לאותיות שהשכיחות שלהן שונה מאוד בין שני הטקסטים ,כך שעבור טקסטים שונים מאוד יתקבל מרחק גדול. distance(freq1, freq1)=0 כלומר המרחק של טקסט מעצמו הינו .0 ממשו את הפונקציה ) distance(freq1,freq2שתחזיר את המרחק בין שני מילונים נתונים. סעיף ד בסעיף זה נכתוב פונקציה שתשבור את צופן קיסר באופן אוטומטי .הפונקציה תעשה שימוש ב– corpus- טקסט ארוך יחסית באנגלית ממנו היא תלמד את שכיחויות האותיות בשפה האנגלית .הפונקציה מקבלת טקסט מוצפן (ע"י צופן קיסר) ומנסה לפענח אותו באמצעות כל אחד מ 26 -המפתחות האפשריים. הפונקציה מזהה את המפתח הנכון לפי מילון השכיחויות שלו :כאשר הטקסט מפוענח כהלכה ,שכיחויות האותיות בטקסט דומות לשכיחויות ב( corpus -כלומר המרחק בין השכיחויות בטקסט המפוענח לשכיחויות ב corpus-הינו מינימלי). כתבו פונקציה ) break_caesar(corpus, cipherששוברת את צופן קיסר באופן שתואר למעלה .הפונקציה מקבלת שני טקסטים corpusו cipher -כמחרוזות ,מפענחת את ה cipher -ומחזירה tupleשל שני איברים: האיבר הראשון הוא – kהמפתח עבורו התקבל מרחק מינימלי ,והאיבר השני הוא הטקסט המפוענח. להלן דוגמת הרצה ,שבה הקורפוס הוא הטקסט של Alice's Adventures in Wonderlandמאת Lewis Carrollמתוך פרוייקט גוטנברג : >>> import urllib.request >>> with urllib.request.urlopen("http://www.gutenberg.org/cache/epub/11/pg11.txt") as r: )'corpus = r.read().decode('utf-8 )"!>>> k, text = break_caesar(corpus.lower(),"dwwdfn dw rqfh >>> k, text )'!(23, 'attack at once כדי לבדוק את עצמכם הריצו את הפונקציה ופענחו את הקבצים cipher1.txt, cipher2.txtהמצורפים לתרגיל (השתמשו בקורפוס הנ"ל). שימו לב :לנוחיותכם ,קובץ השלד מכיל ,מלבד כותרות הפונקציות שעליכם לממש ,גם משתנה גלובלי – alphabetמחרוזת של כל האותיות באלפבית האנגלי .השימוש בפונקציות עזר מותר ,כרגיל. בונוס :נק' :מהיכן לקוח כל אחד מהטקסטים cipher1.txtו?cipher2.txt - סוף. עמ' 7מתוך 7 CC BY-NC-SA 3.0
© Copyright 2024