Releases: scottpdo/flocc
0.5.20
CanvasRenderer drawing update
A minor visual improvement for CanvasRenderer
s drawing toroidal Environment
s — an Agent
close to one of the borders (top, bottom, left, right), whose shape extends beyond the border will now also be drawn on the opposite side of the canvas.
Example:
- The
Agent
located at (0, 0) would previously only be drawn in the upper-left. Now, with theEnvironment
wrapping around from left to right and top to bottom, it gets drawn in all four corners. Non-toroidalEnvironment
s will still draw the image on the left.
0.5.19
Agent Activation
The significance of this feature is arguably enough for it to be its own major release, but there's bigger things in store for v0.6.0... Today, however, we're proud to announce different agent activation regimes!
Currently, if you call environment.tick()
, that calls the tick
function of every Agent in the Environment (by default sequentially, although since v0.3.1 you can randomize the order by passing { randomizeOrder: true }
). This release allows for random activation order — that is, only activating 1 or more randomly chosen Agents with each time step, as opposed to all of them.
To run a model with random activation, you need to pass some additional configuration parameters:
environment.tick({
activation: "random",
activationCount: 10
});
With the above code, every time step 10 Agents will be randomly selected and will run their tick
functions. If activationCount
is equal to or greater than the number of Agents in the Environment, this is identical to calling environment.tick({ randomizeOrder: true })
(although slower in real time). If it is omitted, activationCount
defaults to 1
(only activating a single Agent per time step).
The default activation regime (uniform) can also be opted into explicitly by calling environment.tick({ activation: "uniform" })
. If you include an activationCount
parameter with uniform activation, it will always be ignored.
Since random activation by definition activates fewer agents per time step than uniform activation, you can also tell an Environment to progress multiple time steps with each tick by including a count
option:
environment.tick({
activation: "random",
activationCount: 10,
count: 5
});
This will activate 10 Agents every time step, but will do this 5 times every time the above code is run. So any renderers associated with the Environment will only update every 5 time steps.
0.5.18
No substantive changes in this release, but a few very minor notes:
- Automatic formatting hadn't been working, so added
prettier
as a dev dependency - Converted existing
console.warn
statements to only be called once - Added warning about
environment.tick
defaulting torandomizeOrder: true
in v0.6.0
0.5.17
Network Improvements
Adds a few new features to Networks to power network analysis. (Thanks, Complex Networks Winter Workshop!)
Network.clusteringCoefficient(agent)
: Calculates the clustering coefficient for an agent in the network. The clustering coefficient is a measure of how connected this agent's neighbors are (i.e. how much of a 'cluster' it is a part of). If all of the agent's neighbors are also connected to each other, this will be1
, and if none of them are connected to each other, it will be0
.Network.clusteringCoefficient()
: Calling this method with no parameters returns the global clustering coefficient, a value between0
and1
Network.averageClusteringCoefficient()
: The average clustering coefficient is another global measure, although it differs from the global clustering coefficient.
This also adds a new helper class Array2D
, which is a thin wrapper around NumArray
to handle 2-dimensional arrays. Under the hood, Networks
now include both adjacency list and adjacency matrix representations, the latter being an Array2D
of 0s and 1s.
0.5.16
Sampling with samplers
Currently it's difficult to retrieve multiple random values from an array, if you want the values to be guaranteed unique. For example, when taking 2 random values from the array [1, 2, 3, 4, 5]
, calling utils.sample[1, 2, 3, 4, 5])
twice is not guaranteed to return unique values; it may return 4
twice in a row.
This version adds a new function, utils.sampler
, which is a factory function (a function that returns a function). Calling utils.sampler(n)
returns a function that will act like utils.sample
, but will return a random subset of the array on which it's called, returning either n
values or all of the values in array (if fewer than n
). See a few examples below:
const sample2 = utils.sampler(2);
const arr = [1, 2, 3, 4, 5];
const sampled = sample2(arr); // may return [4, 2]
const sample6 = utils.sampler(6);
const shuffled = sample6(arr); // this will only have 5 elements, and be a shuffled version of `arr`
const sample1 = utils.sampler(1);
const singleValue = sample1(arr); // when called with 1, this acts exactly the same as `utils.sample`
const sample0 = utils.sampler(0);
const result = sample0(arr); // for 0 or negative values, always returns `null`
Like utils.sample
, multiple-value sample functions returned from utils.sampler
will also accept as a second parameter an array of numbers representing weighted values.
const sample2 = utils.sampler(2);
const arr = [1, 2, 3, 4, 5];
const weightsA = [100, 10, 1, 1, 1]; // weights do not have to be normalized (sum to 1)
sample2(arr, weightsA); // will probably but not always be [1, 2]
const weightsB = [100, 100, 1, 1, 1];
sample2(arr, weightsB); // will probably be either [1, 2] or [2, 1] (with equal likelihood)
0.5.15
Setting defaults for stats functions given empty arrays
Previously, the behavior of utility functions — utils.max
, utils.min
, and others, was unspecified if passed an empty array. It turns out that utils.max
actually returned -Infinity
(this is native JS behavior for Math.max()
when no arguments are passed!)
Now, most stats functions return null
if passed an empty array. This includes:
utils.max
utils.min
utils.mean
utils.median
utils.stdDev
The one exception is utils.sum
, which returns 0
. While this does differ from the behavior of the others, I would argue that summing 'starts' from 0
, while the other functions have no clear 'starting point.' In any case, one should be aware of this behavior whenever passing an empty array to one of these functions.
0.5.14
Updates to how Agent
tick rules are assigned
(Deprecated: Agent.addRule
and Agent.enqueue
)
To date, it's been a cumbersome extra step to 1. instantiate an Agent
with data, 2. add a tick rule, and then 3. add it to the environment. However, with this release, these three steps can now be performed simultaneously!
Before:
const agent = new Agent({
x: 12
});
agent.addRule(a => a.increment('x')); // with each tick, increment `x` value
environment.addAgent(agent);
Now:
environment.addAgent(new Agent({
x: 12,
tick(a) { a.increment('x'); }
}));
By setting a function (or Rule
) value for tick
, this will be called with every Environment.tick
that the Agent
belongs to. This is identical behavior to calling agent.addRule(...)
, except that only one function can be set at any time.
Agent
s can also enqueue a rule to be called once at the end of the current tick, by calling agent.enqueue(...)
. Similarly, this is deprecated in favor of setting a queue
value:
Before:
agent.addRule(a => {
a.increment('x');
a.enqueue(a => a.decrement('y'));
});
Now:
a.set('tick', a => {
a.increment('x');
a.set('queue', a => a.decrement('y'));
});
In this case, the lines of code remains the same, but instead of calling the addRule
and enqueue
methods, you should set tick
and queue
values.
The Agent.addRule
and Agent.enqueue
methods are now deprecated, and will be removed in version 0.7.0. Please migrate your existing code to the new API!
0.5.12
CanvasRenderer updates
Some miscellaneous updates and improvements to CanvasRenderer
s:
- New
shape
option:"triangle"
(e.g.agent.set("shape", "triangle");
). Listens to theAgent
'ssize
andcolor
values as well. Agent
s withshape
"rectangle"
now center at theAgent
's xy location rather than using that as the top-left of the rectangle.Agent
s can now be labeled with text. Set the following parameters:text
: the string of text to writetextSize
: the pixel height of the texttextAlign
: uses the same values asCanvasRenderingContext2d.textAlign
(defaults to"center"
)textBaseline
: uses the same values asCanvasRenderingContext2d.textBaseline
(defaults to"middle"
)
0.5.11
KDTree Bugfix
Fixed a bug where having 0 agents in either the left or right subtrees of a KDTree
would sometimes lead to an infinite loop when calling KDTree.rebalance
. Also updated Environment.addAgent
and .removeAgent
to take an optional 2nd parameter to decide whether to rebalance the KDTree
(defaults to true
).
0.5.10
Heatmap bugfix
One more fix: When using position
: "fixed"
and a max
value lower than the automatically detected maximum number of agents in a single cell, colors were not correctly rendering. This fix clamps the alpha value to the range 0...1, so that values above the maximum render correctly.