User:Devon McCormick/DLA00/BuildingACloseNeighborhood

From J Wiki
Jump to navigation Jump to search

Building a Close Neighborhood

A flaw in the existing DLA (diffusion-limited aggregation) code - in the original code as well as in a preliminary re-vamp of this code (also here) - results in etiolated structures, for the reason illustrated below. New points are "released" in the narrow band indicated by the area between the inner and outer circles here.

RadiusOfRelease-MostLikelyPointsOfContact.png

Since this code avoids the potentially infinite processing of a point that wanders away from the cluster by limiting the number of steps in the random walk, this means that points released too far from any point on the cluster will never get a chance to join it.

Centering the Cluster

An attempt to address this by adjusting the central point to be at the center of the point cluster, rather than at the center of the entire space, doesn’t avoid the problem of preferentially adding points to the extreme ends of the cluster as illustrated below. As above, the circular band represents the area in which new points are released.

MostLikelyContactPointsOfCenteredRelease.png

Release from a Convex Hull

One proposed solution is to build a release neighborhood based on the convex hull. However, for certain shapes of clusters, this has essentially the same problem, as illustrated here.

ConvexHullPreferentialPoints.png

Building a Neighborhood

So, the ideal release neighborhood would form some sort of loose outline around the cluster. How might we do this? What follows is one way that shows some promise (an alternate exposition of the following method, in the context of a slightly more advanced version of this DLA code, can be found here). We’ll work with the following problematic cluster.

SpaceWalk00.jpg

This was actually generated from the original version of the DLA code but using the following variant of the random walk function:

walk2=: 3 : 'y + (? 1 +  # nbs) { nbs, csign center - y'
NB. Random walk biased toward center of lattice
csign=: (+.^:_1) @ ( * @ +.)
NB. Get the 'sign' of a complex number i.e. csign 0.25j_0.5 -> 1j_1

As the above diagram illustrates, this alternate method also exhibits the "etiolation problem" albeit in two dimensions.

We'll start by transforming the bit-map representation of the space into an explicit list of points:

   $PTS=: ($space)#:I.,space
12248 2
   3{.PTS     NB. What do some points look like?
222 521
223 522
224 523

(We're using the name space instead of its namespace-qualified version space_dla_ because we specified

   coinsert 'dla'

in our session.)

We use this form to help us by finding points with no neighbors:

   neigh2=: 13 : 'x-.~~.,/y+"1/+.nbs'   NB. Empty neighbors of these
   $NP=: PTS neigh2 PTS
31050 2
   viewmat 2 (<"1 NP)}space

This gives us something as shown here:

Neighbors00.jpg If you look closely, you'll see that the original, delicate structure looks a little fatter as we've chosen all the points next to each point in the original.

However, it’s easier to see the effect if we apply this repeatedly to its own result (timed here to show expensive this could be),

   6!:2 'NP=: PTS neigh2^:20]NP'
94.124175

giving this picture:

Neighbors20.jpg

So, essentially we've chosen an envelope of points around the original set. Removing the points in the cluster gives us a release neighborhood that’s perhaps too close. However if we take only the points just outside this set,

   edges=. NP -.~ ,/NP+"1/+.nbs

Where nbs is a global, from the original implementation, that gives the offsets to generate the eight cells surrounding a given point in a two-dimensional, square lattice.

   |:+.nbs
1 1 0 _1 _1 _1  0  1
0 1 1  1  0 _1 _1 _1
   $edges
76076 2

This is a lot of points, but many of them are duplicated, as seen by looking at the "nub" of this set.

   $edges=. ~.edges
15159 2
   viewmat 2 (<"1 edges)}space

giving us this thin envelope:

Neighbors20edges0.jpg

We can then expand this into a release area, or set of "release candidates" RC, by finding the neighbors of the points in this envelope,

   $RC=: PTS neigh2^:4]edges-.PTS
25970 2
   viewmat 2 (<"1 RC)}space
we get something more interesting, as seen here:

Neighbors20edges4.jpg

These release candidates closely border the cluster. If we release a point in this neighborhood close to the cluster, our random walk will encounter it fairly quickly but we're not biased toward adding points to any particular part of the cluster.

There are potentially small islands of release areas within the cluster as seen in the small pink blob on the lower left quadrant here. These can be accentuated by choosing a narrower initial, enclosing envelope, e.g instead of "20" iterations in the above "expensive" expression

   NP=: PTS neigh2^:20]NP

we could choose a smaller number - like "15" - giving us a result more quickly. Alternately, these islands can be eliminated by fattening the original enclosure by choosing more iterations at that step. The arbitrariness of these adjustments reflects that this is essentially an aesthetic choice.

Arbitrary Seeds

We can apply this technique to any arbitrary set of points to seed the cluster.

Single Seed Structure

Let's say we start with our favorite letter and apply a few hundred random points. We might get something like this:

J-DLA00.png

If we continue aggregating to this, we'll get something like this:

J-DLA03.png

Eventually, the original structure gets buried in the ever-growing aggregation:

J-DLA06.png

Multiple Seeds

Once we've gone this far, there's no reason we can't also apply this to multiple point sets:

FuzzyLogic00.png

And continue to aggregate this:

FuzzyLogic02.png

As long as we like:

FuzzyLogic08.png