Skip to content

Commit beec55b

Browse files
committed
fix #541, add checks for infinite loops in Eidos under SLiMgui
1 parent 6fa7a41 commit beec55b

21 files changed

+215
-32
lines changed

EidosScribe/EidosConsoleWindowController.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,11 @@ - (NSString *)_executeScriptString:(NSString *)scriptString tokenString:(NSStrin
452452
[delegate eidosConsoleWindowControllerWillExecuteScript:self];
453453

454454
std::ostringstream outstream; // in SLiMguiLegacy, one output stream for both types of output
455-
EidosInterpreter interpreter(script, *global_symbols, *global_function_map, eidos_context, outstream, outstream);
455+
EidosInterpreter interpreter(script, *global_symbols, *global_function_map, eidos_context, outstream, outstream
456+
#ifdef SLIMGUI
457+
, true
458+
#endif
459+
);
456460

457461
try
458462
{

QtSLiM/help/SLiMHelpFunctions.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
<p class="p2">(void)initializeSLiMModelType(string$ modelType)</p>
130130
<p class="p3"><span class="s1">Configure the type of SLiM model used for the simulation.<span class="Apple-converted-space">  </span>At present, one of two model types may be selected.<span class="Apple-converted-space">  </span>If </span><span class="s2">modelType</span><span class="s1"> is </span><span class="s2">"WF"</span><span class="s1">, SLiM will use a Wright-Fisher (WF) model; this is the model type that has always been supported by SLiM, and is the model type used if </span><span class="s2">initializeSLiMModelType()</span><span class="s1"> is not called.<span class="Apple-converted-space">  </span>If </span><span class="s2">modelType</span><span class="s1"> is </span><span class="s2">"nonWF"</span><span class="s1">, SLiM will use a non-Wright-Fisher (nonWF) model instead; this is a new model type supported by SLiM 3.0 and above.</span></p>
131131
<p class="p3"><span class="s1">If </span><span class="s2">initializeSLiMModelType()</span><span class="s1"> is called at all then it must be called before any other initialization function, so that SLiM knows from the outset which features are enabled and which are not.</span></p>
132-
<p class="p2">(void)initializeSLiMOptions([logical$ keepPedigrees = F], [string$ dimensionality = ""], [string$ periodicity = ""], [logical$ doMutationRunExperiments = T], [logical$ preventIncidentalSelfing = F]<span class="s5">, [logical$ nucleotideBased = F], [logical$ randomizeCallbacks = T]</span>)</p>
132+
<p class="p2">(void)initializeSLiMOptions([logical$ keepPedigrees = F], [string$ dimensionality = ""], [string$ periodicity = ""], [logical$ doMutationRunExperiments = T], [logical$ preventIncidentalSelfing = F]<span class="s5">, [logical$ nucleotideBased = F], [logical$ randomizeCallbacks = T]</span><span class="s8">, [logical$ checkInfiniteLoops = T]</span>)</p>
133133
<p class="p3"><span class="s1">Configure options for the simulation.<span class="Apple-converted-space">  </span>If </span><span class="s2">initializeSLiMOptions()</span><span class="s1"> is called at all then it must be called before any other initialization function (except </span><span class="s2">initializeSLiMModelType()</span><span class="s1">), so that SLiM knows from the outset which optional features are enabled and which are not.</span></p>
134134
<p class="p3">If <span class="s3">keepPedigrees</span> is <span class="s3">T</span>, SLiM will keep pedigree information for every individual in the simulation, tracking the identity of its parents and grandparents.<span class="Apple-converted-space">  </span>This allows individuals to assess their degree of pedigree-based relatedness to other individuals (see <span class="s3">Individual</span>’s <span class="s3">relatedness()</span> and <span class="s3">sharedParentCount()</span> methods), as well as allowing a model to find “trios” (two parents and an offspring they generated) using the pedigree properties of <span class="s3">Individual</span>.<span class="Apple-converted-space">  </span>As a side effect of <span class="s3">keepPedigrees</span> being <span class="s3">T</span>, the <span class="s3">pedigreeID</span>, <span class="s3">pedigreeParentIDs</span>, and <span class="s3">pedigreeGrandparentIDs</span> properties of <span class="s3">Individual</span> will have defined values, as will the <span class="s3">haplosomePedigreeID</span> property of <span class="s3">Haplosome</span>.<span class="Apple-converted-space">  </span>Note that pedigree-based relatedness doesn’t necessarily correspond to genetic relatedness, due to effects such as assortment and recombination.<span class="Apple-converted-space">  </span>Beginning in SLiM 3.5, <span class="s3">keepPedigrees=T</span> also enables tracking of individual reproductive output, available through the <span class="s3">reproductiveOutput</span> property of <span class="s3">Individual</span> and the <span class="s3">lifetimeReproductiveOutput</span> property of <span class="s3">Subpopulation</span>.</p>
135135
<p class="p6">If <span class="s3">dimensionality</span> is not <span class="s3">""</span>, SLiM will enable its optional “continuous space” facility.<span class="Apple-converted-space">  </span>Three values for <span class="s3">dimensionality</span> are presently supported: <span class="s3">"x"</span>, <span class="s3">"xy"</span>, and <span class="s3">"xyz"</span>, specifying that continuous space should be enabled for one, two, or three dimensions, respectively, using (<i>x</i>), (<i>x</i>, <i>y</i>), and (<i>x</i>, <i>y</i>, <i>z</i>) coordinates respectively.<span class="Apple-converted-space">  </span>This has a number of side effects.<span class="Apple-converted-space">  </span>First of all, it means that the specified properties of <span class="s3">Individual</span> (<span class="s3">x</span>, <span class="s3">y</span>, and/or <span class="s3">z</span>) will be interpreted by SLiM as spatial positions; in particular, SLiMgui will use those properties to display subpopulations spatially.<span class="Apple-converted-space">  </span>Second, it allows spatial interactions to be defined, evaluated, and queried using <span class="s3">initializeInteractionType()</span> and <span class="s3">interaction()</span> callbacks.<span class="Apple-converted-space">  </span>And third, it enables the use of any other properties and methods related to continuous space, such as setting the spatial boundaries of subpopulations, which would otherwise raise an error.</p>
@@ -138,6 +138,7 @@
138138
<p class="p6">If <span class="s3">preventIncidentalSelfing</span> is <span class="s3">T</span>, incidental selfing in hermaphroditic models will be prevented by SLiM.<span class="Apple-converted-space">  </span>By default (i.e., if <span class="s3">preventIncidentalSelfing</span> is <span class="s3">F</span>), SLiM chooses the first and second parents in a biparental mating event independently.<span class="Apple-converted-space">  </span>It is therefore possible for the same individual to be chosen as both the first and second parent, resulting in selfing events even when the selfing rate is zero.<span class="Apple-converted-space">  </span>In many models this is unimportant, since it happens fairly infrequently and does not have large consequences.<span class="Apple-converted-space">  </span>This behavior is SLiM’s default because it is the simplest option, and produces results that most closely align with simple analytical population genetics models.<span class="Apple-converted-space">  </span>However, in some models this selfing can be undesirable and problematic.<span class="Apple-converted-space">  </span>In particular, models that involve very high variance in fitness or very small effective population sizes may see elevated rates of selfing that substantially influence model results.<span class="Apple-converted-space">  </span>If <span class="s3">preventIncidentalSelfing</span> is set to <span class="s3">T</span>, all such incidental selfing will be prevented (by choosing a new second parent if the first parent was chosen again).<span class="Apple-converted-space">  </span>Non-incidental selfing, as requested by the selfing rate, will still be permitted.<span class="Apple-converted-space">  </span>Note that if incidental selfing is prevented, SLiM will hang if it is unable to find a different second parent; there must always be at least two individuals in the population with non-zero fitness, and <span class="s3">mateChoice()</span> and <span class="s3">modifyChild()</span> callbacks must not absolutely prevent those two individuals from producing viable offspring.<span class="Apple-converted-space">  </span>Enforcement of the prohibition on incidental selfing will occur after <span class="s3">mateChoice()</span> callbacks have been called (and thus the default mating weights provided to <span class="s3">mateChoice()</span> callbacks will <i>not</i> exclude the first parent!), but will occur before <span class="s3">modifyChild()</span> callbacks are called (so those callbacks may assume that the first and second parents are distinct).</p>
139139
<p class="p3"><span class="s1">If </span><span class="s2">nucleotideBased</span><span class="s1"> is </span><span class="s2">T</span><span class="s1">, the model will be nucleotide-based.<span class="Apple-converted-space">  </span>In this case, auto-generated mutations (i.e., mutation types used by genomic element types) must be nucleotide-based, and an ancestral nucleotide sequence must be supplied with </span><span class="s2">initializeAncestralNucleotides()</span><span class="s1">.<span class="Apple-converted-space">  </span>Non-nucleotide-based mutations may still be used, but may not be referenced by genomic element types.<span class="Apple-converted-space">  </span>A mutation rate (or rate map) may not be supplied with </span><span class="s2">initializeMutationRate()</span><span class="s1">; instead, a hotspot map may (optionally) be supplied with </span><span class="s2">initializeHotspotMap()</span><span class="s1">.<span class="Apple-converted-space">  </span>This choice has many consequences across SLiM.<span class="Apple-converted-space"> </span></span></p>
140140
<p class="p3">If <span class="s3">randomizeCallbacks</span> is <span class="s3">T</span> (the default), the order in which individuals are processed in callbacks will be randomized to make it easier to avoid order-dependency bugs.<span class="Apple-converted-space">  </span>This flag exists because the order of individuals in each subpopulation is non-random; most notably, females always come before males in the individuals vector, but non-random ordering may also occur with respect to things like migrant versus non-migrant status, origin by selfing versus cloning versus biparental mating, and other factors.<span class="Apple-converted-space">  </span>When this option is <span class="s3">F</span>, individuals in a subpopulation are processed in the order of the individuals vector in each tick cycle stage, which may lead to order-dependency issues if there is an enabled callback whose behavior is not fully independent between calls.<span class="Apple-converted-space">  </span>Setting this option to <span class="s3">T</span> will cause individuals within each subpopulation to be processed in a randomized order in each tick cycle stage; specifically, this randomizes the order of calls to <span class="s3">mutationEffect()</span> callbacks in both WF and nonWF models, and calls to <span class="s3">reproduction()</span> and <span class="s3">survival()</span> callbacks in nonWF models.<span class="Apple-converted-space">  </span>Each subpopulation is still processed separately, in sequential order, so order-dependency issues between subpopulations are still possible if callbacks have effects that are not fully independent.<span class="Apple-converted-space">  </span>This feature was added in SLiM 4, breaking backward compatibility; to recover the behavior of previous versions of SLiM, pass <span class="s3">F</span> for this option (but then be very careful about order-dependency issues in your script).<span class="Apple-converted-space">  </span>The default of <span class="s3">T</span> is the safe option, but a small speed penalty is incurred by the randomization of the processing order – for most models the difference will be less than 1%, but in the worst case it may approach 10%.<span class="Apple-converted-space">  </span>Models that do not have any order-dependency issue may therefore run somewhat faster if this is set to <span class="s3">F</span>.<span class="Apple-converted-space">  </span>Note that anywhere that your script uses the <span class="s3">individuals</span> property of <span class="s3">Subpopulation</span>, the order of individuals returned will be non-random (regardless of the setting of this option); you should use <span class="s3">sample()</span> to shuffle the order of the individuals vector if necessary to avoid order-dependency issues in your script.</p>
141+
<p class="p3">If <span class="s3">checkInfiniteLoops</span> is <span class="s3">T</span> (the default), SLiM and Eidos will check for infinite loops in various circumstances, such as <span class="s3">while</span> and <span class="s3">do–while</span> loops.<span class="Apple-converted-space">  </span>This check is conducted only when running in SLiMgui; at the command line, checks for infinite loops are never conducted regardless of the value of this flag.<span class="Apple-converted-space">  </span>When checking is enabled, an error will be raised if any loop executes more than 10 million times, preventing SLiMgui’s user interface from freezing.<span class="Apple-converted-space">  </span>Normally this is desirable, but if you actually want to execute a loop more than 10 million times, this checking will prove inconvenient.<span class="Apple-converted-space">  </span>In that case, you can pass <span class="s3">F</span> for <span class="s3">checkInfiniteLoops</span> to disable these checks.<span class="Apple-converted-space">  </span>There is no way to turn these checks on or off for individual loops; it is a global setting.</p>
141142
<p class="p6">This function will likely be extended with further options in the future, added on to the end of the argument list.<span class="Apple-converted-space">  </span>Using named arguments with this call is recommended for readability.<span class="Apple-converted-space">  </span>Note that turning on optional features may increase the runtime and memory footprint of SLiM.</p>
142143
<p class="p4">(void)initializeSpecies([integer$ tickModulo = 1], [integer$ tickPhase = 1], [string$ avatar = ""], [string$ color = ""])</p>
143144
<p class="p3">Configure options for the species being initialized.<span class="Apple-converted-space">  </span>This initialization function may only be called in multispecies models (i.e., models with explicit species declarations); in single-species models, the default values are assumed and cannot be changed.</p>

SLiMgui/SLiMHelpFunctions.rtf

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ If
11961196
\pard\pardeftab720\li720\fi-446\ri720\sb180\sa60\partightenfactor0
11971197

11981198
\f1\fs18 \cf0 \kerning1\expnd0\expndtw0 (void)initializeSLiMOptions([logical$\'a0keepPedigrees\'a0=\'a0F], [string$\'a0dimensionality\'a0=\'a0""], [string$\'a0periodicity\'a0=\'a0""], [logical$\'a0doMutationRunExperiments\'a0=\'a0T], [logical$\'a0preventIncidentalSelfing\'a0=\'a0F]\cf2 \expnd0\expndtw0\kerning0
1199-
, [logical$\'a0nucleotideBased\'a0=\'a0F], [logical$\'a0randomizeCallbacks\'a0=\'a0T]\cf0 \kerning1\expnd0\expndtw0 )
1199+
, [logical$\'a0nucleotideBased\'a0=\'a0F], [logical$\'a0randomizeCallbacks\'a0=\'a0T]\kerning1\expnd0\expndtw0 , [logical$\'a0checkInfiniteLoops\'a0=\'a0T]\cf0 )
12001200
\f4 \
12011201
\pard\pardeftab397\li547\ri720\sb60\sa60\partightenfactor0
12021202

@@ -1395,6 +1395,19 @@ If
13951395
\f2\fs20 , the order of individuals returned will be non-random (regardless of the setting of this option); you should use
13961396
\f1\fs18 sample()
13971397
\f2\fs20 to shuffle the order of the individuals vector if necessary to avoid order-dependency issues in your script.\
1398+
If
1399+
\f1\fs18 checkInfiniteLoops
1400+
\f2\fs20 is
1401+
\f1\fs18 T
1402+
\f2\fs20 (the default), SLiM and Eidos will check for infinite loops in various circumstances, such as
1403+
\f1\fs18 while
1404+
\f2\fs20 and
1405+
\f1\fs18 do\'96while
1406+
\f2\fs20 loops. This check is conducted only when running in SLiMgui; at the command line, checks for infinite loops are never conducted regardless of the value of this flag. When checking is enabled, an error will be raised if any loop executes more than 10 million times, preventing SLiMgui\'92s user interface from freezing. Normally this is desirable, but if you actually want to execute a loop more than 10 million times, this checking will prove inconvenient. In that case, you can pass
1407+
\f1\fs18 F
1408+
\f2\fs20 for
1409+
\f1\fs18 checkInfiniteLoops
1410+
\f2\fs20 to disable these checks. There is no way to turn these checks on or off for individual loops; it is a global setting.\
13981411
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
13991412
\cf0 This function will likely be extended with further options in the future, added on to the end of the argument list. Using named arguments with this call is recommended for readability. Note that turning on optional features may increase the runtime and memory footprint of SLiM.\
14001413
\pard\pardeftab720\li720\fi-446\ri720\sb180\sa60\partightenfactor0

VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ development head (in the master branch):
1919
calcSFS() with an integer (non-NULL) binCount would error in multi-chromosome models if mutations from multiple chromosomes (or NULL) were given
2020
survival() callback that moves individuals did not correctly update has_null_haplosomes_, leading to a crash or a DEBUG raise (#549)
2121
calcMeanFroh() did not focus on the specified chromosome correctly, in multi-species models, and thus produced incorrect results (#545)
22+
add infinite loop checking in Eidos; add [logical$ checkInfiniteLoops = T] option to initializeSLiMOptions() to disable checking for infinite loops in Eidos
2223

2324

2425
version 5.0 (Eidos version 4.0):

core/chromosome.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,11 @@ Mutation *Chromosome::ApplyMutationCallbacks(Mutation *p_mut, Haplosome *p_haplo
11181118
EidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());
11191119
EidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);
11201120
EidosFunctionMap &function_map = community_.FunctionMap();
1121-
EidosInterpreter interpreter(mutation_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM);
1121+
EidosInterpreter interpreter(mutation_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM
1122+
#ifdef SLIMGUI
1123+
, community_.check_infinite_loops_
1124+
#endif
1125+
);
11221126

11231127
if (mutation_callback->contains_self_)
11241128
callback_symbols.InitializeConstantSymbolEntry(mutation_callback->SelfSymbolTableEntry()); // define "self"

0 commit comments

Comments
 (0)