-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Boid: Rename velocity to direction_vector #68
base: main
Are you sure you want to change the base?
Conversation
Since the velocity was modelled as a unit vector, it only represents the direction, not the velocity (which is magnitude + direction).
The division in the boid step is completely redundant, since in the next line the direction_vector will be normalized (to a unit vector) anyway.
self.cohere(neighbors) * self.cohere_factor | ||
+ self.separate(neighbors) * self.separate_factor | ||
+ self.match_heading(neighbors) * self.match_factor | ||
) / 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The / 2
affects the result. This is self.velocity +=
, not self.velocity =
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, you're totally right. I will reply in the main thread more extensively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh.. just second I was reading this background... whether the / 2
is need is the debate correct?
I agree with the rename, but the removal of the division by 2 has a problem. To rephrase what I said, adding a unit vector with another vector with a different magnitude (with or without division by 2) and then to normalize it to unit vector again will result with a unit vector with a different direction. |
You're right on the updating and not overwriting, I read over that. However:
The |
Updating makes more sense, because it implements an acceleration. There should be an inertia in the boid movement.
Not sure. https://www.red3d.com/cwr/boids/ has the original implementation (defmethod (:NAVIGATE BOID-BRAIN) ()
(vlet* ((avoid-obstacles (send self :environmental-obstacle-avoidance))
(avoid-flockmates (send self :flockmate-avoidance))
(velocity-matching (send self :velocity-matching))
(centering-urge (send self :neighborhood-centering))
(migratory-urge (send self :migratory-urge))
(course-leveling (send self :course-leveling))
(course-damping (send self :course-damping)))
;;
;; Available-acceleration should probably be 1.0, but I've set it a little higher to
;; avoid have to readjust the weighting factors for all of the acceleration requests.
;;
(vlet* ((composite-acceleration (prioritized-acceleration-allocation 1.3 ;; 1.0
avoid-obstacles
avoid-flockmates
velocity-matching
centering-urge
migratory-urge
course-leveling
course-damping))
(weights (values-list (send self :steering-weights)))
(desired-acceleration (componentwise-product weights composite-acceleration)))
'(when (eql self (default-boid))
(format w " n"))
(values-list desired-acceleration))))
(defun PRIORITIZED-ACCELERATION-ALLOCATION (available-acceleration &rest vectors)
(loop with allocated-acceleration = 0
with (tx ty tz) = '(0 0 0)
for v in vectors
for (vx vy vz) = (or v '(0 0 0))
for mag-v = (magnitude v)
for scaler = (if (> (+ allocated-acceleration mag-v) available-acceleration)
(// (- available-acceleration allocated-acceleration) mag-v)
1)
do (incf tx (* vx scaler))
(incf ty (* vy scaler))
(incf tz (* vz scaler))
(incf allocated-acceleration mag-v)
;; (format tow "~& (~d ~D ~d), ~d, ~d" tx ty tz allocated-acceleration mag-v)
until (> allocated-acceleration available-acceleration)
finally
;; (format t "~& mag= ~d" (magnitude-xyz tx ty tz))
;; (format w "~&~D" allocated-acceleration)
(return (values tx ty tz))))
|
Interesting. If we’re actually talking about acceleration, I find it incredibly weird that it get’s normalized to a unit vector each step. Can we find the original model conceptualization or formalization? |
Superseded by #104, except for the discussion. @coderbeta1 if you want to read the original implementation of Boid Flockers, the thread above has a link and relevant code snippet to it. We might have deviated from the original implementation by not implementing acceleration. |
Proposed Implementation:This seems like a good implementation of the boid flocker model with acceleration implemented as intended. TLDR:
New Current Implementation:
|
Thanks for working on this! I think the most important distinction that needs to be made is if you want to use a stationary coordinate system, of if you want to use the boid itself as the frame of reference. Both have advantages. I'm nudging towards the later, because there is a good case to be made that boids have more control for changing their direction (heading) than for changing their velocity (speed). For me it also feels more intuitive. |
True that. This just means that with the proposed implementation we increase the If we talk about intuition I think it completely depends on the person. For a third person viewer the stationary coordinate system is more intuitive. This is because
On the other hand,
Calculating the forces is easy to implement either way. I feel that the way the article is implemented is quite intuitive when is comes to acceleration. |
I agree with proceeding with the implementation with acceleration and center of mass. Let's proceed forward. The citation (pseudocode at https://vergenet.net/~conrad/boids/pseudocode.html) at the README.md also seems to suggest a form of acceleration. This is the original PR that implemented the example: projectmesa/mesa#136, which has no information about the source of the model. |
ok so I tried to follow the pseudocode as mentioned by @rht . After spending a lot of time reimplementing it, what I noticed is that the original implementation is the same as https://vergenet.net/~conrad/boids/pseudocode.html . Its just that the code implements it in a way that is not easy to understand (since there are no comments in the logic part).
One thing that I feel should be changed is the scheduling.
|
@coderbeta1 you are doing a scholarly work here! We should update Agents.jl about your findings once the dust has settled, as they use Boid for https://github.com/JuliaDynamics/ABMFrameworksComparison. I have a question regarding with the acceleration: the v1, v2, v3, ... in https://vergenet.net/~conrad/boids/pseudocode.html are technically the I agree with the SimultaneousActivation being more logical. Eliminating first mover advantage and order hysteresis makes sense. |
Awesome work so far!
Agreed! It's also faster and less noisy, and all agents act in continuous time independent from each other, so it's obviously the way to go. RandomActivation also allows an agent acting two times in a row, which from a reaction-time standpoint is not the proper way to model it. |
@rht So the thing is, the current implementation does differ from the citation. It does not have acceleration as such:
So while implementing acceleration with clipping max speed and acceleration is way better than without, it is very difficult to figure out what values to choose to get best representation of real life scenario. With the current implementation the solution does at the very least, converge If the aim is to leave it to the user to choose the values and understand the factors which affect the simulation, I think we should go with |
If you look at Reynold's original implementation in Lisp, https://www.red3d.com/cwr/code/boids.lisp, it has If you look at the pseudocode in https://vergenet.net/~conrad/boids/pseudocode.html, it does have a speed limit. Maybe just limiting the speed would be sufficient, without having to set an upper bound to the acceleration? |
Apologies for the late reply, got some important work on my side.
The speed limit does help, but it does not work if acceleration does not have a limit.
|
A velocity has a magnitude and a direction. Since the velocity was modelled as a unit vector, the magnitude is constant, and it only represents the direction, not the velocity (which is magnitude + direction). Therefor, rename
velocity
todirection_vector
.In this model, the magnitude is represented by
speed
.Also removed a redundant division.