Skip to content

Commit

Permalink
tweaks from code review
Browse files Browse the repository at this point in the history
  • Loading branch information
bhaller committed Oct 6, 2023
1 parent df05a91 commit 7d15044
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 35 deletions.
2 changes: 1 addition & 1 deletion QtSLiM/help/SLiMHelpClasses.html
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@
<p class="p5">– (float)sampleNearbyPoint(float point, float$ maxDistance, string$ functionType, ...)</p>
<p class="p6">For a spatial point supplied in <span class="s1">point</span>, returns a nearby point sampled from a kernel weighted by the spatial map’s values.<span class="Apple-converted-space">  </span>Only points within the maximum distance of the kernel, <span class="s1">maxDistance</span>, will be chosen, and the probability that a given point is chosen will be proportional to the density of the kernel at that point multiplied by the value of the map at that point (interpolated, if interpolation is enabled for the map).<span class="Apple-converted-space">  </span>Negative values of the map will be treated as zero.<span class="Apple-converted-space">  </span>The point returned will be within spatial bounds, respecting periodic boundaries if in effect (so there is no need to call <span class="s1">pointPeriodic()</span> on the result).</p>
<p class="p6">The kernel is specified with a kernel shape, <span class="s1">functionType</span>, followed by zero or more ellipsis arguments; see <span class="s1">smooth()</span> for further information.<span class="Apple-converted-space">  </span>For this method, at present only kernel types <span class="s1">"f"</span>, <span class="s1">"l"</span>, <span class="s1">"e"</span>, <span class="s1">"n"</span>, and <span class="s1">"t"</span> are supported, and type <span class="s1">"t"</span> is not presently supported for 3D kernels.</p>
<p class="p6">This method can be used to find points in the vicinity of individuals that are favorable – possessing more resources, or better environmental conditions, etc.<span class="Apple-converted-space">  </span>It can also be used to guide the dispersal or foraging behavior of individuals.<span class="Apple-converted-space">  </span>See <span class="s1">sampleImprovedNearbyPoint()</span> for a variant that may be useful for directed movement across a landscape.</p>
<p class="p6">This method can be used to find points in the vicinity of individuals that are favorable – possessing more resources, or better environmental conditions, etc.<span class="Apple-converted-space">  </span>It can also be used to guide the dispersal or foraging behavior of individuals.<span class="Apple-converted-space">  </span>See <span class="s1">sampleImprovedNearbyPoint()</span> for a variant that may be useful for directed movement across a landscape.<span class="Apple-converted-space">  </span>Note that the algorithm for <span class="s1">sampleNearbyPoint()</span> works by rejection sampling, and so will be very inefficient if the maximum value of the map (anywhere, across the entire map) is much larger than the typical value of the map where individuals are.<span class="Apple-converted-space">  </span>The algorithm for <span class="s1">sampleImprovedNearbyPoint()</span> is different, and does not exhibit this performance issue.</p>
<p class="p5">– (object&lt;SpatialMap&gt;$)smooth(float$ maxDistance, string$ functionType, ...)</p>
<p class="p6">Smooths (or blurs, one could say) the values of the spatial map by convolution with a kernel.<span class="Apple-converted-space">  </span>The kernel is specified with a maximum distance <span class="s1">maxDistance</span> (beyond which the kernel cuts off to a value of zero), a kernel type <span class="s1">functionType</span> that should be <span class="s1">"f"</span>, <span class="s1">"l"</span>, <span class="s1">"e"</span>, <span class="s1">"n"</span>, <span class="s1">"c"</span>, or <span class="s1">"t"</span>, and additional parameters in the ellipsis <span class="s1">...</span> that depend upon the kernel type and further specify its shape.<span class="Apple-converted-space">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>
<p class="p6">The kernel specification is similar to that for the <span class="s1">setInteractionType()</span> method of <span class="s1">InteractionType</span>, but omits the maximum value of the kernel.<span class="Apple-converted-space">  </span>Specifically, <span class="s1">functionType</span> may be <span class="s1">"f"</span>, in which case no ellipsis arguments should be supplied; <span class="s1">"l"</span>, similarly with no ellipsis arguments; <span class="s1">"e"</span>, in which case the ellipsis should supply a <span class="s1">numeric$</span> lambda (rate) parameter for a negative exponential function; <span class="s1">"n"</span>, in which case the ellipsis should supply a <span class="s1">numeric$</span> sigma (standard deviation) parameter for a Gaussian function; <span class="s1">"c"</span>, in which case the ellipsis should supply a <span class="s1">numeric$</span> scale parameter for a Cauchy distribution function; or <span class="s1">"t"</span>, in which case the ellipsis should supply a <span class="s1">numeric$</span> degrees of freedom and a <span class="s1">numeric$</span> scale parameter for a <i>t</i>-distribution function.<span class="Apple-converted-space">  </span>See the <span class="s1">InteractionType</span> class documentation for discussions of these kernel types.</p>
Expand Down
6 changes: 5 additions & 1 deletion SLiMgui/SLiMHelpClasses.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -6252,7 +6252,11 @@ The kernel is specified with a kernel shape,
\f4\fs20 is not presently supported for 3D kernels.\
This method can be used to find points in the vicinity of individuals that are favorable \'96 possessing more resources, or better environmental conditions, etc. It can also be used to guide the dispersal or foraging behavior of individuals. See
\f3\fs18 sampleImprovedNearbyPoint()
\f4\fs20 for a variant that may be useful for directed movement across a landscape.\
\f4\fs20 for a variant that may be useful for directed movement across a landscape. Note that the algorithm for
\f3\fs18 sampleNearbyPoint()
\f4\fs20 works by rejection sampling, and so will be very inefficient if the maximum value of the map (anywhere, across the entire map) is much larger than the typical value of the map where individuals are. The algorithm for
\f3\fs18 sampleImprovedNearbyPoint()
\f4\fs20 is different, and does not exhibit this performance issue.\
\pard\pardeftab397\li720\fi-446\ri720\sb180\sa60\partightenfactor0

