יש דברים נשברים

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

הקלות הבלתי נסבלת של הפרת הפטנט

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

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

דעתכם?

חלון מהיר

לפני כמה פוסטים שאלתי את השאלה הבאה:

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

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

אז הנה הפתרון שלי:
נחלק את התמונה למשבצות בגודל KxK, ונשמור רשימה של כל הנקודות בכל משבצת.
כאשר מבקשים מאיתנו לתת את רשימת הנקודות בחלון מסויים, נסתכל בארבעת החלונות שהחלון הזה חותך ונסנן את כל הנקודות בארבעת החלונות שלא נמצאות בתוך החלון המבוקש.
זה הכל בעצם.
הביצועים של הפתרון הזה מעולים, כדי להכין את הגריד (Grid) נעבור על כל הפיקסלים בתמונה, ולכל נקודה נמצא בזמן קבוע את המשבצת שאליה היא שייכת.
כשממש מחפשים את הנקודות בחלון מסויים, נבדוק במקרה הגרוע 2K*2K פיקסלים (אם כל הנקודות לבנות) אבל במקרה הרגיל נבדוק הרבה פחות (ואם החלון לא מכיל נקודות כלל נדע את זה מהר מאוד).
זה הקוד של העיבוד המקדים:
[code lang="java"]
private static int [][][] buildgrid(byte[][] image, int width, int height, int gridSize)
{
int grid[][][] = new int[width / gridSize][height / gridSize][];
// count the number of points in each grid cell
int numpoints[][] = new int[width / gridSize][height / gridSize];
for(int x=0;x Byte.MIN_VALUE)
{
numpoints[x/gridSize][y/gridSize]++;
}
}
}

for(int x=0;x Byte.MIN_VALUE)
{
int gy = y/gridSize;
int gx = x/gridSize;
int list[] = grid[gx][gy];
if (list == null)
{
int np = numpoints[gx][gy];
list = new int[np * 2];
grid[gx][gy] = list;
numpoints[gx][gy] = 0;
}

list[numpoints[gx][gy]++] = x;
list[numpoints[gx][gy]++] = y;
}
}
}
return grid;
}
[/code]

הקוד הבא סופר את המספר הנקודות בתוך החלון שמרכזו (x,y)' שימו לב שהלולאות עוברות על ארבעה ריבועים בגריד בלבד:
[code lang="java"]
// window boundaries:
int rx1 = x – grid_size/2;
int ry1 = y – grid_size/2;
int rx2 = rx1 + grid_size;
int ry2 = ry1 + grid_size;

// top left grid cell (out of 2×2 group to be checked)
int gx = rx1 / grid_size;
int gy = ry1 / grid_size;

for(int grid_x=gx;grid_x= 0 && grid_x < gwidth;grid_x++) { for(int grid_y=gy;grid_y= 0 && grid_y < gheight;grid_y++) { int list[] = grid[grid_x][grid_y]; if (list == null) continue; for(int i=0;i= rx1 && dx < rx2 && dy >= ry1 && dy < ry2) { c++; } } } } [/code] יתכן שאפשר לשפר את הביצועים אם נחלק את הגריד לריבועים יותר קטנים ונכלול ריבועים שלמים שנופלים בתוך החלון בלי לבדוק כל נקודה באופן פרטני, אבל לא ניסיתי. הביצועים של הפתרון הזה די מטורפים. על Q6600 במהירות 2.4GHZ, עם תמונה בגודל 500X500 פיקסלים וחלון של 20X20, בדיקה של כמה זמן לוקח לספור את הפיקסלים בכל 250,000 החלונות האפשריים לקחה כ160 מילישניות, מה שנותן מהירות בדיקה של מעל 1500 חלונות במילישניה (או יותר ממליון וחצי חלונות בשניה), בלי תלות בגודל התמונה שנבדקת (על תמונה של 1000X1000 המהירות היתה דומה). האפלט הבאה מדגימה את האלגוריתם. אפשר להוריד אותה מפה. הקוד כלול בתוך הJAR (אפשר לפתוח את הJAR עם תוכנה לפתיחת קבצי ZIP).
בנוסף, האפלט יכולה לרוץ כתוכנית רגילה : java -jar fast_window.jar
אפשר ללחוץ בתוך האפלט כדי לסמן את הנקודות בחלון.


הדפדפן שלך לא תומך בג'אווה, ככה האפלט ניראית (רק שהיא אינטראקטיבית) :


בעיית החלוקה ההוגנת (*למדיי)

אז הזכרתי באחר הפוסטים האחרונים את הבעיה הבאה:

בהנתן קבוצת S של n מספרים שלמים, איך נחלק אותה לk קבוצות כך שסכום המספרים בכל קבוצה הוא קרוב לסכום המספרים בקבוצות האחרות.
למשל:
אם

[code]
S = {2,2,3,2,3}
k=2
split(S,k)={{2,2,2},{3,3}}

S1={1,5,11,2,10}
k1=3
split(S1,k1)={{5,2,1},{10},{11}}
[/code]

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

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

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

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

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


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

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