זוהי הפקודה PDL::Indexingp שניתן להריץ בספק האירוח החינמי של OnWorks באמצעות אחת מתחנות העבודה המקוונות המרובות שלנו, כגון Ubuntu Online, Fedora Online, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS
תָכְנִית:
שֵׁם
PDL::Indexing - מבוא לאינדקס ולחיתוך פיצולים.
סקירה כללית
דף אדם זה אמור לשמש מדריך ראשון על תכונות האינדקס והשרשור של
PDL.
כמו כל השפות הווקטוריות, PDL מבצע אוטומציה של לולאה על מערכים באמצעות גרסה של
סימון וקטור מתמטי. הלולאה האוטומטית נקראת "השחלה", בחלקה
כי בסופו של דבר PDL יישם עיבוד מקביל כדי להאיץ את הלולאות.
הרבה מהגמישות והכוח של PDL מסתמכים על תכונות האינדקס והשרשור של
סיומת Perl. אינדקס מאפשר גישה לנתונים של פידל בצורה גמישה מאוד
דֶרֶך. השחלה מספקת וקטוריזציה יעילה של פעולות פשוטות.
הערכים של פידל מאוחסנים בצורה קומפקטית כערכים מוקלדים בבלוק יחיד של זיכרון,
לא (כמו ברשימת רשימות Perl רגילה) כסקלרים בודדים של Perl.
בקטעים שלאחר מכן נקראות "שיטות" רבות -- אלו הם אופרטורים של Perl
להחיל על PDLs. מהמעטפת perldl (או pdl2), אתה יכול לגלות יותר על כל שיטה
על ידי הקלדת "?" ואחריו שם השיטה.
מֵמַד רשימות
פידל (משתנה PDL), באופן כללי, הוא מערך N-ממדי שבו N יכול להיות 0 (עבור
scalar), 1 (למשל עבור דגימת קול), או ערכים גבוהים יותר עבור תמונות ומורכבות יותר
מבנים. לכל מימד של הפידל יש גודל חיובי של מספר שלם. ה"פרל"
המתורגמן מתייחס לכל לולאה כאל סוג מיוחד של סקלאר פרל (חפץ פרל מבורך,
למעשה -- אבל אתה לא צריך לדעת את זה כדי להשתמש בהם) שניתן להשתמש בהם בכל מקום שאתה יכול
לשים סקלר רגיל.
אתה יכול לגשת למידות של פידל כרשימת Perl ולקבוע אחרת את הגודל
של כיור בכמה שיטות. החשובים שבהם הם:
nelem - המספר הכולל של אלמנטים ב-PDL
ndims - מחזירה את מספר הממדים ב-PDL
dims - מחזיר את רשימת הממדים של PDL כרשימת Perl
dim - מחזירה את הגודל של מימד מסוים של PDL
מפתוח ו זרימת נתונים
PDL שומר על רעיון של "זרימת נתונים" בין פיצול לבין שדות משנה שנוספו לאינדקס של זה
בלול. כאשר אתה מייצר שדה משנה מאוגד או אלמנט בודד של פידל אב, ה-
הילד וההורה נשארים מחוברים עד שתנתק אותם באופן ידני. זה מאפשר לך
לייצג את אותם נתונים בדרכים שונות בתוך הקוד שלך -- לדוגמה, אתה יכול לשקול
תמונת RGB בו-זמנית כאוסף של ערכי (R,G,B) בתמונה בגודל 3 x 1000 x 1000,
וכשלושה מישורי צבע נפרדים של 1000 x 1000 המאוחסנים במשתנים שונים. משנה
כל אחד מהמשתנים משנה את הזיכרון הבסיסי, והשינויים באים לידי ביטוי בכל
ייצוגים של הנתונים.
ישנן שתי שיטות חשובות המאפשרות לך לשלוט בחיבורי זרימת נתונים בין ילד
ו-PDL אב:
עותק - כופה עותק מפורש של PDL
sever - מנתק את חיבור זרימת הנתונים בין PDL להוריו (אם יש)
הַשׁחָלָה ו מֵמַד פריטים שנמכרו
רוב פעולות ה-PDL פועלות על פי הממדים הראשונים של טיעוני הפידל שלהם. ל
לדוגמה, "sumover" מסכם את כל האלמנטים לאורך הממד הראשון ברשימה (ממד 0).
אם אתה מאכיל בגלגול תלת מימדי, אז המימד הראשון נחשב ל
ממד "פעיל" והממדים המאוחרים יותר הם ממדי "חוט" כי הם כאלה
פשוט התגלגל. ישנן מספר דרכים להעברה או לסדר מחדש את רשימת הממדים של
PDL. הטכניקות הללו מהירות מאוד מכיוון שהן אינן נוגעות בנתונים הבסיסיים בלבד
לשנות את האופן שבו PDL ניגש לנתונים. פונקציות סדר הממדים העיקריות הן:
mv - מעביר ממד מסוים למקום אחר ברשימת הממדים
xchg - מחליף שני מימדים ברשימת הממדים, ומשאיר את השאר לבד
הזמנה מחדש - מאפשר ערבוב סיטונאי של המידות
clump - מקבץ שני ממדים קטנים או יותר לאחד גדול יותר
לחיצה - מבטל כל ממדים של מידה 1
גוּפָנִי ו דמה מידות
· מסמך השרשור ברמת Perl
· חוטים
· עדכון ותיאור נכון של הפרוסה
· פונקציות חדשות ב-slice.pd (affine, lag, splitdim)
· עיבוד מחדש של פסקה על שרשור מפורש
מפתוח ו השחלה עם PDL
הרבה מהגמישות והכוח של PDL מסתמכים על תכונות האינדקס והלולאה של
סיומת Perl. אינדקס מאפשר גישה לנתונים של אובייקט pdl בצורה גמישה מאוד
דֶרֶך. השחלה מספקת פונקציונליות יעילה של לולאות מרומזות (מאחר שהלולאות הן
מיושם כקוד C מותאם).
אובייקטי Pdl (מאוחר יותר נקראים לעתים קרובות "pdls") הם אובייקטי Perl המייצגים רב-ממדיים
מערכים ופעולות על אלה. בניגוד לסגנון Perl פשוט @x מפרט את נתוני המערך
מאוחסן בצורה קומפקטית בבלוק זיכרון בודד ובכך תופס הרבה פחות זיכרון ו
מאפשר שימוש בקוד C מהיר ליישום פעולות (למשל תוספת וכו') ב-pdls.
pdls יכול יש ילדים
מרכזי ברבות מיכולות האינדקס של PDL הן היחס של "הורה" ו
"ילד" בין pdls. רבות מפקודות האינדקס יוצרות pdl חדש מ-pdl קיים.
ה-pdl החדש הוא ה"ילד" והישן הוא ה"הורה". הנתונים של ה-pdl החדש הם
מוגדר על ידי טרנספורמציה המציינת כיצד ליצור (לחשב) את הנתונים שלו מה-
הנתונים של ההורים. היחס בין ה-Pdl הילד להורה שלו הוא לרוב דו-כיווני,
כלומר, שינויים בנתונים של הילד מופצים בחזרה להורה. (הערה: אתה
תראה, אנחנו מכוונים בטרמינולוגיה שלנו כבר לתכונות החדשות של זרימת הנתונים. הסוג
של זרימת נתונים המשמשת את פקודות האינדקס (עליהן תלמדו תוך דקה)
הוא תמיד בפעולה, לא רק כאשר הפעלת במפורש את זרימת הנתונים ב-pdl שלך
על ידי אמירת "$a->doflow". למידע נוסף על זרימת נתונים בדוק את איש זרימת הנתונים
עמוד.)
דרך נוספת לפרש את ה-pdls שנוצרו על ידי פקודות האינדקס שלנו היא לראות אותם בתור a
סוג של מצביע אינטליגנטי שמצביע אחורה לחלק מהנתונים של ההורה שלו או לכול.
לכן, אין זה מפתיע שהנתונים של ההורה (או חלק מהם) משתנים מתי
מניפולציה דרך ה"מצביע" הזה. לאחר דברי ההקדמה הללו, כי בתקווה
הכינו אותך למה שמגיע (במקום לבלבל אותך יותר מדי) אנחנו הולכים לצלול
היכנס והתחל עם תיאור של פקודות האינדקס וכמה דוגמאות טיפוסיות
כיצד ניתן להשתמש בהם בתוכניות PDL. נמחיש עוד יותר את המצביע/זרימת הנתונים
אנלוגיות בהקשר של כמה מהדוגמאות בהמשך.
ישנם שני יישומים שונים של הקשר ``מצביע חכם'' זה: הראשון
אחד, שהוא קצת יותר איטי אבל עובד עבור כל טרנספורמציה הוא פשוט לעשות את
טרנספורמציה קדימה ואחורה לפי הצורך. השני הוא להתחשב בילד
piddle פידל ``וירטואלי'', שמאחסן רק מצביע להורה ולגישה
מידע כך שרוטינות המשתמשות ב-Piddle של הילד למעשה ניגשות ישירות לנתונים
בהורה. אם הפידל הוירטואלי ניתן לשגרה שאינה יכולה להשתמש בה, PDL
מממש בשקיפות את הפידל הוירטואלי לפני שהוא נותן לשגרה להשתמש בו.
נכון לעכשיו (1.94_01) כל התמורות שהן ``אפיני'', כלומר המדדים של הנתונים
פריט ב-Piddle האב נקבעים על ידי טרנספורמציה ליניארית (+ קבוע) מה-
מדדים של ה-Piddle של הילד מביאים ל-Piddle וירטואליים. כל שאר שגרות האינדקס (למשל
"->אינדקס(...)") מביאים לשיפולים פיזיים. כל השגרות שנערכו על ידי PP יכולות לקבל affine
piddles (פרט לאותם שגרות המעבירות מצביעים לפונקציות ספרייה חיצוניות).
שים לב שהאם משהו מאפיין או לא לא משפיע על הסמנטיקה של מה שאתה עושה
בכל אופן: שניהם
$a->index(...) .= 5;
$a->slice(...) .= 5;
שנה את הנתונים ב-$a. עם זאת, לזיקה יש השפעה משמעותית על הזיכרון
שימוש וביצועים.
פִּלוּחַ pdls
כנראה היישום החשוב ביותר של המושג Pdls הורה/ילד הוא
ייצוג של פרוסות מלבניות של pdl פיזי על ידי pdl וירטואלי. לאחר שדיברתי
מספיק זמן על מושגים בואו נהיה יותר ספציפיים. נניח שאנחנו עובדים עם pdl דו מימדי
מייצג תמונה בגודל 5x5 (היא קטנה בצורה יוצאת דופן כדי שנוכל להדפיס אותה ללא מילוי
מספר מסכים מלאים בספרות ;).
pdl> $im = sequence(5,5)
pdl> p $im
[
[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]
]
pdl> עזרה vars
משתני PDL בחבילה הראשית::
שם סוג מימד מצב זרימה Mem
-------------------------------------------------- --------------
$im כפול D [5,5] P 0.20Kb
[ כאן אולי יהיה מתאים לדבר במהירות על הפקודה "help vars" שמספקת
מידע על pdls במעטפת האינטראקטיבית "perldl" או "pdl2" שמגיעה עם PDL. ]
עכשיו נניח שאנחנו רוצים ליצור PDL 1-D שמתייחס רק לשורה אחת של התמונה, למשל
שורה 2; או pdl שמייצג את כל הקווים הזוגיים של התמונה (תארו לעצמכם שאנחנו צריכים להתמודד עם
פריימים זוגיים ומשונים של תמונה משולבת עקב התנהגות מוזרה של הפריים שלנו
חוטף). כיישום תכוף נוסף של פרוסות אולי נרצה ליצור pdl ש
מייצג אזור מלבני של התמונה כשהחלק העליון והתחתון הפוכים. כל אלה
ניתן להשיג אפקטים (ורבים נוספים) בקלות עם פונקציית הפרוסה החזקה:
pdl> $line = $im->slice(':,(2)')
pdl> $even = $im->slice(':,1:-1:2')
pdl> $area = $im->slice('3:4,3:1')
pdl> help vars # או רק PDL->vars
משתני PDL בחבילה הראשית::
שם סוג מימד מצב זרימה Mem
-------------------------------------------------- --------------
$even Double D [5,2] -C 0.00Kb
$im כפול D [5,5] P 0.20Kb
$line כפול D [5] -C 0.00Kb
$area Double D [2,3] -C 0.00Kb
כל שלושת ה-"ילד" Pdls הם ילדים של $im או באחר (שווה ערך ברובו)
מצביעי פרשנות לנתונים של $im. פעולות בגישה ל-pdls וירטואליים אלה בלבד
אותם חלקים של הנתונים כפי שצוין על ידי הארגומנט לפרוסות. אז אנחנו יכולים פשוט להדפיס
שורה 2:
pdl> p $line
[10 11 12 13 14]
שימו לב גם להבדל ב"מצב הזרימה" של $area מעל ומטה:
pdl> p $area
pdl> עזרה $area
משתנה זה הוא Double D [2,3] VC 0.00Kb
להלן מדגים ש$im ו-$line באמת מתנהגים כפי שהייתם מצפים מא
אובייקט דמוי מצביע (או בתמונת זרימת הנתונים: השינויים בנתונים של $line הם
מופץ בחזרה ל-$im):
pdl> $im++
pdl> p $line
[11 12 13 14 15]
pdl> $line += 2
pdl> p $im
[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[13 14 15 16 17]
[16 17 18 19 20]
[21 22 23 24 25]
]
שים לב כיצד פעולות הקצאה ב-pdl הווירטואלי של הילד משנות את ה-pdl הפיזי של האב
ולהיפך (עם זאת, המקצה הבסיסי "=" לא עושה זאת, השתמש ב-".=" כדי להשיג את האפקט הזה.
ראה להלן את הסיבות). ה-pdls של הילד הווירטואלי הם משהו כמו "קישורים חיים" ל-
הורה "מקורי" pdl. כפי שנאמר בעבר, ניתן לחשוב שהם יעבדו בדומה ל-a
מצביע C. אבל בניגוד ל-C-pointer הם נושאים הרבה יותר מידע. ראשית, הם
ציין את מבנה הנתונים שהם מייצגים (הממדיות של ה-pdl החדש) ו
שנית, ציין כיצד ליצור את המבנה הזה מנתוני ההורים שלו (איך זה עובד
קבור בפנים של PDL וממילא לא חשוב שתדעו (אלא אם כן
רוצה לפרוץ את הליבה בעתיד או רוצה להפוך לגורו של PDL באופן כללי (עבור א
הגדרה של היצור המוזר הזה ראה PDL::Internals)).
הדוגמאות הקודמות הדגימו שימוש טיפוסי בפונקציית הפרוסה. מאז
פונקציונליות החיתוך כל כך חשובה. הנה הסבר על התחביר של המחרוזת
טיעון לחתוך:
$vpdl = $a->slice('ind0,ind1...')
כאשר "ind0" מציין מה לעשות עם אינדקס מס' 0 של ה-pdl $a וכו'. כל רכיב של
רשימה מופרדת בפסיק יכולה להיות אחת מהצורות הבאות:
':' השתמש בכל המימד
'n' השתמש רק באינדקס "n". המימד של אינדקס זה ב-pdl הוירטואלי שנוצר הוא 1.
דוגמה הכוללת את שני הפורמטים הראשונים של האינדקס:
pdl> $column = $im->slice('2,:')
pdl> $row = $im->slice(':,0')
pdl> p $עמודה
[
[3]
[8]
[15]
[18]
[23]
]
pdl> p $row
[
[1 2 3 4 5]
]
pdl> עזרה $column
משתנה זה הוא Double D [1,5] VC 0.00Kb
pdl> עזרה $row
משתנה זה הוא Double D [5,1] VC 0.00Kb
'(n)' השתמש רק באינדקס "n". ממד זה מוסר מה-pdl שנוצר (בהסתמך על
עובדה שתמיד ניתן להסיר ממד בגודל 1). ההבחנה בין זה
המקרה והקודם הופכים חשובים במטלות שבהן יד שמאל וימין
הצד חייב להיות בעל מידות מתאימות.
pdl> $line = $im->slice(':,(0)')
pdl> עזרה $line
משתנה זה הוא Double D [5] -C 0.00Kb
pdl> p $line
[1 2 3 4 5]
מזהים את ההבדל לדוגמא הקודמת?
'n1:n2' or 'n1:n2:n3'
קח את טווח המדדים מ-"n1" ל-"n2" או (צורה שנייה) קח את הטווח של
מדדים מ-"n1" ל-"n2" עם שלב "n3". דוגמה לשימוש בפורמט זה היא
ההגדרה הקודמת של תת-תמונה המורכבת מקווים זוגיים.
pdl> $even = $im->slice(':,1:-1:2')
דוגמה זו גם מדגימה שמדדים שליליים פועלים כמו שהם פועלים כרגיל
מערכים בסגנון Perl על ידי ספירה לאחור מסוף הממד. אם "n2" הוא
קטן מ-"n1" (בדוגמה -1 שווה ערך לאינדקס 4) האלמנטים ב-
pdl וירטואלי מוחזרים למעשה ביחס להורה שלו.
'*[n]'
הוסף מימד דמה. הגודל של ממד זה יהיה 1 כברירת מחדל או שווה ל
"n" אם ניתן הארגומנט המספרי האופציונלי.
עכשיו, זה באמת משהו קצת מוזר ממבט ראשון. מה זה דמה
מֵמַד? ממד דמה מוסיף ממד שבו לא היה אחד קודם. אֵיך
זה נעשה? ובכן, במקרה של המימד החדש בעל מידה 1 זה יכול להיות בקלות
מוסבר בדרך שבה אתה יכול לזהות וקטור (עם אלמנטים "m") עם an
מטריצת "(1,m)" או "(m,1)". הדבר נכון כמובן לגבי אובייקטים בעלי ממדים גבוהים יותר.
מעניין יותר הוא המקרה של דמה בגודל גדול מאחד (למשל
"slice('*5,:')"). זה עובד באותו אופן שבו יוצרת קריאה לפונקציית הדמה
מימד דמה חדש. אז המשך לקרוא ובדוק את ההסבר שלה למטה.
'([n1:n2[:n3]]=i)'
[עדיין לא מיושם ??????] עם טיעון כזה אתה מעלה כללית
אלכסונים. ה אלכסוני יהיה מימד מס. "i" של הפלט pdl החדש ו-(אם
חלק אופציונלי בסוגריים שצוינו) יתרחב לאורך טווח המדדים
שצוין של ממד ה-pdl האב המתאים. בכלל טיעון כזה
הגיוני רק אם יש טיעונים אחרים כמו זה באותה קריאה לפרוס.
החלק בסוגריים הוא אופציונלי עבור סוג זה של ארגומנט. כל הטיעונים של זה
סוג המציין את אותו ממד יעד "i" צריך להתייחס לאותו מספר של
מדדים בממד האב שלהם. הדרך הטובה ביותר להסביר את זה היא כנראה לתת
לדוגמה, כאן אנו יוצרים pdl המתייחס לאלמנטים לאורך אלכסון החלל של
ה-pdl האב שלו (קוביה):
$cube = zeroes(5,5,5);
$sdiag = $cube->slice('(=0),(=0),(=0)');
הפקודה לעיל יוצרת pdl וירטואלי המייצג את האלכסון לאורך
ממד ההורים מס. 0, 1 ו-2 והופך את הממד שלו ל-0 (המימד היחיד) של
זה. אתה משתמש בתחביר המורחב אם גדלי הממדים של ממדי האב מתאימים אותך
רוצה לבנות את האלכסון מבעלי גדלים שונים או שאתה רוצה להפוך את
רצף של אלמנטים באלכסון, למשל
$rect = zeroes(12,3,5,6,2);
$vpdl = $rect->slice('2:7,(0:1=1),(4),(5:4=1),(=1)');
אז האלמנטים של $vpdl יהיו קשורים לאלה של ההורה שלו בצורה שאנחנו יכולים
לבטא כ:
vpdl(i,j) = rect(i+2,j,4,5-j,j) 0<=i<5, 0<=j<2
[ עבודה בפונקציית האינדקס החדשה: "$b = $a->index($c);" ???? ]
שם יש לו אחר סוגים of הקצאות in PDL
הדוגמאות הקודמות כבר הראו שניתן להשתמש ב-pdls וירטואליים כדי לפעול על או
גישה לחלקי נתונים של PDL אב. הם יכולים לשמש גם כערכים במשימות
(כפי שהשימוש ב-"++" בחלק מהדוגמאות לעיל כבר הוכיח). למפורש
הקצאות לנתונים המיוצגים על ידי pdl וירטואלי, עליך להשתמש ב-".=" העמוס יתר על המידה
מפעיל (בהקשר זה אנו קוראים לו מופץ משימה). למה אתה לא יכול להשתמש ב
אופרטור הקצאה רגיל "="?
ובכן, אתה בהחלט עדיין יכול להשתמש באופרטור '=' אבל הוא לא יעשה מה שאתה רוצה. זֶה
זה נובע מהעובדה שלא ניתן להעמיס על האופרטור '=' באותו אופן כמו אחר
מפעילי הקצאות. אם ניסינו להשתמש ב-'=' כדי לנסות להקצות נתונים לחלק של a
pdl פיזי באמצעות pdl וירטואלי לא נשיג את האפקט הרצוי (במקום זאת
משתנה המייצג את ה-pdl הווירטואלי (הפניה לדבר מבורך) היה לאחר ה-
המשימה רק תכיל את ההתייחסות לדבר מבורך אחר שיתנהג אליו
מטלות עתידיות כעותק "פיזי" של ה-rvalue המקורי [זה למעשה עדיין לא
ברור ונושא לדיונים ברשימת התפוצה של מפתחי PDL]. במובן הזה זה
ישבור את החיבור של ה-pdl להורה [האם ההתנהגות הזו במובן מסוים היא לא
ההפך ממה שקורה ב-dataflow, שבו ".=" מנתק את החיבור להורה? ].
לְמָשָׁל
pdl> $line = $im->slice(':,(2)')
pdl> $line = אפסים(5);
pdl> $line++;
pdl> p $im
[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[13 14 15 16 17]
[16 17 18 19 20]
[21 22 23 24 25]
]
pdl> p $line
[1 1 1 1 1]
אבל באמצעות ".="
pdl> $line = $im->slice(':,(2)')
pdl> $line .= אפסים(5)
pdl> $line++
pdl> p $im
[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[ 1 1 1 1 1]
[16 17 18 19 20]
[21 22 23 24 25]
]
pdl> הדפס $line
[1 1 1 1 1]
כמו כן, אתה יכול להחליף
pdl> $line .= 0;
עבור ההקצאה שלמעלה (האפס מומר לגלגול סקלרי, ללא מידות כך
ניתן להקצות אותו לכל כיס).
תכונה נחמדה בגרסאות Perl האחרונות היא תתי שגרות lvalue (כלומר, גרסאות 5.6.x ו-
גבוה יותר כולל כל הפרלים הנתמכים כעת על ידי PDL). זה מאפשר להשתמש ב-
תחביר חיתוך משני צידי המטלה:
pdl> $im->slice(':,(2)') .= אפסים(5)->xvals->צף
קשור לתכונת הקצאת המשנה של lvalue היא מלכודת קטנה לחסרי זהירות: פרלים אחרונים
הציג "תכונה" השוברת את השימוש של PDL בתתי lvalue עבור הקצאות פרוסות כאשר
פועל תחת מאתר הבאגים של perl, "perl -d". תחת ניפוי הבאגים, השימוש לעיל נותן
שגיאה כמו: "לא יכול להחזיר תת-שגרה זמנית מ-lvalue..." אז עליך להשתמש בתחביר
ככה:
pdl> ($pdl = $im->slice(':,(2)')) .= אפסים(5)->xvals->צף
שעובד גם עם ובלי ניפוי הבאגים אבל אפשר לטעון שהוא מגושם ומסורבל לקריאה.
שימו לב שיכולה להיות בעיה עם מטלות כמו זה כאשר lvalue ו-rvalue pdls
עיין בחלקים חופפים של נתונים ב-pdl האב:
# החזר את הרכיבים של השורה הראשונה של $a
($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)');
נכון לעכשיו, נתוני האב בצד ימין של המטלות אינם מועתקים לפני ה-
לולאת הקצאה (פנימית) ממשיכה. לכן, התוצאה של משימה זו תהיה תלויה
על הרצף שבו מוקצים אלמנטים וכמעט בוודאות לֹא תעשה מה שאתה
מבוקש. אז הסמנטיקה היא כרגע לא מוגדר לעת עתה ועלולים להשתנות בכל עת. ל
להשיג את ההתנהגות הרצויה, להשתמש
($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)')->copy;
מה שיוצר עותק פיזי של הפרוסה או
($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)')->sever;
שמחזירה את אותה פרוסה אך מנתקת את הקשר של הפרוסה להורה שלה.
אחר פונקציות זֶה לתפעל ממדים
לאחר שדיברנו בהרחבה על פונקציית הפרוסה יש לציין שזה לא ה-
רק פונקציית אינדקס PDL. ישנן פונקציות נוספות לאינדקס שגם הן שימושיות
(במיוחד בהקשר של שרשור עליו נדבר בהמשך). הנה רשימה
וכמה דוגמאות כיצד להשתמש בהם.
"דֶמֶה"
מוסיף ממד דמה בגודל שאתה מציין (ברירת מחדל 1) במיקום הנבחר.
אתה לא יכול לחכות לשמוע איך זה מושג? ובכן, כל הרכיבים עם האינדקס "(X,x,Y)"
("0<=x
pdl (כאשר "X" ו-"Y" מתייחסים לקבוצת המדדים לפני ואחרי המיקום
היכן הוכנס ממד הדמה.)
דוגמה זו מחשבת את קואורדינטת ה-x של מרכז התמונה (מאוחר יותר נעשה זאת
למד שבעצם לא היינו צריכים את מימד הדמה הודות לקסם המרומז
הַשׁחָלָה; אבל באמצעות ממדי דמה הקוד יעבוד גם בעולם נטול חוטים;
אם כי ברגע שעבדת עם שרשורי PDL לא תרצה לחיות בלעדיהם
שוב).
# מרכז
($xd,$yd) = $im->dims;
$xc = sum($im*xvals(zeroes($xd))->dummy(1,$yd))/sum($im);
בואו נסביר קצת יותר איך זה עובד. ראשית, המוצר:
$xvs = xvals(zeroes($xd));
הדפס $xvs->dummy(1,$yd); # חזור על השורה $yd פעמים
$prod = $im*xvs->dummy(1,$yd); # יוצרים את המוצר לפיקסלים עם
# השורה החוזרת על עצמה של ערכי x
השאר הוא אז סיכום התוצאות של המוצר מבחינת הפיקסלים ביחד ו
מנרמל עם סכום כל ערכי הפיקסלים בתמונה המקורית ובכך מחושב
קואורדינטת ה-x של "מרכז המסה" של התמונה (לפרש ערכי פיקסלים כ
מסה מקומית) המכונה המרכז של תמונה.
הבא הוא (מנקודת מבט של צריכת זיכרון) המרה זולה מאוד מ
בקנה מידה אפור ל-RGB, כלומר כל פיקסל מכיל כעת משולש של ערכים במקום סקלאר.
שלושת הערכים בטריפל הם, למרבה המזל, כולם זהים עבור תמונה אפורה, אז
שהטריק שלנו עובד טוב בכך שהוא ממפה את כל שלושת החברים של המשולש ל-
אותו אלמנט מקור:
# המרה זולה בקנה מידה אפור ל-RGB
$rgb = $grey->dummy(0,3)
למרבה הצער, לא ניתן להשתמש בטריק הזה כדי להמיר את התמונות הישנות שלך בשחור לבן לתמונות צבעוניות
בצורה שתרצה. :(
שים לב ששימוש בזיכרון של פידלים עם ממדי דמה רגיש במיוחד
הייצוג הפנימי. אם ניתן לייצג את הפידל כאפיין וירטואלי
(``vaffine'') פידל, רק מבני הבקרה מאוחסנים. אבל אם $b פנימה
$a = אפסים(10000);
$b = $a->dummy(1,10000);
נעשה פיזי על ידי שגרה כלשהי, תגלה שהשימוש בזיכרון של התוכנית שלך
גדל פתאום ב-100Mb.
"אֲלַכסוֹנִי"
מחליף שני ממדים (שצריכים להיות בגודל שווה) בממד אחד
מתייחס לכל האלמנטים לאורך ה"אלכסון" לאורך שני הממדים הללו. הנה אנחנו
יש שתי דוגמאות שצריכות להיראות מוכרות לכל מי שאי פעם עשה קצת ליניארי
אַלגֶבּרָה. ראשית, צור מטריצת אחדות:
# מטריצת אחדות
$e = zeroes(float, 3, 3); # להפוך הכל לאפס
($tmp = $e->diagonal(0,1)) .= 1; # הגדר את האלמנטים לאורך האלכסון ל-1
הדפס $e;
או האלכסון השני:
($tmp = $e->slice(':-1:0')->diagonal(0,1)) .= 2;
הדפס $e;
(האם שמתם לב איך השתמשנו בפונקציית הפרוסה כדי להחזיר את רצף השורות לפני כן
הגדרת האלכסון של הילד החדש, ובכך להגדיר את האלכסון הצלב של ה
הורה?) או מיפוי ממרחב המטריצות האלכסוניות לשדה שמעליו
המטריצות מוגדרות, עקבות של מטריצה:
# עקבות של מטריצה
$trace = sum($mat->diagonal(0,1)); # לסכם את כל האלמנטים האלכסוניים
"xchg" ו-"mv"
xchg מחליף או "מעביר" את שני הממדים שצוינו. ישר
דוּגמָה:
# העברה של מטריצה (ללא ערבוב מפורש של נתונים ו
# יצירת עותק)
$prod = $ax $a->xchg(0,1);
$prod אמור להיות די קרוב למטריצת האחדות אם $a היא מטריצה אורתוגונלית.
לעתים קרובות "xchg" ישמש בהקשר של שרשור אבל עוד על כך בהמשך.
mv עובד בצורה דומה. הוא מזיז ממד (מצוין על ידי מספרו ב-
הורה) לתפקיד חדש ב-pdl הילד החדש:
$b = $a->mv(4,0); # הפוך את הממד החמישי של $a לראשון ב-
# ילד חדש $b
ההבדל בין "xchg" ל-"mv" הוא ש-"xchg" משנה רק את המיקום של שניים
ממדים אחד עם השני, בעוד "mv" מכניס את הממד הראשון למקום של
שנית, הזזת הממדים האחרים בהתאם.
"סְבַך"
ממוטט כמה ממדים לאחד. הטיעון היחיד שלו מציין כמה ממדים
של ה-pdl של המקור צריך להיות ממוטט (החל מהראשון). (יש להודות
דוגמה לא מציאותית היא 3D pdl שמחזיק נתונים מערימה של קבצי תמונה שאתה
זה עתה קראתי. עם זאת, הנתונים מכל תמונה באמת מייצגים זמן 1D
סדרה וסודרה כך רק בגלל שהיא עברה דיגיטציה עם מסגרת
חוטף. אז לקבל את זה שוב בתור מערך של רצפי זמן אתה אומר
pdl> $seqs = $stack->סְבַך(2)
pdl> עזרה vars
משתני PDL בחבילה הראשית::
שם סוג מימד מצב זרימה Mem
-------------------------------------------------- --------------
$seqs Double D [8000,50] -C 0.00Kb
$stack Double D [100,80,50] P 3.05Mb
ככל שזה נראה לא מציאותי, תוכנת המיקרוסקופ הקונפוקאלי שלנו כותבת נתונים (לפעמים)
בדרך זו. אבל לעתים קרובות יותר אתה משתמש בגוש כדי להשיג אפקט מסוים בעת שימוש במרומז
או שרשור מפורש.
שיחות ל מפתוח פונקציות יכול be כבול
כפי שאולי שמתם לב בחלק מהדוגמאות לעיל קריאות לפונקציות האינדקס
ניתן לשרשר בצורה יפה מכיוון שכל הפונקציות הללו מחזירות אובייקט צאצא חדש שנוצר.
עם זאת, בעת ביצוע מניפולציות אינדקס נרחבות בשרשרת הקפידו לעקוב אחר מה
אתה עושה, למשל
$a->xchg(0,1)->mv(0,4)
מעביר את הממד 1 של $a למיקום 4 מאז ביצוע הפקודה השנייה
ממד מקורי 1 הועבר למיקום 0 של הילד החדש שקורא ל-"mv"
פוּנקצִיָה. אני חושב שהבנתם את הרעיון (למרות ההסברים המפותלים שלי).
מופץ הקצאות ('.=') ו דמה ממדים
משנה הקשורה לאינדקס היא ההקצאה ל-pdls המכילה מידות דמה של
גודל גדול מ-1. הקצאות אלו (באמצעות ".=") אסורות מכיוון שמספר אלמנטים
של lvalue pdl מצביעים על אותו אלמנט של האב. כתוצאה מכך הערך של
רכיבי האב הללו עשויים להיות מעורפלים ותלויים ברצף שבו
היישום עושה את ההקצאות לאלמנטים. לכן, משימה כמו זו:
$a = pdl [1,2,3];
$b = $a->dummy(1,4);
$b .= yvals(zeroes(3,4));
יכול לייצר תוצאות בלתי צפויות והתוצאות הן במפורש לא מוגדר על ידי PDL כי
כאשר PDL מקבל תכונות מחשוב מקבילות, התוצאה הנוכחית עשויה להשתנות.
מנקודת המבט של זרימת הנתונים, הכנסת דמה בגודל גדול מאחד
מימדים נחשבים כטרנספורמציה בלתי הפיכה (בדומה למינוח ב
תרמודינמיקה) אשר מונעת הפצה לאחור של הקצאה להורה (שאתה אתה
ביקש במפורש באמצעות המטלה ".="). בעיה דומה שכדאי להיזהר ממנה
מתרחש בהקשר של שרשור שבו לפעמים נוצרים מידות דמה באופן מרומז
במהלך לולאת החוט (ראה להלן).
סיבות ל מה היא הורה / ילד (אוֹ "מַצבִּיעַ") מושג
[זה יצטרך לחכות קצת]
XXXXXX יעיל בזיכרון
XXXXX בהקשר של שרשור
XXXXX דרך גמישה וחזקה מאוד לגשת לחלקים מנתוני pdl
(בצורה הרבה יותר כללית ממה שמאפשרים שניות וכו')
XXXXX יישום יעיל
הבדל XXXXXX למדור/ב וכו'.
איך ל לעשות דברים גופני שוב
[XXXXX מלא מאוחר יותר כשהכל יסתדר קצת יותר]
** בעת הצורך (שגרת xsub מתממשקת לפונקציית C lib)
** איך הושג (->פיזי)
** איך לבדוק (הוא פיזי (הסבר איך זה עובד כרגע))
** ->העתק ו->נתק
הַשׁחָלָה
בפסקה הקודמת בנושא אינדקס כבר הזכרנו את המונח מדי פעם אבל
עכשיו באמת הגיע הזמן לדבר במפורש על "שרשור" עם pdls. למונח שרשור יש
משמעויות רבות ושונות בתחומי מחשוב שונים. במסגרת PDL זה
אפשר כנראה להגדיר באופן רופף כמתקן לולאה מרומז. זה מרומז כי
אתה לא מציין שום דבר כמו הקיפת for-loops אלא הלולאות הן אוטומטיות
(או 'באופן קסם') שנוצר על ידי PDL בהתבסס על הממדים של ה-pdls המעורבים. זֶה
צריך לתת לך מושג ראשון למה הפונקציות המשפיעות על האינדקס/מימד שפגשת
בפסקאות הקודמות חשובות ושימושיות במיוחד בהקשר של
הַשׁחָלָה. המרכיב הנוסף להשחלה (מלבד ה-pdls המעורבים) הוא א
פונקציה שמודעת לשרשור (בדרך כלל, אלו הן פונקציות הידור PDL::PP) ו
שהpdls "מושחלים" מעל. כל כך הרבה על הטרמינולוגיה ועכשיו בואו ננסה
לשפוך קצת אור על המשמעות של כל זה.
משתמע השחלה - a ראשון דוגמה
ישנן שתי גרסאות שונות במקצת של השחלה. אנחנו מתחילים עם מה שאנחנו קוראים לו
"שרשור מרומז". בואו נבחר דוגמה מעשית הכוללת לולאה של פונקציה
על אלמנטים רבים של pdl. נניח שיש לנו תמונת RGB שברצוננו להמיר לאפור-
סוּלָם. תמונת RGB מיוצגת על ידי pdl בעל 3 עמעום "im(3,x,y)" שבו הממד הראשון
מכיל את שלושת מרכיבי הצבע של כל פיקסל ו-"x" ו-"y" הם רוחב וגובה של
התמונה, בהתאמה. לאחר מכן עלינו לציין כיצד להמיר משולש צבע בנתון
פיקסל לערך אפור (כדי להיות דוגמה מציאותית הוא צריך לייצג את היחס
העוצמה שבה תאי העין חסרי הצבע שלנו יזהו את הצבע הזה כדי להשיג
מה שהיינו מכנים המרה טבעית מצבע לקנה מידה אפור). קירוב לכך
עובד די טוב הוא לחשב את עוצמת האפור מכל שלישיית RGB (r,g,b) בתור a
סכום משוקלל
ערך אפור = 77/256*r + 150/256*g + 29/256*b =
inner([77,150,29]/256, [r,g,b])
כאשר הצורה האחרונה מציינת שאנו יכולים לכתוב זאת כמכפלה פנימית של וקטור 3
הכולל את המשקולות עבור רכיבים אדומים, ירוקים וכחולים כאשר ה-3 וקטור מכיל את
רכיבי צבע. באופן מסורתי, ייתכן שכתבנו פונקציה כמו הבאה
לעבד את כל התמונה:
my @dims=$im->dims;
# כאן בדוק בדרך כלל שלמעום הראשון יש גודל נכון (3), וכו'
$grey=zeroes(@dims[1,2]); # צור את ה-pdl עבור התמונה האפורה שהתקבלה
$w = pdl [77,150,29] / 256; # וקטור המשקולות
עבור ($j=0;$j
עבור ($i=0;$i
# חשב את ערך הפיקסלים
$tmp = inner($w,$im->slice(':,(i),(j)'));
set($grey,$i,$j,$tmp); # והגדר אותו בתמונה בקנה מידה אפור
}
}
כעת אנו כותבים את אותו הדבר באמצעות השרשור (לשים לב ש"פנימי" היא פונקציה מודעת לשרשור
מוגדר בחבילת PDL::Primitive)
$grey = inner($im,pdl([77,150,29]/256));
סיימנו עם one-liner שיוצר אוטומטית את pdl $grey עם ימין
מספר וגודל של מידות ומבצע את הלולאות באופן אוטומטי (לולאות אלו הן
מיושם כקוד C מהיר בחלק הפנימי של PDL). ובכן, אנחנו עדיין חייבים לך
הסבר כיצד ה'קסם' הזה מושג.
איך עושה מה היא דוגמה לעבוד ?
הדבר הראשון שיש לציין הוא שכל פונקציה שמודעת לשרשור (אלה בלי
פונקציות חריגות שהורכבו מתיאורים תמציתיים על ידי PDL::PP, שנקראו מאוחר יותר רק PP-
functions) מצפה למספר מוגדר (מינימלי) של ממדים (אנו קוראים להם ממדי ליבה)
מכל ארגומנט ה-pdl שלו. הפונקציה הפנימית מצפה לדו-מימדי (קלט)
פרמטרים שמהם הוא מחשב פרמטר אפס ממדי (פלט). אנחנו כותבים את זה
באופן סמלי כ"פנימי((n),(n),[o]())" וקראו לזה "פנימי" חֲתִימָה, כאשר n מייצג
הגודל של הממד הזה. n להיות שווה בפרמטר הראשון והשני אומר ש
מידות אלו חייבות להיות בגודל שווה בכל שיחה. כדוגמה אחרת קח את
מוצר חיצוני שלוקח שני וקטורים דו-ממדיים כדי ליצור מטריצה דו-ממדית, הכתובה באופן סמלי כ
"חיצוני((n),(מ),[o](n,m))". ה-"[o]" בשתי הדוגמאות מציין שזה (כאן השלישי)
ארגומנט הוא ארגומנט פלט. בדוגמה האחרונה הממדים של ראשון ושני
הטיעון לא חייב להסכים אבל אתה רואה איך הם קובעים את הגודל של שני הממדים
של הפלט pdl.
הנה הנקודה שבה השרשור סוף סוף נכנס למשחק. אם אתה קורא ל-PP-פונקציות עם
pdls שיש להם יותר ממידות הליבה הנדרשות הממדים הראשונים של ה-pdl
ארגומנטים משמשים כממדי הליבה והממדים הנוספים מושחלים
על. הבה נדגים זאת תחילה עם הדוגמה שלנו למעלה
$grey = inner($im,$w); # w הוא וקטור המשקל מלמעלה
במקרה זה $w הוא 1D ולכן סיפק רק את ממד הליבה, $im הוא 3D, יותר
במיוחד "(3,x,y)". הממד הראשון (בגודל 3) הוא מימד הליבה הנדרש
התואם (כפי שנדרש על ידי פנימי) לממד הראשון (והיחיד) של $w. השני
ממד הוא ממד החוט הראשון (בגודל "x") והשלישי הוא כאן השני
ממד חוט (בגודל "y"). הפלט pdl נוצר באופן אוטומטי (כפי שמתבקש על ידי
הגדרה של $grey ל-"null" לפני ההפעלה). מידות הפלט מתקבלות על ידי
הוספת ה לולאה ממדים (כאן "(x,y)") לממדי פלט הליבה (כאן 0D) ל
תניב את הממדים הסופיים של ה-pdl שנוצר אוטומטית (כאן "0D+2D=2D" כדי להניב פלט דו-ממדי
בגודל "(x,y)").
אז הפקודה לעיל קוראת לפונקציונליות הליבה שמחשבת את המכפלה הפנימית של שניים
וקטורים 1D "x*y" פעמים עם $w וכל הפרוסות 1D בצורה "(':,(i),(j)')" של $im ו
מגדיר את הרכיבים המתאימים של הפלט pdl "$grey(i,j)" לתוצאה של כל
חישוב. נוכל לכתוב את זה באופן סמלי כמו
$grey(0,0) = f($w,$im(:,(0),(0)))
$grey(1,0) = f($w,$im(:,(1),(0)))
.
.
.
$grey(x-2,y-1) = f($w,$im(:,(x-2),(y-1)))
$grey(x-1,y-1) = f($w,$im(:,(x-1),(y-1)))
אבל זה נעשה באופן אוטומטי על ידי PDL מבלי לכתוב לולאות Perl מפורשות. אנחנו מבינים
שהפקודה באמת יוצרת פלט pdl עם הממדים הנכונים ומגדירה את
אלמנטים אכן לתוצאה של החישוב עבור כל פיקסל של תמונת הקלט.
כאשר מעורבים אפילו יותר PDL וממדים נוספים, הדברים מסתבכים קצת יותר.
תחילה ניתן את הכללים הכלליים כיצד מידות החוט תלויות במידות של
קלט pdls המאפשר לך להבין את הממדיות של PDL פלט שנוצר אוטומטית
(עבור כל קבוצה נתונה של קלט pdls וממדי ליבה של פונקציית PP המדוברת). ה
סביר להניח שהכללים הכלליים ייראו קצת מבלבלים ממבט ראשון, כך שנצא לדרך
כדי להמחיש את השימוש עם קבוצה של דוגמאות נוספות (שתקווה שגם
להוכיח שאכן ישנם מצבים מעשיים רבים שבהם השרשור מגיע
שימושי ביותר).
A שיחה ל קידוד משמעת
לפני שנצביע על הפרטים הטכניים האחרים של השרשור, אנא שים לב לקריאה זו
משמעת תכנות בעת שימוש בהשרשור:
על מנת לשמור על קריאות האדם, אנא הערה על כל ביטוי לא טריוויאלי שלך
קוד הכולל שרשור. והכי חשוב, עבור כל תת שגרה, כלול מידע ב-
ההתחלה לגבי מה שאתה מצפה שהמימדים ייצגו (או טווחי ממדים).
כאזהרה, הסתכל על הפונקציה הלא מתועדת הזו ונסה לנחש מה עלול לקרות:
חיפוש משנה {
שלי ($im,$palet) = @_;
שלי $res;
index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=null));
החזר $res;
}
האם תסכים שאולי יהיה קשה להבין את הממדים הצפויים, המטרה של
השגרה וכו'? (אם אתה רוצה לגלות מה קטע הקוד הזה עושה, ראה למטה)
איך ל להבין הַחוּצָה מה היא לולאה ממדים
ישנם כמה כללים המאפשרים לך להבין את מספר וגודל הלולאה
מידות (ואם גודל ה-pdls הקלט שלך תואם את כללי השרשור).
מימדים של כל ארגומנט pdl מחולקים לשתי קבוצות הבאות: Core
מידות (כפי שהוגדרו על ידי פונקציית PP, ראה נספח B לרשימת פרימיטיביים של PDL)
ומידות נוספות הכוללות את כל המידות הנותרות של אותו pdl. לדוגמה
קריאה לפונקציה "func" עם החתימה "func((n,m),[o](n))" עם pdl
"a(2,4,7,1,3)" בתור "f($a,($o = null))" מביא לפיצול סמנטי של הממדים של a
לתוך: מידות ליבה "(2,4)" ומידות נוספות "(7,1,3)".
מידות ליבה R0 מזוהות עם מידות ה-N הראשונות של ה-pdl בהתאמה
טיעון (ונדרשים). כל מימד נוסף הוא מימד נוסף ורגיל
לקבוע את מידות הלולאה.
R1 מספר ממדי הלולאה (מרומזים) שווה למספר המרבי של תוספת
ממדים השתלטו על סט הארגומנטים של pdl.
R2 הגודל של כל אחת ממידות הלולאה נגזר מהגודל של ההתאמה
מידות של הארגומנטים pdl. הגודל של ממד לולאה ניתן על ידי ה-
גודל מקסימלי שנמצא בכל אחד מה-pdls בעלי הממד הנוסף הזה.
R3 עבור כל pdls שיש להם מימד נוסף נתון הגודל חייב להיות שווה לגודל של
ממד הלולאה (כפי שנקבע על ידי הכלל הקודם) או 1; אחרת אתה מעלה א
חריגת זמן ריצה. אם הגודל של המימד הנוסף ב-pdl הוא כזה
מטופל באופן מרומז כממד דמה של גודל השווה לאותה גודל עמום של הלולאה כאשר
ביצוע לולאת החוט.
R4 אם ל-pdl אין ממד לולאה, בלולאת החוט מתייחסים ל-pdl הזה כאילו
בעל ממד דמה בגודל השווה לגודל הממד של הלולאה.
R5 אם נעשה שימוש ביצירה אוטומטית של פלט (על ידי הגדרת ה-pdl הרלוונטי ל-"PDL->null" לפני
invocation) מספר הממדים של ה-pdl שנוצר שווה לסכום ה-
מספר מידות פלט הליבה + מספר מידות לולאה. גודל הליבה
מידות הפלט נגזרות מהממד הרלוונטי של קלט pdls (כפי שצוין
בהגדרת הפונקציה) והגדלים של הממדים האחרים שווים ל-
גודל ממד הלולאה ממנו הוא נגזר. ה-pdl שנוצר באופן אוטומטי יהיה
פיזי (אלא אם זרימת הנתונים פועלת).
בהקשר זה, שים לב שאתה יכול להיתקל בבעיה בהקצאה ל-pdls המכיל
מידות דמה גדולות מאחת (ראה לעיל). למרות שה-pdl(s) הפלט שלך לא הכילו
כל ממדי דמה מלכתחילה הם עלולים להסתיים עם דמה שנוצרה באופן מרומז
מידות לפי R4.
כדוגמה, נניח שיש לנו פונקציית PP (לא מפורטת כאן) עם החתימה:
func((m,n),(m,n,o),(m),[o](m,o))
ואתה קורא לזה עם 3 pdls "a(5,3,10,11)", "b(5,3,2,10,1,12)", ו-"c(5,1,11,12)" כפי ש
func($a,$b,$c,($d=null))
אז מספר מידות הלולאה הוא 3 (על ידי "R0+R1" מ-$b ו-$c) עם גדלים
"(10,11,12)" (על ידי R2); שני ממדי ליבת הפלט הם "(5,2)" (מהחתימה של
func) וכתוצאה מכך פלט 5 מימדי pdl $c בגודל "(5,2,10,11,12)" (ראה R5) ו
(הנוצר באופן אוטומטי) $d נגזר מ-"($a,$b,$c)" באופן שניתן לבטא
ב-pdl פסאודו-קוד as
$d(:,:,i,j,k) .= func($a(:,:,i,j),$b(:,:,:,i,0,k),$c(:, 0,j,k))
עם 0<=i<10, 0<=j<=11, 0<=k<12
אם ננתח שוב את ההמרה של צבע לקנה מידה אפור תוך מחשבה על הכללים האלה, נציין
יתרון גדול נוסף של שרשור מרומז. אנחנו יכולים לקרוא להמרה עם pdl
מייצג פיקסל (im(3)), שורה של פיקסלים rgb ("im(3,x)"), תמונת צבע נכונה
("im(3,x,y)") או ערימה שלמה של תמונות RGB ("im(3,x,y,z)"). כל עוד $im הוא של
טופס "(3,...)" הפלט pdl שנוצר אוטומטית יכיל את המספר הנכון של
ממדים ומכילים את נתוני העוצמה כפי שאנו מצפים להם מאז שהלולאות היו
מבוצע באופן מרומז בזכות משתמע השחלה. אתה יכול בקלות לשכנע את עצמך את זה
קורא עם פיקסל צבע $grey הוא 0D, עם קו זה יוצא אפור 1D(x), עם תמונה
נקבל "grey(x,y)" ולבסוף נקבל ערימת תמונות שהומרת "grey(x,y,z)".
הבה נמלא את הכללים הכלליים האלה בקצת חיים נוספים על ידי מעבר של כמה דברים נוספים
דוגמאות. הקורא עשוי לנסות למצוא ניסוחים מקבילים עם הסבר מפורש-
לולאה והשווה את הגמישות של אותן שגרות באמצעות השרשור מרומז ל-
ניסוח מפורש. יתר על כן, במיוחד כאשר משתמשים במספר ממדי חוט זה א
תרגיל שימושי כדי לבדוק את המהירות היחסית על ידי ביצוע כמה מבחני אמת מידה (שאנחנו עדיין
חייב לעשות).
ראשון בשורה היא דוגמה מעובדת מרוכזת מעט, כעת מקודדת עם השחלה פנימה
אכפת.
# mult מושחל לחישוב קואורדי מרכז, עובד גם עבור ערימות
$xc = sumover(($im*xvals(($im->dims)[0]))->סְבַך(2)) /
sumover($im->סְבַך(2));
בואו ננתח מה קורה צעד אחר צעד. ראשית המוצר:
$prod = $im*xvals(zeroes(($im->dims)[0]))
זה למעשה יעבוד עבור $im בהיותו חד, שני, תלת ממדי ומעלה. אם $im הוא
חד מימדי זה רק מוצר רגיל (במובן שכל אלמנט של $im הוא
מוכפל עם הרכיב המתאים של "xvals(...)"), אם ל-$im יש יותר ממדים
השחלה נוספת מתבצעת על ידי הוספת מידות דמה מתאימות ל-"xvals(...)"
לפי R4. חשוב מכך, שתי פעולות הסיכום מציגות דוגמה ראשונה כיצד
לעשות שימוש בפקודות המניפולציות של המימד. מבט מהיר על החתימה של סומובר
יזכיר לך שזה רק "יזלול" את הממד הראשון של קלט pdl נתון.
אבל מה אם נרצה באמת לחשב את הסכום על כל האלמנטים של שני הראשונים
ממדים? ובכן, שום דבר לא מונע מאיתנו להעביר pdl וירטואלי לתוך sumover אשר בזה
המקרה נוצר על ידי חיבור שני הממדים הראשונים של ה-"pdl האב" לאחד. מ ה
נקודת המבט של ה-pdl האב הסכום מחושב כעת על פני שני המימדים הראשונים,
בדיוק כמו שרצינו, אם כי sumover בדיוק ביצעה את העבודה כפי שצוין בחתימה שלו. יש
זה ?
עוד עדינות קטנה בכתיבת הקוד ככה: השתמשנו בכוונה
"sumover($pdl->סְבַך(2))" במקום "sum($pdl)", כך שנוכל להעביר רק תמונה
"(x,y)" או ערימת תמונות "(x,y,t)" לתוך השגרה הזו וקבל רק אחת
קואורדינטה x או וקטור של קואורדינטות x (בגודל t) בתמורה.
קבוצה נוספת של פעולות נפוצות הן מה שאפשר לכנות "פעולות השלכה". אלה
פעולות לוקחות ND pdl כקלט ומחזירות (N-1)-D pdl "מוקרן". פעולות אלו
מבוצעים לעתים קרובות עם פונקציות כמו sumover, prodover, מינימום ומקסימום. באמצעות
שוב תמונות כדוגמאות אולי נרצה לחשב את ערך הפיקסלים המרבי עבור כל שורה
של תמונה או ערימת תמונה. אנחנו יודעים איך לעשות את זה
# מקסימום של שורות (כפונקציה של מספר קו וזמן)
maximum($stack,($ret=null));
אבל מה אם אתה רוצה לחשב מקסימום לכל עמודה כאשר שרשור מרומז תמיד חל
פונקציונליות הליבה של הממד הראשון והחוטים על כל האחרים? איך אנחנו יכולים
להשיג שבמקום זאת פונקציונליות הליבה מיושמת על הממד השני ו
השחלה מתבצעת על פני האחרים. האם אתה יכול לנחש? כן, אנחנו יוצרים PDL וירטואלי שיש לו
הממד השני של ה-"pdl האב" כממד הראשון שלו באמצעות הפקודה "mv".
# מקסימום של עמודות (כפונקציה של מספר העמודה והזמן)
maximum($stack->mv(1,0),($ret=null));
וחישוב כל הסכומים של תת-פרוסות על פני הממד השלישי הוא כעת כמעט קל מדי
# סכומי פיקסלים בזמן (בהנחה שהזמן הוא העמעום השלישי)
sumover($stack->mv(2,0),($ret=null));
לבסוף, אם אתה רוצה להחיל את הפעולה על כל האלמנטים (כמו מקסימום על כל האלמנטים או
סכום על כל האלמנטים) ללא קשר לממדים של ה-pdl המדובר בא "גוש".
שימושי. כדוגמה, תסתכל על ההגדרה של "סכום" (כמוגדר ב-"Ufunc.pm"):
סכום משנה {
PDL::Ufunc::sumover($name->clump(-1),($tmp=null));
החזר $tmp->at(); # החזר מספר Perl, לא 0D pdl
}
כבר הזכרנו שכל הפעולות הבסיסיות תומכות בהשרשור והקצאה היא לא
יוצא מן הכלל. אז הנה כמה משימות שרשור
pdl> $im = zeroes(byte, 10,20)
pdl> $line = exp(-rvals(10)**2/9)
# מטלת שרשור
pdl> $im .= $line # הגדר כל שורה של $im ל-$line
pdl> $im2 .= 5 # הגדר כל רכיב של $im2 ל-5
עד עכשיו אתה בטח רואה איך זה עובד ומה זה עושה, לא?
כדי לסיים את הדוגמאות בפסקה זו הנה פונקציה ליצור ממנה תמונת RGB
מה שנקרא תמונת פלטה. תמונת הפלטה מורכבת משני חלקים: תמונה של
מדדים לטבלת חיפוש צבעים ולטבלת בדיקת הצבע עצמה. [תאר איך זה
עובד ] אנחנו הולכים להשתמש בפונקציית PP שעדיין לא נתקלנו בקוד הקודם
דוגמאות. זוהי פונקציית האינדקס בעלת השם המתאים, החתימה "((n),(),[o]())" (ראה נספח
B) עם פונקציונליות הליבה ש"index(pdl (0,2,4,5),2,($ret=null))" יחזיר את
אלמנט עם אינדקס 2 של הקלט הראשון pdl. במקרה זה, $ret יכיל את הערך 4.
אז הנה הדוגמה:
# חיפוש אינדקס משורשר ליצירת תמונת RGB, או RGBA או YMCK
# מתמונת פלטה (מיוצגת על ידי טבלת חיפוש $palette ו
# תמונת אינדקס צבע $im)
# אתה יכול להגיד סתם דמה(0) מכיוון שכללי השחלה גורמים לזה להתאים
pdl> index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=null));
בואו נעבור על זה ונסביר את השלבים הכרוכים בכך. בהנחה שאנו עוסקים ב-RGB
ה-lookup-table $palet הוא בגודל "(3,x)". ראשית אנו מחליפים את מידות הפלטה
כך שהלולאה מתבצעת על הממד הראשון של $palet (בגודל 3 שמייצג את r,
רכיבי g, ו-b). כעת מסתכלים על $im, אנו מוסיפים ממד דמה בגודל השווה ל-
אורך מספר הרכיבים (במקרה שאנו דנים כאן יכולנו להיות רק
השתמש במספר 3 מכיוון שיש לנו 3 רכיבי צבע). אנחנו יכולים להשתמש במימד דמה מאז
עבור רכיבי צבע אדום, ירוק וכחול אנו משתמשים באותו אינדקס מהתמונה המקורית,
למשל בהנחה שלפיקסל מסוים של $im היה הערך 4 אז הבדיקה אמורה לייצר את
משולש
[palet(0,4),palette(1,4),palet(2,4)]
עבור הרכיבים האדומים, הירוקים והכחולים החדשים של תמונת הפלט. מקווה שעד עכשיו יש לך
איזשהו רעיון מה חתיכת הקוד שלמעלה אמורה לעשות (לעיתים קרובות זה באמת
די מסובך לתאר בפירוט כיצד עובדת קוד השרשור; פשוט קדימה
ולהתנסות קצת כדי לקבל תחושה טובה יותר לגבי זה).
אם קראת בעיון את כללי השרשור, אולי שמת לב שלא
יש לציין במפורש את גודל ממד הדמה שיצרנו עבור $im; כאשר אנו
צור אותו בגודל 1 (ברירת המחדל) כללי ההברגה גורמים לו להתאים אוטומטית
הגודל הרצוי (לפי כלל R3, בדוגמה שלנו הגודל יהיה 3 בהנחה של פלטה של
גודל "(3,x)"). מכיוון שמצבים כאלה אכן מתרחשים לעתים קרובות בפועל זו למעשה הסיבה
כלל R3 הוכנס (החלק שגורם למידות של מידה 1 להתאים לחוט
גודל עמום של לולאה). אז אנחנו יכולים פשוט לומר
pdl> index($palette->xchg(0,1),$im->long->דמה(0),($res=null));
שוב, אתה יכול לשכנע את עצמך שהשגרה הזו תיצור את הפלט הנכון אם תקרא
עם פיקסל ($im הוא 0D), קו ($im הוא 1D), תמונה ($im הוא 2D), ..., בדיקת RGB
טבלה (הלוח היא "(3,x)") וטבלת חיפוש RGBA (הלוח היא "(4,x)", ראה למשל OpenGL).
גמישות זו מושגת על ידי כללי השחלה שנועדו לעשות את הנכון
דבר ברוב המצבים.
כדי לסכם את הכל שוב, הרעיון הכללי הוא כדלקמן. אם אתה רוצה להשיג
לולאה על ממדים מסוימים ויש להם את הליבה פונקציונלי מוחל על אחר
קבוצת ממדים שצוינה אתה משתמש בפקודות מניפולציה של מימדים כדי ליצור (או
כַּמָה) וירטואלי pdl(s) כך שמנקודת המבט של ה הורה pdl(s) אתה מבין מה
אתה רוצה (תמיד עם החתימה של הפונקציה המדוברת ו-R1-R5 בראש!).
קל, לא?
תְפוּקָה יצירה אוטומטית ו פונקציית PP קוראים אמנות
בשלב זה עלינו להסיט לפרט טכני כלשהו שקשור לכלל
קריאה למוסכמות של פונקציות PP ויצירה אוטומטית של ארגומנטים פלט.
בעיקרון, יש שתי דרכים להפעיל שגרות pdl, כלומר
$result = func($a,$b);
ו
func($a,$b,$result);
אם אתה משתמש רק בהשרשור מרומז, משתנה הפלט יכול להיות אוטומטי
נוצר על ידי PDL. אתה מסמן את זה לפונקציית PP על ידי הגדרת ארגומנט הפלט ל-a
סוג מיוחד של pdl שמוחזר מקריאה לפונקציה "PDL->null" שמחזירה
pdl "ריק" בעצם (למי שמתעניין בפרטים יש דגל ב-C pdl
מבנה לכך). המידות של ה-pdl שנוצר נקבעות לפי הכללים של
השרשור מרומז: הממדים הראשונים הם מימדי הפלט הליבה אליהם
מצורפות מידות השחלה (שנקבעות בתורן לפי מידות ה-
קלט pdls כמתואר לעיל). אז אתה יכול להגיד
func($a,$b,($result=PDL->null));
or
$result = func($a,$b)
שהם בדיוק המקבילה.
הזהיר שאתה יכול לֹא השתמש ביצירה אוטומטית של פלט בעת שימוש בהשרשור מפורש (עבור
סיבות המפורטות בסעיף הבא בנושא מפורש השחלה, הגרסה השנייה של
הַשׁחָלָה).
בלולאות "הדוקות" אתה כנראה רוצה להימנע מיצירה מרומזת של pdl זמני
כל שלב של הלולאה שמגיע יחד עם הסגנון ה"פונקציונלי" אלא לומר
# צור פלט pdl בגודל מתאים רק בהזמנה ראשונה
$result = null;
עבור (0...$n) {
func($a,$b,$result); # בסך הכל מלבד ה-$result הפריאה הראשונה
func2($b); # מוגדר ויש לו את הגודל המתאים
# קח את הפלט בתנאי שהעמעומים של $b לא ישתנו
twiddle($result,$a); # לעשות משהו מ-$result ל-$a עבור איטרציה
}
הודעת קח הביתה של סעיף זה פעם נוספת: היו מודעים למגבלה על הפלט
יצירה בעת השימוש מפורש השחלה.
מְפוֹרָשׁ השחלה
לאחר שדיברנו עד כה רק על הטעם הראשון של השרשור, הגיע הזמן לעשות זאת
להציג את הגרסה השנייה. במקום לדשדש מידות כל הזמן ו
להסתמך על הכללים של שרשור מרומז כדי להסתדר, לפעמים אולי תרצה
ציין בצורה מפורשת יותר כיצד לבצע את לולאת החוט. זה כנראה לא מדי
מפתיע שהגרסה הזו של המשחק נקראת מפורש השחלה. עכשיו, לפנינו
ליצור רושם שגוי: זה גם לא משתמע or מפורש; שני הטעמים כן
לְעַרְבֵּב. אבל עוד על כך בהמשך.
שתי הפונקציות הנפוצות ביותר עם השרשור מפורש הן פתיל וביטול פתיל. אנחנו מתחילים
עם דוגמה שממחישה שימוש טיפוסי של הראשון:
[# ** זו הדוגמה הגרועה ביותר שאפשר להתחיל איתה]
# אך ניתן להשתמש בו כדי להראות ש-$mat += $line שונה מ
# $mat->חוט(0) += $line
# שרשור מפורש להוספת וקטור לכל עמודה של מטריצה
pdl> $mat = zeroes(4,3)
pdl> $line = pdl (3.1416,2,-2)
pdl> ($tmp = $mat->חוט(0)) += $line
בדוגמה זו, "$mat->חוט(0)" אומר ל-PDL שאתה רוצה את הממד השני של זה
pdl שיש להשחיל עליו תחילה המוביל ללולאת חוט שניתן לבטא כ
עבור (j=0; j<3; j++) {
עבור (i = 0; i <4; i ++) {
mat(i,j) += src(j);
}
}
"thread" לוקח רשימה של מספרים כארגומנטים המציינים במפורש לאיזה ממדים
חוט תחילה. עם הכנסת השרשור המפורש המידות של pdl הן
פיצול רעיוני לשלוש קבוצות שונות את שתי האחרונות מהן כבר יש לנו
נתקלו: מידות חוט, מידות ליבה ומידות נוספות.
מבחינה קונספטואלית, עדיף לחשוב על הממדים האלה של pdl שצוינו ב
קריאה "להשחיל" כאילו נלקחת ממערך המידות הרגילות ולבש א
מחסנית נפרדת. אז בהנחה שיש לנו pdl "a(4,7,2,8)" שאומר
$b = $a->thread(2,1)
יוצר pdl וירטואלי חדש של הממד "b(4,8)" (שאנחנו קוראים לו לעמעומים הנותרים)
יש גם 2 ממדי חוט בגודל "(2,7)". למטרות מסמך זה אנו כותבים
כי באופן סמלי כ"b(4,8){2,7}". הבדל חשוב לדוגמאות הקודמות שבהן
נעשה שימוש רק בהברגה מרומזת היא העובדה שממדי הליבה מתאימים
מה היא נותר ממדים שאינן בהכרח המידות הראשונות של הפד"ל. אָנוּ
כעת יציין כיצד נוכחותם של ממדי חוט משנה את הכללים R1-R5 עבור חוט
לולאות (אשר חלות על המקרה המיוחד שבו לאף אחד מהארגומנטים של pdl אין שרשור כלשהו
ממדים).
T0 ממדי ליבה מותאמים ל-n הראשון נותר ממדים של ה-pdl
טיעון (שים לב להבדל ל-R1). רחוק יותר נותר ממדים יש לו נוסף
ממדים ומשמשים לקביעת משתמע לולאה ממדים.
T1a המספר של משתמע לולאה ממדים שווה למספר המרבי של תוספת
ממדים השתלטו על סט הארגומנטים של pdl.
T1b המספר של מפורש לולאה ממדים שווה למספר המרבי של חוטים
ממדים השתלטו על סט הארגומנטים של pdl.
T1c המספר הכולל של לולאה ממדים שווה לסכום של מפורש לולאה ממדים
ו משתמע לולאה ממדים. בלולאת החוט, מפורש לולאה ממדים יש לו
מושחל תחילה ואחריו משתמע לולאה ממדים.
T2 הגודל של כל אחד מה לולאה ממדים נגזר מהגודל של ההתאמה
מידות של הארגומנטים pdl. זה ניתן על ידי הגודל המקסימלי שנמצא בכל pdls
בעל ממד החוט הזה (עבור מפורש לולאה ממדים) או מימד נוסף (עבור
משתמע לולאה ממדים).
T3 כלל זה חל על כל מפורש לולאה ממד כמו גם כל משתמע לולאה
ממד. לכל pdls שיש להם נתון חוט/תוספת ממד הגודל חייב להיות
שווה לגודל ההתאמה מפורש/מרומז לולאה ממד או 1; אחרת
אתה מעלה חריג בזמן ריצה. אם בגודל של א חוט/תוספת ממד של pdl הוא אחד
מתייחסים אליו באופן מרומז כממד דמה בגודל השווה ל- מפורש/מרומז
לולאה ממד.
T4 אם ל-pdl אין a חוט/תוספת ממד שמתאים ל-
מפורש/מרומז לולאה ממד, בלולאת השרשור מתייחסים ל-pdl הזה כאילו יש
ממד דמה בגודל השווה לגודל של אותו ממד לולאה.
T4a כל ה-pdls שיש להם חוט ממדים חייב להיות אותו מספר חוט
ממדים.
לא ניתן להשתמש ביצירה אוטומטית של פלט T5 אם לאחד מהארגומנטים של pdl יש כאלה חוט
ממדים. אחרת R5 חל.
אותן הגבלות חלות לגבי ממדי דמה מרומזים (נוצרו על ידי
יישום של T4) כפי שכבר צוין בסעיף על השרשור מרומז: אם בכלל
ל-pdls הפלט יש ממד דמה (מפורש או מרומז) גדול מאחד
יועלה חריג בזמן ריצה.
הבה נדגים את הכללים הללו בעבודה במקרה גנרי. נניח שיש לנו (כאן
לא מצוין) פונקציית PP עם החתימה:
func((m,n),(m),(),[o](m))
ואתה קורא לזה עם 3 pdls "a(5,3,10,11)", "b(3,5,10,1,12)", "c(10)" ו-pdl פלט
"d(3,11,5,10,12)" (שיכול כאן לֹא להיווצר אוטומטית) כ
func($a->thread(1,3),$b->thread(0,3),$c,$d->thread(0,1))
מהחתימה של func והקריאה לעיל, ה-pdls מתפצלים לקבוצות הבאות של
מידות ליבה, תוספת וחוט (נכתב בצורה "pdl(core dims){thread dims}[extra
עמום]"):
a(5,10){3,11}[] b(5){3,1}[10,12] c(){}[10] d(5){3,11}[10,12]
עם זה כדי לעזור לנו (באופן כללי מועיל לכתוב את הטיעונים כך
כשאתה מתחיל לשחק עם שרשור ורוצה לעקוב אחר מה שקורה) אנחנו
עוד הסק שמספר ממדי הלולאה המפורשת הוא 2 (לפי T1b מ-$a ו-$b)
עם מידות "(3,11)" (על ידי T2); 2 ממדי לולאה מרומזים (לפי T1a מ-$b ו-$d) בגודל
"(10,12)" (על ידי T2) והרכיבים של מחושבים מ-pdls הקלט באופן שיכול
להתבטא ב-pdl פסאודו-קוד כ
עבור (l=0;l<12;l++)
עבור (k=0;k<10;k++)
עבור השפעת (j=0;j<11;j++) של התייחסות אליו כעמום דמה (אינדקס j)
עבור (i=0;i<3;i++) |
d(i,j,:,k,l) = func(a(:,i,:,j),b(i,:,k,0,l),c(k))
אוף, הדוגמה הזו הייתה ממש לא קלה מבחינת הנהלת חשבונות. זה משמש בעיקר בתור
דוגמה כיצד להבין מה קורה כאשר אתה נתקל במראה מסובך
ביטוי. אבל עכשיו באמת הגיע הזמן להראות שהשרשור מועיל על ידי מתן עוד
מהדוגמאות ה"מעשיות" שלנו.
[ הדוגמאות הבאות יזדקקו לכמה הסברים נוספים בעתיד. בשביל ה
רגע בבקשה נסה לחיות עם ההערות בקטעי הקוד. ]
דוגמא 1:
*** הפוך למטריצה המיוצגת על ידי eigvecs ו-eigvals
** נתון מטריצה סימטרית M = A^T x diag(lambda_i) x A
** => הפוך M^-1 = A^T x diag(1/lambda_i) x A
** first $tmp = diag(1/lambda_i)*A
** ואז A^T * $tmp לפי מוצר פנימי משורשר
# טיפול באינדקס כך שמטריצות מודפסות בצורה נכונה תחת pdl
$inv .= $evecs*0; # פשוט העתק כדי לקבל פלט בגודל מתאים
$tmp .= $evecs; # אתחול, ללא הפצה לאחור
($tmp2 = $tmp->חוט(0)) /= $evals; # חלוקת הברגה
# ועכשיו כפל מטריצה במסווה
PDL::Primitive::inner($evecs->xchg(0,1)->thread(-1,1),
$tmp->thread(0,-1),
$inv->thread(0,1));
# חלופה לריבוי מטריצות באמצעות השרשור מרומז,
# xchg ראשון רק עבור טרנספוזיציה
PDL::Primitive::inner($evecs->xchg(0,1)->דמה(1),
$tmp->xchg(0,1)->דמה(2),
($inv=null));
דוגמא 2:
# מכפלה חיצונית על ידי כפל מושחל
# הדגיש שעלינו לעשות זאת באמצעות קריאה מפורשת ל-my_biop1
# בעת שימוש בשרשור מפורש
$res=zeroes(($a->dims)[0],($b->dims)[0]);
my_biop1($a->thread(0,-1),$b->thread(-1,0),$res->(0,1),"*");
# דבר דומה על ידי שרשור מרומז עם pdl שנוצר אוטומטית
$res = $a->דמה(1) * $b->דמה(0);
דוגמא 3:
# שימוש שונה בשרשור ובטל פתיל כדי לערבב מספר
# ממדים במכה אחת בלי הרבה קריאות ל->xchg ו->mv
# השתמש בחוט/בטל את ההברגה כדי לערבב מידות
# פשוט נסה את זה והשווה את ה-pdl הילד עם ההורה שלו
$trans = $a->thread(4,1,0,3,2)->unthread;
דוגמא 4:
# חשב כמה תיבות תוחמות
# $bb יחזיק את BB בתור [xmin,xmax],[ymin,ymax],[zmin,zmax]
# אנו משתמשים שוב בחוט ובפתק את ההברגה כדי לערבב מידות
pdl> $bb = zeroes(double, 2,3);
pdl> minimum($vertices->חוט(0)->גוש->לבטל את השרשור(1), $bb->slice('(0),:'));
pdl> maximum($vertices->חוט(0)->גוש->לבטל את השרשור(1), $bb->slice('(1),:'));
דוגמא 5:
# לחשב רצף תמונות בקצוב עצמי (כלומר מנורמל עצמי).
# משתמש בשרשור מפורש ובחלוקה מושחלת באופן מרומז
$stack = read_image_stack();
# חשב את הממוצע (ממוצע לפיקסל) של התמונות הראשונות של $n+1
$aver = zeroes([stack->dims]->[0,1]); # הפוך את הפלט pdl
sumover($stack->slice(":,:,0:$n")->thread(0,1),$aver);
$aver /= ($n+1);
$stack /= $aver; # לנרמל את הערימה על ידי חלוקת הברגה
# מרומז מול מפורש
# לחילופין לחשב $aver עם שרשור מרומז ויצירה אוטומטית
sumover($stack->slice(":,:,0:$n")->mv(2,0),($aver=null));
$aver /= ($n+1);
#
משתמע נגד מפורש השחלה
בפסקה זו אנו הולכים להמחיש מתי שרשור מפורש עדיף על פני
שרשור מרומז ולהיפך. אבל שוב, זו כנראה לא הדרך הטובה ביותר
אם כן, אתה כבר יודע: שני הטעמים מתערבבים. אז, זה יותר על איך
כדי לקבל את הטוב משני העולמות, ובכל מקרה, לפי מיטב מסורות פרל: TIMTOWTDI !
[ מצטערים, עדיין יש למלא את זה במהדורה מאוחרת יותר; או עיין בדוגמאות לעיל
או בחר כמה חדשים ]
לבסוף, זה עשוי להיות מקום טוב להצדיק את כל הפרטים הטכניים שעברנו
פועל בערך במשך כמה עמודים: למה שרשור?
ובכן, קוד שמשתמש בהשרשור צריך להיות מהיר יותר (באופן ניכר) מקוד שמשתמש
for-loops מפורשות (או מבני Perl דומים) כדי להשיג את אותה פונקציונליות.
במיוחד במחשבי על (עם מתקני מחשוב וקטורים/עיבוד מקביל) PDL
השחלה תיושם באופן שינצל את המתקנים הנוספים
של המכונות הללו. יתר על כן, זהו מבנה פשוט מבחינה רעיונית (אם כי טכני
פרטים עשויים להיות מעורבים לפעמים) ויכולים מאוד להפחית את המורכבות התחבירית של
קוד PDL (אך זכור את האזהרה לתיעוד). ברגע שיהיה לך נוח
עם השחלה דרך החשיבה (וקידוד) זה לא אמור להיות קשה מדי
להבין קוד שמישהו אחר כתב (בתנאי שהוא נתן לך מושג מה
מידות הקלט הצפויות הן וכו'). כטיפ כללי להגברת הביצועים שלך
קוד: אם אתה צריך להכניס לולאה לקוד שלך נסה לנסח מחדש את הבעיה כך
שאתה יכול להשתמש בהברגה כדי לבצע את הלולאה (כמו בכל דבר שיש חריגים אליו
כלל האצבע הזה; אבל מחברי המסמך הזה נוטים לחשוב שאלה נדירים
מקרים ;).
PDL::PP
An קל דרך ל לְהַגדִיר פונקציות זֶה יש לו מודע of מפתוח ו השחלה (ו מה היא עוֹלָם ו
הכל)
PDL:PP הוא חלק מהפצת PDL. הוא משמש ליצירת פונקציות שמודעות להן
כללים לאינדקס והשרשור מתיאורים תמציתיים מאוד. זה יכול להיות שימושי עבורך אם
אתה רוצה לכתוב פונקציות משלך או אם אתה רוצה לממשק פונקציות מ-an
ספרייה חיצונית כך שהם תומכים באינדקס והשרשור (ואולי גם בזרימת נתונים,
ראה PDL::Dataflow). לפרטים נוספים בדוק PDL::PP.
נספח A
אפין טרנספורמציות - a מיוחד בכיתה of פשוט ו חזק טרנספורמציות
[זה גם משהו שצריך להוסיף במהדורות עתידיות. האם יש לנו כבר את הגנרל
make_affine שגרה ב-PDL ? יתכן שנפנה לאדם מתאים אחר
עמוד מכאן ]
נספח B
חתימות of תֶקֶן PDL::PP הידור פונקציות
מבחר חתימות של פרימיטיביות PDL כדי להראות כמה ממדים PP הידור
פונקציות זוללות (ולכן אתה יכול להבין מה מושחל). רוב
הפונקציות הללו הן הפונקציות הבסיסיות המוגדרות ב-"primitive.pd"
# פונקציות בפרימיטיבי.pd
#
sumover ((n),[o]())
prodover ((n),[o]())
ערכי ציר ((n)) במקום
פנימי ((n),(n),[o]())
חיצוני ((n),(מ),[o](n,m))
innerwt ((n),(n),(n),[o]())
inner2 ((m),(m,n),(n),[o]())
inner2t ((j,n),(n,m),(m,k),[o]())
אינדקס (1D,0D,[o])
מינימום (1D,[o])
מקסימום (1D,[o])
wstat ((n),(n),(),[o],())
assgn ((),())
# פעולות בסיסיות
פעולות בינאריות ((),(),[o]())
פעולות לא חוקיות ((),[o]())
AUTHOR & זכויות יוצרים
זכויות יוצרים (C) 1997 כריסטיאן סולר (c.soeller@auckland.ac.nz) & Tuomas J. Lukka
(lukka@fas.harvard.edu). כל הזכויות שמורות. למרות שמיועד לשחרור כדף אדם
עם הפצת PDL הסטנדרטית, זה לא נחלת הכלל. ניתן רשות ל
להפיץ באופן חופשי עותקים מילה במילה של מסמך זה בתנאי שאין שינויים בחוץ
של העיצוב להתבצע, וכי הודעה זו תישאר בעינה. מותר לך ו
מומלץ להשתמש בקוד שלו ובנגזרות שלו בקוד המקור שלך בשביל הכיף או בשבילך
להרוויח כראות עיניך.
השתמש ב-PDL::Indexingp באינטרנט באמצעות שירותי onworks.net