Closed Datseris closed 1 year ago
Interested in taking this. Haven't contributed to this repository before. Are there utility functions that would be useful for implementation? Also, does this repository contain everything I need to execute / get a feel for walk!
before starting randomwalk!
?
Great! Answer: yes to everything!
Internal function you will need is move_agent!(agent, pos, model)
. So, the randomwalk
generates the new position and then calls move_agent!
.
There is only one thing that will be tricky: in this random walk, you need to collect the possible positions nearby an agent that have distance r
. We don't hjave code for this at the moment. We only have code for collecting nearby positions that are within distance r
. This means, that you get positions that also have less than r
distance. The code is here:
https://github.com/JuliaDynamics/Agents.jl/blob/main/src/spaces/grid_general.jl#L48
You'd need to create an alternative version called offsets_at_radius
that only returns position offsets that are only at distance r
, not less than it.
Update here: the internal function you will need is just walk!
. You create the new direction and simply call walk!(agent, new_direction, model)
.
Thanks for the update @Datseris
If the intention is to have useful general-use functions, random walks in ContinuousSpace
allow for more freedom than just uniform random directions.
It is rather easy to implement correlated random walks (i.e., the new step direction is dependent on the last one): instead of picking a new direction uniformly, one needs to apply a rotation to the current direction (Rotations.jl
makes it quite easy).
The correlation between successive steps is defined by the properties of the rotation matrix; as an extreme example, there are some bacteria that do perform random walks, but can only make almost-perfectly anticorrelated steps ("run-reverse"), which could be represented by rotations with angles normally distributed around 180 degrees with a small stdev.
How to smoothly fit this in the interface is another question, but since I'm already working on these things I might think about this a bit if there is interest in providing these functionalities out of the box.
In 2 dimensions it will be sufficient to provide a distribution for the angle (e.g. from Distributions.jl
); in 3 dimensions things can get more complicated, but if we are just working with "dimensionless" agents (not solid bodies) then it's sufficient to specify two angle distributions (in-plane and out-of-plane rotation, or yaw and pitch if you want).
The simple uncorrelated random walk would be just the (default) case of Uniform angle distributions.
we can allow a keyword argument to randomwalk!
which would be tthe angle distribution for continuous space. By default, it is Uniform(0, 2π)
from Distributions.jl.
Would be nice if someone is going to implement this, sounds like a generally useful feature!
I'm rather busy now, but if noone else takes care of this before mid november I'll be happy to help.
I guess it makes sense to first implement the randomwalk!
function and then wait until #673 is merged to think about rotations (since Rotations.jl
works with SVector
s)
I wouldn't wait for #673 because its a breaking change. Converting to SVector
is free, you can still use Rotations.jl.
I am starting to work on this.
For the correlated random walks, agent.vel
needs to be updated after each reorientation:
1 - is agent.vel = new_direction
a safe / correct way to update the velocity of the agent or is there a dedicated function?
2 - should I assume that norm(agent.vel) ≈ 1
always holds, so that I can just rotate the unit vectors and then walk the agent as walk!(agent, new_direction .* r, model)
, or should the step size r
be included in vel
? I personally prefer the second option (and that's what I usually do in my simulations) which is more flexible although it requires an extra "normalization" step at each reorientation
agent.vel = new_direction
is correct, and dont assume normal velocity vectors. they typically have units related to space size.
Shall we agree on a convention for euclidean spaces?
If I had to choose, I would round the step to the on-grid distance which is closest to the given r
. But I don't really work with walks on grids so I'm not sure whether this can have some strange effects or if there is a different preferred convention.
Indeed small changes in r
would affect the geometric properties of the walk.
E.g. consider the following 2D cube of offsets (be it hypercube
)
(-2, -2) (-2, -1) (-2, 0) (-2, 1) (-2, 2)
(-1, -2) (-1, -1) (-1, 0) (-1, 1) (-1, 2)
(0, -2) (0, -1) (0, 0) (0, 1) (0, 2)
(1, -2) (1, -1) (1, 0) (1, 1) (1, 2)
(2, -2) (2, -1) (2, 0) (2, 1) (2, 2)
for which the euclidean distances are (hypercube_distances
)
2.82843 2.23607 2.0 2.23607 2.82843
2.23607 1.41421 1.0 1.41421 2.23607
2.0 1.0 0.0 1.0 2.0
2.23607 1.41421 1.0 1.41421 2.23607
2.82843 2.23607 2.0 2.23607 2.82843
suppose I have specified r=2.1
.
I would do something like
_, k = findmin(abs.(hypercube_distances .- r))
R = hypercube_distances[k]
offsets = hypercube[hypercube_distances .== R]
which in this case gives the offsets with distance 2.0
CartesianIndex(0, -2)
CartesianIndex(-2, 0)
CartesianIndex(2, 0)
CartesianIndex(0, 2)
But if instead I give r=2.12
it would select for the offsets at distances 2.23607 returning
CartesianIndex(-1, -2)
CartesianIndex(1, -2)
CartesianIndex(-2, -1)
CartesianIndex(2, -1)
CartesianIndex(-2, 1)
CartesianIndex(2, 1)
CartesianIndex(-1, 2)
CartesianIndex(1, 2)
Shall we agree on a convention for euclidean spaces?
I would not bother implementing this. assuming you mean euclidean metric on a discrete space. I wouldn't care about this now. Instead I would make a random walk on chebyshev space, on manhattan space, and a random walk on ContinuousSpace
(which just chooses a random angle and radius r
). For Euclidean metric on DiscreteSpace
it erros saying "its better to use continuous space for this as the walk properties depend on r
.
I think our
walk!(agent, rand, model)
is an unintuitive function, with also less power than possible. When I think of a random walk, I would think that I provide a radius to a function, and the agent takes a step with distance as much as the radius, but random direction.Our function doesn't allow for this. So, I propose that we implement a
randomwalk!
function with specification:which moves the agent in distance
r
, respecting periodic boundary conditions, but random orientation, respecting the space metric. So, for continuous space this is literally moving in a random direction in the unit circle. For Discrete space this uses the spaces metric and finds all points that have distancefloor(r)
. For Chebyshev this is hypercube, and so on. Only for Manhattan and Chebyshev this function can utilize points that have exactlyfloor(r)
distance. For euclidean metric this can only be approximate.