شبیه سازی حرکت گروهی پرندگان در پایتون (قسمت ۲)

(حوصله ندارم فقط کد ها رو نشونم بده!)در قسمت قبلی نشان دادیم که چطور می توان حرکت پرندگان و قانون هم ترازی را در پایتون پیاده سازی کرد. در این قسمت به پیاده سازی دو قانون دیگر یعنی جدایی و انسجام می پردازیم.انسجام به معنای حرکت به سمت مرکز ثقل همسایگان است. این کار را انجام می دهیم تا بویدها را مجبور کنیم که به هم نزدیک شوند و از پراکنده شدن آن ها جلوگیری کنیم. برای این کار برای هر بوید (بوید فعلی)‌ باید مرکز ثقل را پیدا کرده و جهت حرکت را به سمت آن قرار دهیم. v بنابرا این بوید فعلی (سبز رنگ) به سمت مرکز ثقل همسایه ها (آن هایی که در دایره هستند)‌ حرکت می کند. به طور جزیی تر ابتدا محل مرکز ثقل (center_of_mass) (که یک بردار است) را پیدا می کنیم و از محل فعلی کم می کنیم تا جهت حرکت به سمت مرکز ثقل (vec_to_com) پیدا شود. در نهایت مثل حالت قبل این جهت را از سرعت فعلی بوید کم می کنیم تا نیروی مورد نظر(steering) بدست آید. یعنی:vec_to_com = center_of_mass - self.positionsteering = vec_to_com - self.velocityکد این قسمت بسیار شبیه قسمت قبلی می شود:def cohesion(self, boids): steering = Vector(*np.zeros(2)) total = 0 center_of_mass = Vector(*np.zeros(2)) for boid in boids: if np.linalg.norm(boid.position - self.position) < self.perception: center_of_mass += boid.position total += 1 if total > 0: center_of_mass /= total center_of_mass = Vector(*center_of_mass) vec_to_com = center_of_mass - self.position if np.linalg.norm(vec_to_com) > 0: vec_to_com = (vec_to_com / np.linalg.norm(vec_to_com)) * self.max_speed steering = vec_to_com - self.velocity if np.linalg.norm(steering)> self.max_force: steering = (steering /np.linalg.norm(steering)) * self.max_force return steeringدر میانه کد بالا دو بار نرمالایز می کنیم. یک بار بردار جهت به سمت مرکز ثقل را با max_speed و دیگری خود نیروی آخری یعنی steering را به اندازه max_force. این کار باعث می شود کنترل بیشتری بر روی اثر هر کدام داشته باشیم. در apply_behaviour این رفتار را اضافه می کنیم. اما چون می خواهیم بدانیم این رفتار خاص بدون هم ترازی چگونه است قسمت قبل را کامنت می کنیم:def apply_behaviour(self, boids): #alignment = self.align(boids) cohesion = self.cohesion(boids) #self.acceleration += alignment self.acceleration += cohesionاگر max_force را هم به مقدار یک و max_speed را به ۱۰ تنظیم کنیم. نتیجه می شود:همانطور که می بینید بوید ها تمایل به جمع شدن در خوشه هایی را دارند. این همان رفتار انسجام (cohesion) بدون هم ترازی (alignment) است که انتظار داشتیم.(می توانید با پارامتر ها بازی کنید و با تغییر دادن آنها رفتارهای متفاوت را ببینید)در نهایت یک رفتار می ماند که پیاده سازی کنیم: جدایی. جدایی به این معنی است که ما نمی خواهیم پرنده هایمان به هم برخورد کنند و تصادف ایجاد شود! بنابراین هر پرنده (بوید) باید حواسش به این برخورد ها باشد و قبل از برخورد جهت حرکت خودش را اصلاح کند.جدایی (separation)تفاوت مهمی اینجا وجود دارد: اگر بوید فعلی به پرنده ای نزدیک تر است اثر دور کردن آن پرنده بیشتر است. یعنی مثلا در شکل بالا بوید نزدیک تر، خطرناک تر است و باید با میزان بیشتری از آن دور شد. بنابراین اثر هر بوید متناظر با عکس فاصله آن است.def separation(self, boids): steering = Vector(*np.zeros(2)) total = 0 avg_vector = Vector(*np.zeros(2)) for boid in boids: distance = np.linalg.norm(boid.position - self.position) if self.position != boid.position and distance < self.perception: diff = self.position - boid.position diff /= distance avg_vector += diff total += 1 if total > 0: avg_vector /= total avg_vector = Vector(*avg_vector) if np.linalg.norm(steering) > 0: avg_vector = (avg_vector / np.linalg.norm(steering)) * self.max_speed steering = avg_vector - self.velocity if np.linalg.norm(steering)> self.max_force: steering = (steering /np.linalg.norm(steering)) * self.max_force return steeringدقت کنید که در حلقه اصلی فاصله ها را حساب می کنیم و تفاضل بردار های مکان را بر فاصله تقسیم می کنیم (قانون عکس فاصله). اگر فقط این قاعده را پیاده کنیم (بدون دو رفتار دیگر) چیزی شبیه زیر خواهیم داشت:همانطور که می بینید بوید ها سعی می کنند تا جای ممکن از هم فاصله بگیرند!قسمت آخر حل این پازل قرار دادن تمام بخش ها کنار هم است. باید دقت کنید که در تمامی توابعی که داشتیم steering یک شتاب یا نیرو بود. دلیل اینکه این دو کلمه را به این راحتی به جای هم استفاده می کنم این است که با فرض یکسان بودن جرم همه بوید ها (مثلا پرندگان که معمولا منطقی است) نیرو و شتاب برابر اند:قانون نیوتوناز طرفی از قانون نیرو ها می دانیم که نیروی وارد بر یک شی حاصل جمع بردار نیروهای مختلفی است که بر آن وارد می شود(چون شتاب با نیرو برابر است):پس ما هم فقط آن ها را با هم جمع می کنیم. این کار را در تابع apply_behaviour انجام می دهیم:def apply_behaviour(self, boids): alignment = self.align(boids) cohesion = self.cohesion(boids) separation = self.separation(boids) self.acceleration += alignment self.acceleration += cohesion self.acceleration += separationنتیجه کلی به صورت زیر می شود:این تصویر به زیبایی پیچیدگی سیستم را نشان می دهد. البته باید گفت که چنین چیزی تمام آنچه در طبیعت رخ می دهد را بازنمایی نمی کند قطعا قواعد دیگری هم در حرکت پرنده دخیل هستند که نیاز به مطالعه بیشتری دارد اما تعداد این قاعده ها و نحوه عملکرد آن ها ساده است. سیستم بوید ها به ما نشان می دهد می توان از سادگی پیچیدگی ایجاد کرد و آن را رها کرد تا از طریق خود سازماندهی به کمال برسد. نکته جالبی که در مورد این برنامه نویسی وجود دارد این است که شما به عنوان برنامه نویس تعیین نمی کنید که چه الگوهایی شکل می گیرد. آن ها خود به خود به وجود می آیند. صد البته پارامتر ها دست شماست اما نتیجه نهایی، بازی زیبایی از تصادف و قانون است. سیستم های طبیعی بیشتر از ناظم به تصادف نیاز دارند!یک نکته فنیاگر کد بالا را همزمان با من پیاده سازی کرده باشید متوجه نکته ای نا خوشاید می شوید. کد بالا با افزایش تعداد بوید ها مثلا بالای ۵۰ عدد بسیار کند می شود! دلیل این اتفاق این است که پیچیدگی محاسباتی کدی که من نوشتم O(n^2) است که خیلی کند می شود. یکی از کارهایی که به صورت ناموفق انجام دادم استفاده از کتابخانه ray برای موازی سازی انجام سه قاعده بود. کدهای آن بر روی گیت هاب وجود دارد و می توانید جزییات آن را ببینید. من به شخصه نتوانستم سرعت آن را خیلی بهبود بدهم. اما ایده هایی وجود دارد که می تواند آن را سریع تر کند. دقت کنید در حلقه هایی که داریم ما نیازی نداریم که همه بوید ها را بررسی کنیم. یک روش تقسیم بندی فضا است. این مساله بسیار شبیه به افزایش سرعت در الگوریتم knn است. یک بررسی اینجا وجود دارد. من در حال حاضر بیشتر روی این موضوع نمی توانم وقت بگذارم اما اگر شخصی این کار را انجام دهد بسیار خوشحال می شوم که به یک درخواست بر روی گیت هاب برای من بفرستد.