\f3\fs18 \cf2 \'96\'a0(object<SpatialMap>$)smooth(float$\'a0maxDistance, string$\'a0functionType, ...)\
Expand Down
63 changes: 30 additions & 33 deletions core/spatial_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2099,8 +2099,7 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
// FIXME: TO BE PARALLELIZED
for (size_t point_index = 0; point_index < point_count; point_index++)
{
double point[1];
point[0] = *(point_buf_ptr)++;
double point_a = *(point_buf_ptr)++;

// displace the point by a draw from the kernel, looping until the displaced point is in bounds
double displaced_point[1];
Expand All @@ -2109,7 +2108,7 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
{
// displace the point by a draw from the kernel, then enforce periodic boundaries
kernel.DrawDisplacement_S1(displaced_point);
displaced_point[0] += point[0];
displaced_point[0] += point_a;

while (displaced_point[0] < 0.0)
displaced_point[0] += bounds_a1_;
Expand All @@ -2122,15 +2121,15 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
do
{
kernel.DrawDisplacement_S1(displaced_point);
displaced_point[0] += point[0];
displaced_point[0] += point_a;
}
while ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_));
}

// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint
double rescaled_point[1], rescaled_displaced[1];

rescaled_point[0] = (point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);

// Metropolis-Hastings: move to the new point if it is better, otherwise stay with probability equal to ratio of map values
Expand All @@ -2140,17 +2139,16 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
if ((map_value > original_map_value) || (map_value > original_map_value * Eidos_rng_uniform(rng)))
*(result_ptr++) = displaced_point[0];
else
*(result_ptr++) = point[0];
*(result_ptr++) = point_a;
}
}
else if (spatiality_ == 2)
{
// FIXME: TO BE PARALLELIZED
for (size_t point_index = 0; point_index < point_count; point_index++)
{
double point[2];
point[0] = *(point_buf_ptr)++;
point[1] = *(point_buf_ptr)++;
double point_a = *(point_buf_ptr)++;
double point_b = *(point_buf_ptr)++;

// displace the point by a draw from the kernel, looping until the displaced point is in bounds
double displaced_point[2];
Expand All @@ -2159,8 +2157,8 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
{
// displace the point by a draw from the kernel, then enforce periodic boundaries
kernel.DrawDisplacement_S2(displaced_point);
displaced_point[0] += point[0];
displaced_point[1] += point[1];
displaced_point[0] += point_a;
displaced_point[1] += point_b;

while (displaced_point[0] < 0.0)
displaced_point[0] += bounds_a1_;
Expand All @@ -2178,8 +2176,8 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
do
{
kernel.DrawDisplacement_S2(displaced_point);
displaced_point[0] += point[0];
displaced_point[1] += point[1];
displaced_point[0] += point_a;
displaced_point[1] += point_b;
}
while ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||
(displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_));
Expand All @@ -2188,8 +2186,8 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint
double rescaled_point[2], rescaled_displaced[2];

rescaled_point[0] = (point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_point[1] = (point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);
rescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_point[1] = (point_b - bounds_b0_) / (bounds_b1_ - bounds_b0_);
rescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_displaced[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);

Expand All @@ -2204,8 +2202,8 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
}
else
{
*(result_ptr++) = point[0];
*(result_ptr++) = point[1];
*(result_ptr++) = point_a;
*(result_ptr++) = point_b;
}
}
}
Expand All @@ -2214,10 +2212,9 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
// FIXME: TO BE PARALLELIZED
for (size_t point_index = 0; point_index < point_count; point_index++)
{
double point[3];
point[0] = *(point_buf_ptr)++;
point[1] = *(point_buf_ptr)++;
point[2] = *(point_buf_ptr)++;
double point_a = *(point_buf_ptr)++;
double point_b = *(point_buf_ptr)++;
double point_c = *(point_buf_ptr)++;

// displace the point by a draw from the kernel, looping until the displaced point is in bounds
double displaced_point[3];
Expand All @@ -2226,9 +2223,9 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
{
// displace the point by a draw from the kernel, then enforce periodic boundaries
kernel.DrawDisplacement_S3(displaced_point);
displaced_point[0] += point[0];
displaced_point[1] += point[1];
displaced_point[2] += point[2];
displaced_point[0] += point_a;
displaced_point[1] += point_b;
displaced_point[2] += point_c;

while (displaced_point[0] < 0.0)
displaced_point[0] += bounds_a1_;
Expand All @@ -2251,9 +2248,9 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
do
{
kernel.DrawDisplacement_S3(displaced_point);
displaced_point[0] += point[0];
displaced_point[1] += point[1];
displaced_point[2] += point[2];
displaced_point[0] += point_a;
displaced_point[1] += point_b;
displaced_point[2] += point_c;
}
while ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||
(displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_) ||
Expand All @@ -2263,9 +2260,9 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint
double rescaled_point[3], rescaled_displaced[3];

rescaled_point[0] = (point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_point[1] = (point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);
rescaled_point[2] = (point[2] - bounds_c0_) / (bounds_c1_ - bounds_c0_);
rescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_point[1] = (point_b - bounds_b0_) / (bounds_b1_ - bounds_b0_);
rescaled_point[2] = (point_c - bounds_c0_) / (bounds_c1_ - bounds_c0_);
rescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);
rescaled_displaced[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);
rescaled_displaced[2] = (displaced_point[2] - bounds_c0_) / (bounds_c1_ - bounds_c0_);
Expand All @@ -2282,9 +2279,9 @@ EidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStr
}
else
{
*(result_ptr++) = point[0];
*(result_ptr++) = point[1];
*(result_ptr++) = point[2];
*(result_ptr++) = point_a;
*(result_ptr++) = point_b;
*(result_ptr++) = point_c;
}
}
}
Expand Down

0 comments on commit 7d15044

Please sign in to comment.