View Javadoc
1   package org.opentrafficsim.road.gtu.tactical.lmrs;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedHashMap;
5   import java.util.LinkedHashSet;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Map.Entry;
9   import java.util.Optional;
10  import java.util.Set;
11  import java.util.function.BiFunction;
12  import java.util.function.Function;
13  import java.util.function.Supplier;
14  import java.util.stream.Collectors;
15  import java.util.stream.Stream;
16  
17  import org.djunits.unit.SpeedUnit;
18  import org.djunits.value.vdouble.scalar.Duration;
19  import org.djunits.value.vdouble.scalar.Length;
20  import org.djunits.value.vdouble.scalar.Speed;
21  import org.djutils.exceptions.Throw;
22  import org.djutils.exceptions.Try;
23  import org.opentrafficsim.base.OtsRuntimeException;
24  import org.opentrafficsim.base.logger.Logger;
25  import org.opentrafficsim.base.parameters.ParameterException;
26  import org.opentrafficsim.base.parameters.ParameterSet;
27  import org.opentrafficsim.base.parameters.ParameterTypes;
28  import org.opentrafficsim.base.parameters.Parameters;
29  import org.opentrafficsim.core.definitions.DefaultsNl;
30  import org.opentrafficsim.core.gtu.GtuException;
31  import org.opentrafficsim.core.gtu.GtuType;
32  import org.opentrafficsim.core.gtu.Stateless;
33  import org.opentrafficsim.core.gtu.perception.DirectEgoPerception;
34  import org.opentrafficsim.core.parameters.ParameterFactoryOneShot;
35  import org.opentrafficsim.core.units.distributions.ContinuousDistSpeed;
36  import org.opentrafficsim.road.gtu.LaneBasedGtu;
37  import org.opentrafficsim.road.gtu.perception.CategoricalLanePerception;
38  import org.opentrafficsim.road.gtu.perception.LanePerception;
39  import org.opentrafficsim.road.gtu.perception.categories.AnticipationTrafficPerception;
40  import org.opentrafficsim.road.gtu.perception.categories.DirectInfrastructurePerception;
41  import org.opentrafficsim.road.gtu.perception.categories.DirectIntersectionPerception;
42  import org.opentrafficsim.road.gtu.perception.categories.neighbors.Anticipation;
43  import org.opentrafficsim.road.gtu.perception.categories.neighbors.DirectNeighborsPerception;
44  import org.opentrafficsim.road.gtu.perception.categories.neighbors.Estimation;
45  import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType;
46  import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType.AnticipationPerceivedGtuType;
47  import org.opentrafficsim.road.gtu.perception.mental.AdaptationHeadway;
48  import org.opentrafficsim.road.gtu.perception.mental.AdaptationLaneChangeDesire;
49  import org.opentrafficsim.road.gtu.perception.mental.AdaptationSituationalAwareness;
50  import org.opentrafficsim.road.gtu.perception.mental.AdaptationSpeed;
51  import org.opentrafficsim.road.gtu.perception.mental.BehavioralAdaptation;
52  import org.opentrafficsim.road.gtu.perception.mental.FactorEstimation;
53  import org.opentrafficsim.road.gtu.perception.mental.Fuller;
54  import org.opentrafficsim.road.gtu.perception.mental.Mental;
55  import org.opentrafficsim.road.gtu.perception.mental.SumFuller;
56  import org.opentrafficsim.road.gtu.perception.mental.ar.ArFuller;
57  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTask;
58  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskCarFollowing;
59  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskCarFollowingExp;
60  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskLaneChanging;
61  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskLaneChangingD;
62  import org.opentrafficsim.road.gtu.perception.mental.ar.ArTaskRoadSideDistraction;
63  import org.opentrafficsim.road.gtu.perception.mental.channel.AdaptationSpeedChannel;
64  import org.opentrafficsim.road.gtu.perception.mental.channel.AdaptationUpdateTime;
65  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelFuller;
66  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelMental;
67  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTask;
68  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskAcceleration;
69  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskCarFollowing;
70  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskCooperation;
71  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskIntersection;
72  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskLaneChange;
73  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskRoadSideDistraction;
74  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskScan;
75  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskSignal;
76  import org.opentrafficsim.road.gtu.perception.mental.channel.ChannelTaskTrafficLight;
77  import org.opentrafficsim.road.gtu.perception.mental.channel.IntersectionPerceptionChannel;
78  import org.opentrafficsim.road.gtu.perception.mental.channel.NeighborsPerceptionChannel;
79  import org.opentrafficsim.road.gtu.tactical.LaneBasedTacticalPlannerFactory;
80  import org.opentrafficsim.road.gtu.tactical.following.AbstractIdm;
81  import org.opentrafficsim.road.gtu.tactical.following.CarFollowingModel;
82  import org.opentrafficsim.road.gtu.tactical.following.DesiredHeadwayModel;
83  import org.opentrafficsim.road.gtu.tactical.following.DesiredSpeedModel;
84  import org.opentrafficsim.road.gtu.tactical.following.Idm;
85  import org.opentrafficsim.road.gtu.tactical.following.IdmPlus;
86  import org.opentrafficsim.road.gtu.tactical.following.IdmPlusMulti;
87  import org.opentrafficsim.road.gtu.tactical.util.ConflictUtil;
88  import org.opentrafficsim.road.gtu.tactical.util.SpeedLimitUtil;
89  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Cooperation;
90  import org.opentrafficsim.road.gtu.tactical.util.lmrs.GapAcceptance;
91  import org.opentrafficsim.road.gtu.tactical.util.lmrs.LmrsParameters;
92  import org.opentrafficsim.road.gtu.tactical.util.lmrs.LmrsUtil;
93  import org.opentrafficsim.road.gtu.tactical.util.lmrs.MandatoryIncentive;
94  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Synchronization;
95  import org.opentrafficsim.road.gtu.tactical.util.lmrs.Tailgating;
96  import org.opentrafficsim.road.gtu.tactical.util.lmrs.VoluntaryIncentive;
97  import org.opentrafficsim.road.network.speed.SpeedLimits;
98  
99  import nl.tudelft.simulation.jstats.distributions.DistLogNormal;
100 import nl.tudelft.simulation.jstats.distributions.DistNormalTrunc;
101 import nl.tudelft.simulation.jstats.distributions.DistTriangular;
102 import nl.tudelft.simulation.jstats.streams.StreamInterface;
103 import picocli.CommandLine.ITypeConverter;
104 import picocli.CommandLine.Option;
105 
106 /**
107  * This tactical planner is general purpose for the use of the LMRS with any combination of defined sub-components. The class
108  * seconds as a parameter factory. For both model components and parameter values, the factory can be used specific to the GTU
109  * type. Model components can be set through command line arguments, or through calling {@link #set(Setting, Object)}.
110  * Parameters can be set through standard parameter factory methods.
111  * <p>
112  * <b>Usage</b><br>
113  * The factory can be used as:
114  *
115  * <pre>
116  * LmrsFactory&lt;Lmrs&gt; factory = new LmrsFactory&lt;&gt;(List.of(DefaultsNl.CAR, DefaultsNl.VAN), Lmrs::new);
117  *
118  * factory.set(Setting.ADAPTATION_SPEED, false);
119  * </pre>
120  *
121  * The GTU list is optional (default is {@code List.of(DefaultsNl.CAR, DefaultsNl.TRUCK)}), and the second
122  * {@link TacticalPlannerProvider} argument can also be given as a list to specifiy different providers per GTU type. All
123  * settings must be provided either for all GTU types, or for a specific GTU type with which the factory was initialized. GTUs
124  * of other types can be generated within the simulation, so long as any of their parent types is within the list of the
125  * factory.
126  * <p>
127  * <b>Command line arguments</b><br>
128  * This class can be mixed in with any program using command line arguments:
129  *
130  * <pre>
131  * &#64;Mixin
132  * private LmrsFactory&lt;Lmrs&gt; factory = new LmrsFactory&lt;&gt;(Lmrs::new);
133  *
134  * public static void main(String[] args)
135  * {
136  *     Program program = new Program();
137  *     CliUtil.changeOptionDefault(program, "gtuTypes", "NL.CAR|NL.VAN|NL.TRUCK");
138  *     CliUtil.execute(program, args);
139  * }
140  * </pre>
141  *
142  * <i>Note: command line arguments and programmatically setting settings (set method) should in principle not both be used
143  * within the same program. Default command line arguments should be changed by the option default as in the example above,
144  * before the input args are executed.</i>
145  * <p>
146  * Use command line argument {@code --help} to get a list of all available command line arguments. In the example the factory is
147  * initialized using the constructor of {@link Lmrs} as a supplier of the tactical planner class. Within the context of a
148  * program it may be necessary to use a supplier of an another implementation of a tactical planner instead. The supplier can be
149  * any function that follows the {@link TacticalPlannerProvider} signature, supplying an extension of
150  * {@link AbstractIncentivesTacticalPlanner}.
151  * <p>
152  * Command line arguments can be defined to contain values for specific GTU types. The following arguments allow a simulation
153  * with GTU types {@code NL.CAR} and {@code NL.TRUCK}, or any of their sub types. All GTUs will not generally keep to the slow
154  * lane ({@code incentiveKeep}), while trucks will limit themselves on the rightmost two lanes ({@code incentiveStayRight}). GTU
155  * types and the values that apply to them should be given in the same order. The number of values given should either be 1, or
156  * equal to the number of GTU types given.
157  *
158  * <pre>
159  * --gtuTypes=NL.CAR|NL.TRUCK --incentiveKeep=false --incentiveStayRight=false|true
160  * </pre>
161  *
162  * The pipe character ({@code |}) is used to separate values. If the pipe character is part of any value, values can be quoted.
163  * If a quote is part of a any value, the value can be quoted and the quote of the value can be escaped with a backslash \. The
164  * following code will set the {@code --gtuTypes} to {@code [NL.CAR, NL.VAN, NL.T|RUCK]}.
165  *
166  * <pre>
167  * CliUtil.execute(new CommandLine(myProgram).setTrimQuotes(true), new String[] {"--gtuTypes=NL.CAR|NL.VAN|\"NL.T|RUCK\""});
168  * </pre>
169  *
170  * <b>One-shot mode</b>
171  * <p>
172  * This class extends {@link ParameterFactoryOneShot} and can thus be used as a parameter factory. It supports one-shot mode.
173  * Any parameter set after {@link #setOneShotMode()} is called and before the next GTU is generated is only applied to said GTU.
174  * At any other moment parameters that are set are fixed. This class implements {@link #setOneShotMode()} to apply the same mode
175  * on model settings, applying only to the next GTU generated, after which settings are reverted to the state when
176  * {@link #setOneShotMode()} was called.
177  * <p>
178  * <b>Settings applicability</b><br>
179  * Many settings on perception components may only apply to some implementations of Fuller, see Table 1.<br>
180  * <br>
181  * <table border="1" style="text-align:center; padding:2px; border-spacing:0px; border-width:1px; border-style:solid">
182  * <caption><i>Table 1: Perception components for Fuller implementations</i></caption>
183  * <tr>
184  * <td style="text-align:left"><b>Setting</b></td>
185  * <td colspan="4" style="text-align:center"><b>Fuller implementation</b> (FULLER_IMPLEMENTATION)</td>
186  * </tr>
187  * <tr>
188  * <td></td>
189  * <td>NONE</td>
190  * <td>SUMMATIVE</td>
191  * <td>ANTICIPATION_RELIANCE</td>
192  * <td>ATTENTION_MATRIX</td>
193  * </tr>
194  * <tr>
195  * <td style="text-align:left">PRIMARY_TASK</td>
196  * <td>-</td>
197  * <td>-</td>
198  * <td>&#10003;</td>
199  * <td>-</td>
200  * </tr>
201  * <tr>
202  * <td style="text-align:left">TEMPORAL_ANTICIPATION</td>
203  * <td>-</td>
204  * <td>&#10003;</td>
205  * <td>&#10003;</td>
206  * <td>&#10003;</td>
207  * </tr>
208  * <tr>
209  * <td style="text-align:left">ESTIMATION</td>
210  * <td>-</td>
211  * <td>&#10003;</td>
212  * <td>&#10003;</td>
213  * <td>&#10003;</td>
214  * </tr>
215  * <tr>
216  * <td style="text-align:left">FRACTION_OVERESTIMATION</td>
217  * <td>-</td>
218  * <td>&#10003;</td>
219  * <td>&#10003;</td>
220  * <td>&#10003;</td>
221  * </tr>
222  * <tr>
223  * <td colspan="5"><i>Tasks for mental model</i></td>
224  * </tr>
225  * <tr>
226  * <td style="text-align:left">TASK_CAR_FOLLOWING</td>
227  * <td>-</td>
228  * <td>&#10003;</td>
229  * <td>&#10003;</td>
230  * <td>&#10003;</td>
231  * </tr>
232  * <tr>
233  * <td style="text-align:left">TASK_FREE_ACCELERATION</td>
234  * <td>-</td>
235  * <td>-</td>
236  * <td>-</td>
237  * <td>&#10003;</td>
238  * </tr>
239  * <tr>
240  * <td style="text-align:left">TASK_TRAFFIC_LIGHTS</td>
241  * <td>-</td>
242  * <td>-</td>
243  * <td>-</td>
244  * <td>&#10003;</td>
245  * </tr>
246  * <tr>
247  * <td style="text-align:left">TASK_SIGNAL</td>
248  * <td>-</td>
249  * <td>-</td>
250  * <td>-</td>
251  * <td>&#10003;</td>
252  * </tr>
253  * <tr>
254  * <td style="text-align:left">TASK_LANE_CHANGE</td>
255  * <td>-</td>
256  * <td>&#10003;</td>
257  * <td>&#10003;</td>
258  * <td>&#10003;</td>
259  * </tr>
260  * <tr>
261  * <td style="text-align:left">TASK_COOPERATION</td>
262  * <td>-</td>
263  * <td>-</td>
264  * <td>-</td>
265  * <td>&#10003;</td>
266  * </tr>
267  * <tr>
268  * <td style="text-align:left">TASK_CONFLICTS</td>
269  * <td>-</td>
270  * <td>-</td>
271  * <td>-</td>
272  * <td>&#10003;</td>
273  * </tr>
274  * <tr>
275  * <td style="text-align:left">TASK_ROADSIDE_DISTRACTION</td>
276  * <td>-</td>
277  * <td>&#10003;</td>
278  * <td>&#10003;</td>
279  * <td>&#10003;</td>
280  * </tr>
281  * <tr>
282  * <td colspan="5"><i>Behavioral adaptations for mental model</i></td>
283  * </tr>
284  * <tr>
285  * <td style="text-align:left">ADAPTATION_SPEED</td>
286  * <td>-</td>
287  * <td>&#10003;</td>
288  * <td>&#10003;</td>
289  * <td>&#10003;</td>
290  * </tr>
291  * <tr>
292  * <td style="text-align:left">ADAPTATION_HEADWAY</td>
293  * <td>-</td>
294  * <td>&#10003;</td>
295  * <td>&#10003;</td>
296  * <td>&#10003;</td>
297  * </tr>
298  * <tr>
299  * <td style="text-align:left">ADAPTATION_LANE_CHANGE</td>
300  * <td>-</td>
301  * <td>&#10003;</td>
302  * <td>&#10003;</td>
303  * <td>&#10003;</td>
304  * </tr>
305  * <tr>
306  * <td style="text-align:left">ADAPTATION_UPDATE_TIME</td>
307  * <td>-</td>
308  * <td>-</td>
309  * <td>-</td>
310  * <td>&#10003;</td>
311  * </tr>
312  * </table>
313  * <p>
314  * Copyright (c) 2026-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
315  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
316  * </p>
317  * @author Wouter Schakel
318  * @param <T> tactical planner type
319  */
320 public class LmrsFactory<T extends AbstractIncentivesTacticalPlanner> extends ParameterFactoryOneShot
321         implements LaneBasedTacticalPlannerFactory<T>
322 {
323 
324     /** Remembered state to reset in one-shot mode. */
325     private Map<Setting<?>, List<?>> state;
326 
327     /** Random number stream. */
328     private StreamInterface stream;
329 
330     /** Distribution of vGain. */
331     private ContinuousDistSpeed vGainDist;
332 
333     /** Distribution of sigma. */
334     private DistTriangular sigmaDist;
335 
336     /** Distribution of fSpeed. */
337     private DistNormalTrunc fSpeedDist;
338 
339     /** Distribution of fSpeedGtu. */
340     private DistNormalTrunc fSpeedGtuDist;
341 
342     /** LMRS provider. */
343     private final List<TacticalPlannerProvider<T>> lmrsProvider;
344 
345     /** GTU type IDs in order of multi-valued arguments. */
346     @Option(names = {"--gtuTypes"}, description = "GTU type IDs in order of multi-valued arguments",
347             defaultValue = "NL.CAR|NL.TRUCK", split = "\\|", splitSynopsisLabel = "|")
348     private final List<String> gtuTypes;
349 
350     /** Peeked car-following model per GTU type. */
351     private Map<GtuType, CarFollowingModel> peekedCarFollowingModel = new LinkedHashMap<>();
352 
353     // LMRS
354 
355     /** Car-following model: IDM, IDM_PLUS (default) or IDM_PLUS_MULTI. */
356     @Option(names = {"--carFollowingModel"}, description = "Car-following model: IDM, IDM_PLUS or IDM_PLUS_MULTI",
357             defaultValue = "IDM_PLUS", split = "\\|", splitSynopsisLabel = "|", converter = CarFollowingModelConverter.class)
358     private List<BiFunction<DesiredHeadwayModel, DesiredSpeedModel, CarFollowingModel>> carFollowingModel =
359             listOf(IdmPlus::new);
360 
361     /** Lane change synchronization: PASSIVE (default), PASSIVE_MOVING, ALIGN_GAP or ACTIVE. */
362     @Option(names = {"--synchronization"},
363             description = "Lane change synchronization: PASSIVE, PASSIVE_MOVING, ALIGN_GAP or ACTIVE", defaultValue = "PASSIVE",
364             split = "\\|", splitSynopsisLabel = "|", converter = SynchronizationConverter.class)
365     private List<Synchronization> synchronization = listOf(Synchronization.PASSIVE);
366 
367     /** Lane change cooperation: PASSIVE (default), PASSIVE_MOVING or ACTIVE. */
368     @Option(names = {"--cooperation"}, description = "Lane change cooperation: PASSIVE, PASSIVE_MOVING or ACTIVE",
369             defaultValue = "PASSIVE", split = "\\|", splitSynopsisLabel = "|", converter = CooperationConverter.class)
370     private List<Cooperation> cooperation = listOf(Cooperation.PASSIVE);
371 
372     /** Lane change gap-acceptance: INFORMED (default) or EGO_HEADWAY. */
373     @Option(names = {"--gapAcceptance"}, description = "Lane change gap-acceptance: INFORMED or EGO_HEADWAY",
374             defaultValue = "INFORMED", split = "\\|", splitSynopsisLabel = "|", converter = GapAcceptanceConverter.class)
375     private List<GapAcceptance> gapAcceptance = listOf(GapAcceptance.INFORMED);
376 
377     // LMRS -> Mandatory incentives
378 
379     /** Mandatory lane change incentive for route (default: true). */
380     @Option(names = {"--incentiveRoute"}, description = "Mandatory lane change incentive for route", defaultValue = "true",
381             split = "\\|", splitSynopsisLabel = "|", negatable = true)
382     private List<Boolean> incentiveRoute = listOf(true);
383 
384     /** Mandatory lane change incentive to join slow traffic at split and not block other traffic. */
385     @Option(names = {"--incentiveGetInLane"},
386             description = "Mandatory lane change incentive to join slow traffic at split and not block other traffic",
387             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
388     private List<Boolean> incentiveGetInLane = listOf(false);
389 
390     /** Custom mandatory incentives. */
391     private List<Set<Supplier<MandatoryIncentive>>> customMandatoryIncentives = listOf(new LinkedHashSet<>());
392 
393     // LMRS -> Voluntary incentives
394 
395     /** Voluntary lane change incentive for speed with courtesy (default: true). */
396     @Option(names = {"--incentiveSpeedWithCourtesy"}, description = "Voluntary lane change incentive for speed with courtesy",
397             defaultValue = "true", split = "\\|", splitSynopsisLabel = "|", negatable = true)
398     private List<Boolean> incentiveSpeedWithCourtesy = listOf(true);
399 
400     /** Voluntary lane change incentive for cooperative lane changes (default: false). */
401     @Option(names = {"--incentiveCourtesy"}, description = "Voluntary lane change incentive for cooperative lane changes",
402             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
403     private List<Boolean> incentiveCourtesy = listOf(false);
404 
405     /** Voluntary lane change incentive to join the shortest queue (default: false). */
406     @Option(names = {"--incentiveQueue"}, description = "Voluntary lane change incentive to join the shortest queue",
407             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
408     private List<Boolean> incentiveQueue = listOf(false);
409 
410     /** Voluntary lane change incentive for trucks to stay in slowest rightmost two lanes (default: false). */
411     @Option(names = {"--incentiveStayRight"},
412             description = "Voluntary lane change incentive for trucks to stay in rightmost two lanes", defaultValue = "false",
413             split = "\\|", splitSynopsisLabel = "|", negatable = true)
414     private List<Boolean> incentiveStayRight = listOf(false);
415 
416     /** Voluntary lane change incentive to keep to the slow lane (default: true). */
417     @Option(names = {"--incentiveKeep"}, description = "Voluntary lane change incentive to keep to the slow lane",
418             defaultValue = "true", split = "\\|", splitSynopsisLabel = "|", negatable = true)
419     private List<Boolean> incentiveKeep = listOf(true);
420 
421     /** Custom voluntary incentives. */
422     private List<Set<Supplier<VoluntaryIncentive>>> customVoluntaryIncentives = listOf(new LinkedHashSet<>());
423 
424     // LMRS -> Acceleration incentives
425 
426     /** Acceleration incentive to slow down prior to a lower speed limit (default: false). */
427     @Option(names = {"--accelerationSpeedLimitTransition"},
428             description = "Acceleration incentive to slow down prior to a lower speed limit", defaultValue = "false",
429             split = "\\|", splitSynopsisLabel = "|", negatable = true)
430     private List<Boolean> accelerationSpeedLimitTransition = listOf(false);
431 
432     /** Acceleration incentive to approach traffic lights (default: false). */
433     @Option(names = {"--accelerationTrafficLights"}, description = "Acceleration incentive to approach traffic lights",
434             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
435     private List<Boolean> accelerationTrafficLights = listOf(false);
436 
437     /** Acceleration incentive to approach intersection conflicts (default: false). */
438     @Option(names = {"--accelerationConflicts"}, description = "Acceleration incentive to approach intersection conflicts",
439             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
440     private List<Boolean> accelerationConflicts = listOf(false);
441 
442     /** Acceleration incentive to not overtake traffic on the slow lane (default: false). */
443     @Option(names = {"--accelerationNoSlowLaneOvertake"},
444             description = "Acceleration incentive to not overtake traffic on the slow lane", defaultValue = "false",
445             split = "\\|", splitSynopsisLabel = "|", negatable = true)
446     private List<Boolean> accelerationNoSlowLaneOvertake = listOf(false);
447 
448     /** Custom acceleration incentives. */
449     private List<Set<Supplier<AccelerationIncentive>>> customAccelerationIncentives = listOf(new LinkedHashSet<>());
450 
451     // Fuller
452 
453     /** Implementation of Fuller: NONE (default), SUMMATIVE, ANTICIPATION_RELIANCE or ATTENTION_MATRIX. */
454     @Option(names = {"--fullerImplementation"},
455             description = "Implementation of Fuller: NONE, SUMMATIVE, ANTICIPATION_RELIANCE or ATTENTION_MATRIX",
456             defaultValue = "ATTENTION_MATRIX", split = "\\|", splitSynopsisLabel = "|")
457     private List<FullerImplementation> fullerImplementation = listOf(FullerImplementation.NONE);
458 
459     /** ID of primary task under ANTICIPATION_RELIANCE (default: lane-changing). */
460     @Option(names = {"--primaryTask"}, description = "ID of primary task under ANTICIPATION_RELIANCE",
461             defaultValue = "lane-changing", split = "\\|", splitSynopsisLabel = "|")
462     private List<String> primaryTask = listOf("lane-changing");
463 
464     /** Enables temporal constant-speed anticipation (default: true). */
465     @Option(names = {"--anticipation"}, description = "Enables temporal constant-speed anticipation", defaultValue = "true",
466             split = "\\|", splitSynopsisLabel = "|", negatable = true)
467     private List<Boolean> temporalAnticipation = listOf(true);
468 
469     /** Enables estimation of neighboring vehicles (default: true). */
470     @Option(names = {"--estimation"}, description = "Enables estimation of neighboring vehicles", defaultValue = "true",
471             split = "\\|", splitSynopsisLabel = "|", negatable = true)
472     private List<Boolean> neighborEstimation = listOf(true);
473 
474     /** Fraction of drivers over-estimating speed and distance [0..1] (default: 1). */
475     @Option(names = {"--fractionOverEstimation"}, description = "Fraction of drivers over-estimating speed and distance [0..1]",
476             defaultValue = "0.0", split = "\\|", splitSynopsisLabel = "|")
477     private List<Double> fractionOverEstimation = listOf(1.0);
478 
479     // Fuller -> Tasks
480 
481     /** Enables car-following task (default: true). */
482     @Option(names = {"--carFollowingTask"}, description = "Enables car-following task", defaultValue = "true", split = "\\|",
483             splitSynopsisLabel = "|", negatable = true)
484     private List<Boolean> carFollowingTask = listOf(true);
485 
486     /** Enables alternate car-following task under SUMMATIVE and ANTICIPATION_RELIANCE (default: false). */
487     @Option(names = {"--alternateCarFollowingTask"}, description = "Enables alternate car-following task (exponential)",
488             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
489     private List<Boolean> alternateCarFollowingTask = listOf(false);
490 
491     /** Enables free acceleration task under ATTENTION_MATRIX (default: false). */
492     @Option(names = {"--freeAccelerationTask"},
493             description = "Enables free acceleration task, useful when updateTimeAdaptation is true", defaultValue = "false",
494             split = "\\|", splitSynopsisLabel = "|", negatable = true)
495     private List<Boolean> freeAccelerationTask = listOf(false);
496 
497     /** Enables traffic lights task under ATTENTION_MATRIX (default: false). */
498     @Option(names = {"--trafficLightsTask"}, description = "Enables traffic light task", defaultValue = "false", split = "\\|",
499             splitSynopsisLabel = "|", negatable = true)
500     private List<Boolean> trafficLightsTask = listOf(false);
501 
502     /** Enables signal task under ATTENTION_MATRIX (default: true). */
503     @Option(names = {"--signalTask"}, description = "Enables signal task", defaultValue = "true", split = "\\|",
504             splitSynopsisLabel = "|", negatable = true)
505     private List<Boolean> signalTask = listOf(true);
506 
507     /** Enables lane-changing task (default: true). */
508     @Option(names = {"--laneChangingTask"}, description = "Enables lane-change task", defaultValue = "true", split = "\\|",
509             splitSynopsisLabel = "|", negatable = true)
510     private List<Boolean> laneChangingTask = listOf(true);
511 
512     /** Enables alternate lane-changing task under SUMMATIVE and ANTICIPATION_RELIANCE (default: false). */
513     @Option(names = {"--alternateLaneChangingTask"}, description = "Enables alternate lane-changing task (lane change desire)",
514             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
515     private List<Boolean> alternateLaneChangingTask = listOf(false);
516 
517     /** Enables cooperation task under ATTENTION_MATRIX (default: true). */
518     @Option(names = {"--cooperationTask"}, description = "Enables cooperation task", defaultValue = "true", split = "\\|",
519             splitSynopsisLabel = "|", negatable = true)
520     private List<Boolean> cooperationTask = listOf(true);
521 
522     /** Enables intersection task under ATTENTION_MATRIX (default: false). */
523     @Option(names = {"--intersectionTask"}, description = "Enables intersection task", defaultValue = "false", split = "\\|",
524             splitSynopsisLabel = "|", negatable = true)
525     private List<Boolean> intersectionTask = listOf(false);
526 
527     /** Enables road-side distraction task (default: false). */
528     @Option(names = {"--roadSideDistractionTask"}, description = "Enables road-side distraction task", defaultValue = "false",
529             split = "\\|", splitSynopsisLabel = "|", negatable = true)
530     private List<Boolean> roadSideDistractionTask = listOf(false);
531 
532     // Fuller -> Adaptations
533 
534     /** Enables behavioral speed adaptation. */
535     @Option(names = {"--speedAdaptation"}, description = "Enables behavioral speed adaptation", defaultValue = "true",
536             split = "\\|", splitSynopsisLabel = "|", negatable = true)
537     private List<Boolean> speedAdaptation = listOf(true);
538 
539     /** Enables behavioral headway adaptation. */
540     @Option(names = {"--headwayAdaptation"}, description = "Enables behavioral headway adaptation", defaultValue = "true",
541             split = "\\|", splitSynopsisLabel = "|", negatable = true)
542     private List<Boolean> headwayAdaptation = listOf(true);
543 
544     /** Enables behavioral voluntary lane change adaptation. */
545     @Option(names = {"--laneChangeAdaptation"}, description = "Enables behavioral voluntary lane change adaptation",
546             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
547     private List<Boolean> laneChangeAdaptation = listOf(false);
548 
549     /** Enables behavioral update time adaptation under ATTENTION_MATRIX. */
550     @Option(names = {"--updateTimeAdaptation"}, description = "Enables behavioral update time adaptation",
551             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
552     private List<Boolean> updateTimeAdaptation = listOf(false);
553 
554     // Social interactions
555 
556     /** Enables social pressure exerted to the (potential) leader. */
557     @Option(names = {"--socialPressure"}, description = "Enables social pressure exerted to the (potential) leader",
558             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
559     private List<Boolean> socialPressure = listOf(false);
560 
561     /** Enables tailgating due to social pressure towards the leader. */
562     @Option(names = {"--tailgating"}, description = "Enables tailgating due to social pressure towards the leader",
563             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
564     private List<Boolean> tailgating = listOf(false);
565 
566     /** Enables lane changes due to social pressure from the (potential) follower. */
567     @Option(names = {"--socioLaneChange"},
568             description = "Enables lane changes due to social pressure from the (potential) follower", defaultValue = "false",
569             split = "\\|", splitSynopsisLabel = "|", negatable = true)
570     private List<Boolean> socioLaneChange = listOf(false);
571 
572     /** Enables speed increase due to social pressure from the follower. */
573     @Option(names = {"--socioSpeed"}, description = "Enables speed increase due to social pressure from the follower",
574             defaultValue = "false", split = "\\|", splitSynopsisLabel = "|", negatable = true)
575     private List<Boolean> socioSpeed = listOf(false);
576 
577     /** GTU types for which warning for key was given. */
578     private final Map<String, Set<GtuType>> noPressureWarningGiven = new LinkedHashMap<>();
579 
580     /**
581      * Shorthand to create a list of default value(s). This is used instead of {@code List.of()} to return a mutable list.
582      * @param <V> value type
583      * @param values values
584      * @return list of default value(s)
585      */
586     @SafeVarargs
587     private static <V> List<V> listOf(final V... values)
588     {
589         return Stream.of(values).collect(Collectors.toCollection(ArrayList::new));
590     }
591 
592     /**
593      * Constructor that will use default NL.CAR and NL.TRUCK GTU types.
594      * @param lmrsProvider provider for LMRS implementation, e.g. {@code Lmrs::new}
595      * @throws NullPointerException when lmrsProvider is null
596      */
597     public LmrsFactory(final TacticalPlannerProvider<T> lmrsProvider)
598     {
599         this(List.of(DefaultsNl.CAR, DefaultsNl.TRUCK), lmrsProvider);
600     }
601 
602     /**
603      * Constructor with given GTU types and default LMRS implementation class.
604      * @param gtuTypes GTU types
605      * @param lmrsProvider provider for LMRS implementation, e.g. {@code Lmrs::new}
606      * @throws NullPointerException when gtuTypes or lmrsProvider is null
607      */
608     public LmrsFactory(final List<GtuType> gtuTypes, final TacticalPlannerProvider<T> lmrsProvider)
609     {
610         Throw.whenNull(gtuTypes, "gtuTypes");
611         Throw.whenNull(lmrsProvider, "lmrsProvider");
612         this.gtuTypes = gtuTypes.stream().map((g) -> g.getId()).collect(Collectors.toCollection(ArrayList::new));
613         this.lmrsProvider = listOf(lmrsProvider);
614     }
615 
616     /**
617      * Constructor with given GTU types and LMRS implementation class per GTU type.
618      * @param gtuTypes GTU types
619      * @param lmrsProviders providers for LMRS implementation for each GTU type, e.g. {@code Lmrs::new}, may contain
620      *            {@code null} values (except first element)
621      * @throws NullPointerException when gtuTypes or lmrsProviders is null
622      * @throws IllegalArgumentException when gtuTypes and lmrsProviders are not of equal size
623      */
624     public LmrsFactory(final List<GtuType> gtuTypes, final List<TacticalPlannerProvider<T>> lmrsProviders)
625     {
626         Throw.whenNull(gtuTypes, "gtuTypes");
627         Throw.whenNull(lmrsProviders, "lmrsProviders");
628         Throw.when(gtuTypes.size() != lmrsProviders.size(), IllegalArgumentException.class,
629                 "gtuTypes and lmrsProviders are not of equal size");
630         this.gtuTypes = gtuTypes.stream().map((g) -> g.getId()).collect(Collectors.toList());
631         this.lmrsProvider = new ArrayList<>(lmrsProviders);
632     }
633 
634     /**
635      * Sets the factory to one-shot mode. All {@linkplain Setting}s, parameters and correlations set or added between a call to
636      * this method and to {@link #create(LaneBasedGtu) create()} are removed from the factory after the call to
637      * {@link #create(LaneBasedGtu) create()}.
638      */
639     @Override
640     public void setOneShotMode()
641     {
642         super.setOneShotMode();
643         this.state = new LinkedHashMap<>();
644     }
645 
646     /**
647      * Resets the factory to the state when {@link #setOneShotMode()} was called.
648      * @param <V> setting value type
649      */
650     @SuppressWarnings("unchecked")
651     protected <V> void resetState()
652     {
653         // Note that the parameter factory (super class) resets its own state when it has set parameter values
654         if (this.state == null)
655         {
656             return;
657         }
658         for (Entry<Setting<?>, List<?>> entry : this.state.entrySet())
659         {
660             List<V> values = (List<V>) entry.getKey().getListFunction().apply(this);
661             values.clear();
662             values.addAll((List<V>) entry.getValue());
663         }
664         this.state = null;
665     }
666 
667     /**
668      * Sets the random number stream.
669      * @param stream random number stream
670      * @return this factory for method chaining
671      */
672     @SuppressWarnings("hiddenfield")
673     public LmrsFactory<T> setStream(final StreamInterface stream)
674     {
675         this.stream = stream;
676         this.vGainDist = new ContinuousDistSpeed(new DistLogNormal(stream, 3.379, 0.4), SpeedUnit.KM_PER_HOUR);
677         this.sigmaDist = new DistTriangular(stream, 0.0, 0.25, 1.0);
678         this.fSpeedDist = new DistNormalTrunc(stream, 123.7 / 120.0, 0.1, 0.8, 50.0);
679         this.fSpeedGtuDist = new DistNormalTrunc(stream, 85.0 / 80.0, 2.5 / 80.0, 0.8, 50.0);
680         return this;
681     }
682 
683     /**
684      * Sets the setting value for all GTU types.
685      * @param <V> value type
686      * @param setting setting
687      * @param value value used for all GTU types
688      * @return this factory for method chaining
689      */
690     public <V> LmrsFactory<T> set(final Setting<V> setting, final V value)
691     {
692         Throw.whenNull(value, "value");
693         final List<V> values = setting.getListFunction().apply(this);
694         saveState(setting, values);
695         values.clear();
696         values.add(value);
697         return this;
698     }
699 
700     /**
701      * Sets the setting value for given GTU type.
702      * @param <V> value type
703      * @param setting setting
704      * @param value value
705      * @param gtuType GTU type
706      * @return this factory for method chaining
707      * @throws IllegalArgumentException when the GTU type is not known
708      */
709     public <V> LmrsFactory<T> set(final Setting<V> setting, final V value, final GtuType gtuType)
710     {
711         Throw.whenNull(value, "value");
712         Throw.whenNull(gtuType, "gtuType");
713 
714         int gtuTypeIndex = this.gtuTypes.indexOf(gtuType.getId());
715         Throw.when(gtuTypeIndex < 0, IllegalArgumentException.class, "GTU type %s not defined.", gtuType.getId());
716 
717         final List<V> values = setting.getListFunction().apply(this);
718         saveState(setting, values);
719 
720         /*
721          * Append with null values if not going from 1 to N but from M to N. This is a weird state with an incomplete command
722          * line argument, and code setting a setting. In this state a default or global value is unknown. We try to deal with
723          * it, but when the setting is required for any GTU type M+1 through N an exception might arise later. This depends on
724          * whether the setting will also be set for those GTU types, or whether the setting is known for a parent type.
725          */
726         while (values.size() < this.gtuTypes.size())
727         {
728             values.add(null);
729         }
730         values.set(gtuTypeIndex, value);
731         return this;
732     }
733 
734     /**
735      * Saves the state of given setting when in one-shot mode and the setting was not already saved.
736      * @param <V> value type
737      * @param setting setting
738      * @param values value list
739      */
740     protected <V> void saveState(final Setting<V> setting, final List<V> values)
741     {
742         if (this.state != null && !this.state.containsKey(setting))
743         {
744             this.state.put(setting, new ArrayList<>(values));
745         }
746     }
747 
748     /**
749      * Returns value of setting for the GTU type.
750      * @param <V> value type
751      * @param setting setting
752      * @param gtuType GTU type
753      * @return value from value array for the GTU type
754      */
755     // This method is for sub classes, which cannot access the value lists directly
756     protected <V> V get(final Setting<V> setting, final GtuType gtuType)
757     {
758         return get(setting.getListFunction().apply(this), gtuType, gtuType);
759     }
760 
761     /**
762      * Returns value from value array for the GTU type.
763      * @param <V> value type
764      * @param values values
765      * @param gtuType GTU type
766      * @return value from value array for the GTU type
767      */
768     protected <V> V get(final List<V> values, final GtuType gtuType)
769     {
770         return get(values, gtuType, gtuType);
771     }
772 
773     /**
774      * Returns value from value array for the GTU type.
775      * @param <V> value type
776      * @param values values
777      * @param gtuType GTU type
778      * @param originalGtuType original GTU type (only for possible exception message)
779      * @return value from value array for the GTU type
780      */
781     private <V> V get(final List<V> values, final GtuType gtuType, final GtuType originalGtuType)
782     {
783         Throw.when(values.size() > 1 && this.gtuTypes.size() > values.size(), IllegalArgumentException.class,
784                 "Argument has %s values %s but %s GTU types are defined.", values.size(), values, this.gtuTypes.size());
785         if (values.size() == 1)
786         {
787             return values.get(0);
788         }
789         int index = this.gtuTypes.indexOf(gtuType.getId());
790         if (index < 0 || values.get(index) == null)
791         {
792             return get(values,
793                     gtuType.getParent().orElseThrow(() -> new IllegalArgumentException(
794                             "Unable to obtain setting value for GTU type " + originalGtuType.getId() + " or any parent.")),
795                     originalGtuType);
796         }
797         return values.get(index);
798     }
799 
800     /**
801      * Peek car-following model to support peeked desired speed and desired headway.
802      * @param gtuType GTU type
803      * @return next car-following model
804      */
805     private CarFollowingModel peekCarFollowingModel(final GtuType gtuType)
806     {
807         return this.peekedCarFollowingModel.computeIfAbsent(gtuType, (gt) ->
808         {
809             DesiredSpeedModel desiredSpeedModel = get(this.socioSpeed, gtuType)
810                     ? new SocioDesiredSpeed(AbstractIdm.DESIRED_SPEED) : AbstractIdm.DESIRED_SPEED;
811             return get(this.carFollowingModel, gtuType).apply(AbstractIdm.HEADWAY, desiredSpeedModel);
812         });
813     }
814 
815     @Override
816     public Optional<Speed> peekDesiredSpeed(final GtuType gtuType, final SpeedLimits speedLimits, final Speed maxVehicleSpeed,
817             final Parameters parameters) throws GtuException
818     {
819         return Try.assign(
820                 () -> Optional.of(peekCarFollowingModel(gtuType).desiredSpeed(parameters, speedLimits, maxVehicleSpeed)),
821                 IllegalStateException.class, "Parameter for desired speed missing.");
822     }
823 
824     @Override
825     public Optional<Length> peekDesiredHeadway(final GtuType gtuType, final Speed speed, final Parameters parameters)
826             throws GtuException
827     {
828         return Try.assign(() -> Optional.of(peekCarFollowingModel(gtuType).desiredHeadway(parameters, speed)),
829                 IllegalStateException.class, "Parameter for desired headway missing.");
830     }
831 
832     @Override
833     public Parameters getParameters(final GtuType gtuType) throws ParameterException
834     {
835         ParameterSet parameters = new ParameterSet();
836         parameters.setDefaultParameters(LmrsUtil.class);
837         parameters.setDefaultParameters(LmrsParameters.class);
838         parameters.setDefaultParameters(AbstractIdm.class);
839         parameters.setDefaultParameters(ConflictUtil.class);
840         parameters.setDefaultParameter(ParameterTypes.T0);
841         parameters.setDefaultParameter(ParameterTypes.LC_INFO);
842         parameters.setDefaultParameter(ParameterTypes.LOOKBACK);
843         parameters.setDefaultParameter(ParameterTypes.LOOKAHEAD);
844         parameters.setDefaultParameter(ParameterTypes.VCONG);
845         parameters.setDefaultParameter(ParameterTypes.LCDUR);
846         if (IdmPlusMultiFunction.SINGLETON.equals(get(this.carFollowingModel, gtuType)))
847         {
848             parameters.setDefaultParameter(IdmPlusMulti.NLEADERS);
849         }
850         if (get(this.accelerationSpeedLimitTransition, gtuType))
851         {
852             parameters.setDefaultParameter(SpeedLimitUtil.A_LAT);
853         }
854 
855         // Fuller
856         if (!FullerImplementation.NONE.equals(get(this.fullerImplementation, gtuType)))
857         {
858             parameters.setParameter(ParameterTypes.TR, Duration.ZERO);
859             parameters.setDefaultParameter(AdaptationSituationalAwareness.TR_MAX);
860             parameters.setParameter(ChannelFuller.EST_FACTOR, 1.0);
861             parameters.setParameter(Fuller.OVER_EST,
862                     this.stream.nextDouble() <= get(this.fractionOverEstimation, gtuType) ? 1.0 : -1.0);
863             parameters.setDefaultParameter(ChannelTaskScan.TDSCAN);
864             if (get(this.headwayAdaptation, gtuType))
865             {
866                 parameters.setDefaultParameter(AdaptationHeadway.BETA_T);
867             }
868             if (get(this.speedAdaptation, gtuType))
869             {
870                 parameters.setDefaultParameter(AdaptationSpeed.BETA_V0);
871             }
872 
873             if (FullerImplementation.ATTENTION_MATRIX.equals(get(this.fullerImplementation, gtuType)))
874             {
875                 // Attention matrix
876                 parameters.setDefaultParameters(ChannelFuller.class);
877                 parameters.setDefaultParameters(ChannelMental.class);
878                 if (get(this.updateTimeAdaptation, gtuType))
879                 {
880                     parameters.setDefaultParameter(AdaptationUpdateTime.DT_MIN);
881                     parameters.setDefaultParameter(AdaptationUpdateTime.DT_MAX);
882                 }
883                 if (get(this.carFollowingTask, gtuType))
884                 {
885                     parameters.setDefaultParameter(ArTaskCarFollowingExp.HEXP);
886                 }
887                 if (get(this.trafficLightsTask, gtuType) || get(this.intersectionTask, gtuType))
888                 {
889                     parameters.setDefaultParameter(ChannelTaskIntersection.TD_B);
890                     parameters.setDefaultParameter(ChannelTaskIntersection.TD_C);
891                     parameters.setDefaultParameter(ChannelTaskIntersection.BETA_YL);
892                     parameters.setDefaultParameter(ChannelTaskIntersection.BETA_CON);
893                 }
894                 if (get(this.signalTask, gtuType))
895                 {
896                     parameters.setDefaultParameter(ChannelTaskSignal.TDSIGNAL);
897                 }
898             }
899             else
900             {
901                 // Summative or anticipation reliance
902                 parameters.setDefaultParameters(Fuller.class);
903                 parameters.setDefaultParameters(SumFuller.class);
904                 parameters.setDefaultParameter(AdaptationSituationalAwareness.SA);
905                 parameters.setDefaultParameter(AdaptationSituationalAwareness.SA_MIN);
906                 parameters.setDefaultParameter(AdaptationSituationalAwareness.SA_MAX);
907                 if (FullerImplementation.ANTICIPATION_RELIANCE.equals(get(this.fullerImplementation, gtuType)))
908                 {
909                     parameters.setDefaultParameter(ArFuller.ALPHA);
910                     parameters.setDefaultParameter(ArFuller.BETA);
911                 }
912                 if (get(this.alternateCarFollowingTask, gtuType))
913                 {
914                     parameters.setDefaultParameter(ArTaskCarFollowingExp.HEXP);
915                 }
916             }
917 
918         }
919 
920         // Social interactions
921         parameters.setDefaultParameter(Tailgating.RHO);
922         // Alternate default values in case of social interactions, including distributions for the speed-leading strategy
923         if (get(this.tailgating, gtuType))
924         {
925             if (!get(this.socialPressure, gtuType) && giveWarning("tailgating", gtuType))
926             {
927                 Logger.ots().warn(
928                         "Tailgating is enabled for {} but likely ineffective as social pressure is currently disabled.",
929                         gtuType);
930             }
931             parameters.setDefaultParameter(Tailgating.DEV_RHO);
932             parameters.setParameter(ParameterTypes.TMAX, Duration.ofSI(1.6));
933         }
934         boolean socioLc = get(this.socioLaneChange, gtuType);
935         boolean socioV = get(this.socioSpeed, gtuType);
936         if (socioLc || socioV)
937         {
938             if (socioLc && !this.socialPressure.contains(true) && giveWarning("socioLc", gtuType))
939             {
940                 Logger.ots().warn("SocioLaneChange is enabled for {} but likely ineffective as"
941                         + " social pressure is currently disabled for all GTU types.", gtuType);
942             }
943             if (socioV && !this.socialPressure.contains(true) && giveWarning("socioV", gtuType))
944             {
945                 Logger.ots().warn("SocioSpeed is enabled for {} but likely ineffective as"
946                         + " social pressure is currently disabled for all GTU types.", gtuType);
947             }
948             parameters.setParameter(LmrsParameters.VGAIN, this.vGainDist.get());
949             parameters.setParameter(LmrsParameters.SOCIO, this.sigmaDist.draw());
950         }
951         parameters.setParameter(ParameterTypes.FSPEED, this.fSpeedDist.draw());
952         parameters.setParameter(ParameterTypes.FSPEED_GTU, this.fSpeedGtuDist.draw());
953         return parameters;
954     }
955 
956     @Override
957     public T create(final LaneBasedGtu gtu) throws GtuException
958     {
959         GtuType gtuType = gtu.getType();
960 
961         // Car-following model
962         CarFollowingModel cfModel = peekCarFollowingModel(gtuType);
963         this.peekedCarFollowingModel.remove(gtuType);
964 
965         // Perception
966         LanePerception perception = getPerception(gtu);
967 
968         // Tactical planner
969         Synchronization sync = get(this.synchronization, gtuType);
970         Cooperation coop = get(this.cooperation, gtuType);
971         GapAcceptance gapAccept = get(this.gapAcceptance, gtuType);
972         Tailgating tail = !get(this.socialPressure, gtuType) ? Tailgating.NONE
973                 : (get(this.tailgating, gtuType) ? Tailgating.PRESSURE : Tailgating.RHO_ONLY);
974         T tacticalPlanner = get(this.lmrsProvider, gtuType).from(cfModel, gtu, perception, sync, coop, gapAccept, tail);
975 
976         // Mandatory incentives
977         if (get(this.incentiveRoute, gtuType))
978         {
979             tacticalPlanner.addMandatoryIncentive(IncentiveRoute.SINGLETON);
980         }
981         if (get(this.incentiveGetInLane, gtuType))
982         {
983             tacticalPlanner.addMandatoryIncentive(IncentiveGetInLane.SINGLETON);
984         }
985         get(this.customMandatoryIncentives, gtuType).forEach((s) -> tacticalPlanner.addMandatoryIncentive(s.get()));
986 
987         // Voluntary incentives
988         if (get(this.incentiveSpeedWithCourtesy, gtuType))
989         {
990             tacticalPlanner.addVoluntaryIncentive(IncentiveSpeedWithCourtesy.SINGLETON);
991         }
992         if (get(this.incentiveCourtesy, gtuType))
993         {
994             tacticalPlanner.addVoluntaryIncentive(IncentiveCourtesy.SINGLETON);
995         }
996         if (get(this.incentiveQueue, gtuType))
997         {
998             tacticalPlanner.addVoluntaryIncentive(IncentiveQueue.SINGLETON);
999         }
1000         if (get(this.incentiveStayRight, gtuType))
1001         {
1002             tacticalPlanner.addVoluntaryIncentive(IncentiveStayOnSlowLanes.SINGLETON);
1003         }
1004         if (get(this.incentiveKeep, gtuType))
1005         {
1006             tacticalPlanner.addVoluntaryIncentive(IncentiveKeep.SINGLETON);
1007         }
1008         if (get(this.socioLaneChange, gtuType))
1009         {
1010             tacticalPlanner.addVoluntaryIncentive(IncentiveSocioSpeed.SINGLETON);
1011         }
1012         get(this.customVoluntaryIncentives, gtuType).forEach((s) -> tacticalPlanner.addVoluntaryIncentive(s.get()));
1013 
1014         // Acceleration incentives
1015         if (get(this.accelerationSpeedLimitTransition, gtuType))
1016         {
1017             tacticalPlanner.addAccelerationIncentive(AccelerationSpeedTransition.SINGLETON);
1018         }
1019         if (get(this.accelerationTrafficLights, gtuType))
1020         {
1021             tacticalPlanner.addAccelerationIncentive(AccelerationTrafficLights.SINGLETON);
1022         }
1023         if (get(this.accelerationConflicts, gtuType))
1024         {
1025             tacticalPlanner.addAccelerationIncentive(new AccelerationConflicts());
1026         }
1027         if (get(this.accelerationNoSlowLaneOvertake, gtuType))
1028         {
1029             tacticalPlanner.addAccelerationIncentive(
1030                     new AccelerationNoSlowLaneOvertake(() -> tacticalPlanner.getLatestMandatoryDesire()));
1031         }
1032         get(this.customAccelerationIncentives, gtuType).forEach((s) -> tacticalPlanner.addAccelerationIncentive(s.get()));
1033 
1034         // Add AccelerationLaneChangers if the bookkeeping requires it
1035         if (gtu.getBookkeeping().isEdge())
1036         {
1037             tacticalPlanner.addAccelerationIncentive(AccelerationLaneChangers.SINGLETON);
1038         }
1039 
1040         resetState();
1041 
1042         return tacticalPlanner;
1043     }
1044 
1045     /**
1046      * Returns {@code true} only the first time for each combination of key and GTU type.
1047      * @param key key
1048      * @param gtuType GTU type
1049      * @return {@code true} only the first time for each combination of key and GTU type
1050      */
1051     private boolean giveWarning(final String key, final GtuType gtuType)
1052     {
1053         return this.noPressureWarningGiven.computeIfAbsent(key, (k) -> new LinkedHashSet<>()).add(gtuType);
1054     }
1055 
1056     /**
1057      * Returns perception for the GTU.
1058      * @param gtu GTU
1059      * @return perception for the GTU
1060      */
1061     protected LanePerception getPerception(final LaneBasedGtu gtu)
1062     {
1063         GtuType gtuType = gtu.getType();
1064 
1065         Mental mental;
1066         Estimation estimation;
1067         Anticipation anticipation;
1068 
1069         if (FullerImplementation.ATTENTION_MATRIX.equals(get(this.fullerImplementation, gtuType)))
1070         {
1071             // tasks
1072             LinkedHashSet<Function<LanePerception, Set<ChannelTask>>> taskSuppliers = new LinkedHashSet<>();
1073             addChannelTask(taskSuppliers, get(this.carFollowingTask, gtuType), ChannelTaskCarFollowing.SUPPLIER);
1074             addChannelTask(taskSuppliers, get(this.freeAccelerationTask, gtuType), ChannelTaskAcceleration.SUPPLIER);
1075             addChannelTask(taskSuppliers, get(this.trafficLightsTask, gtuType), ChannelTaskTrafficLight.SUPPLIER);
1076             addChannelTask(taskSuppliers, get(this.signalTask, gtuType), ChannelTaskSignal.SUPPLIER);
1077             addChannelTask(taskSuppliers, get(this.laneChangingTask, gtuType), ChannelTaskLaneChange.SUPPLIER);
1078             addChannelTask(taskSuppliers, get(this.cooperationTask, gtuType), ChannelTaskCooperation.SUPPLIER);
1079             addChannelTask(taskSuppliers, get(this.intersectionTask, gtuType), ChannelTaskIntersection.SUPPLIER);
1080             addChannelTask(taskSuppliers, get(this.roadSideDistractionTask, gtuType),
1081                     new ChannelTaskRoadSideDistraction.Supplier(gtu));
1082             addChannelTask(taskSuppliers, true, ChannelTaskScan.SUPPLIER);
1083 
1084             // behavioral adaptation
1085             Set<BehavioralAdaptation> behavioralAdapatations = new LinkedHashSet<>();
1086             if (get(this.speedAdaptation, gtuType))
1087             {
1088                 behavioralAdapatations.add(new AdaptationSpeedChannel());
1089             }
1090             if (get(this.headwayAdaptation, gtuType))
1091             {
1092                 behavioralAdapatations.add(new AdaptationHeadway());
1093             }
1094             if (get(this.laneChangeAdaptation, gtuType))
1095             {
1096                 behavioralAdapatations.add(AdaptationLaneChangeDesire.SINGLETON);
1097             }
1098             if (get(this.updateTimeAdaptation, gtuType))
1099             {
1100                 behavioralAdapatations.add(AdaptationUpdateTime.SINGLETON);
1101             }
1102 
1103             mental = new ChannelFuller(taskSuppliers, behavioralAdapatations);
1104 
1105             estimation = get(this.neighborEstimation, gtuType) ? FactorEstimation.SINGLETON : Estimation.NONE;
1106             anticipation = get(this.temporalAnticipation, gtuType) ? Anticipation.CONSTANT_SPEED : Anticipation.NONE;
1107         }
1108         else if (FullerImplementation.NONE.equals(get(this.fullerImplementation, gtuType)))
1109         {
1110             mental = null;
1111             estimation = Estimation.NONE;
1112             anticipation = Anticipation.NONE;
1113         }
1114         else
1115         {
1116             // SUMMATIVE or ANTICIPATION_RELIANCE
1117             Set<ArTask> tasks = new LinkedHashSet<>();
1118             FullerImplementation fullerImpl = get(this.fullerImplementation, gtuType);
1119 
1120             // tasks
1121             if (get(this.carFollowingTask, gtuType))
1122             {
1123                 Throw.when(get(this.alternateCarFollowingTask, gtuType), IllegalStateException.class,
1124                         "Both carFollowingTask and alternateCarFollowingTask are true");
1125                 tasks.add(ArTaskCarFollowing.SINGLETON);
1126             }
1127             else if (get(this.alternateCarFollowingTask, gtuType))
1128             {
1129                 tasks.add(ArTaskCarFollowingExp.SINGLETON);
1130             }
1131             if (get(this.laneChangingTask, gtuType))
1132             {
1133                 Throw.when(get(this.alternateLaneChangingTask, gtuType), IllegalStateException.class,
1134                         "Both laneChangingTask and alternateLaneChangingTask are true");
1135                 tasks.add(ArTaskLaneChanging.SINGLETON);
1136             }
1137             else if (get(this.alternateLaneChangingTask, gtuType))
1138             {
1139                 tasks.add(ArTaskLaneChangingD.SINGLETON);
1140             }
1141             if (get(this.roadSideDistractionTask, gtuType))
1142             {
1143                 tasks.add(new ArTaskRoadSideDistraction(gtu));
1144             }
1145 
1146             // behavioral adaptation
1147             Set<BehavioralAdaptation> behavioralAdapatations = new LinkedHashSet<>();
1148             if (get(this.speedAdaptation, gtuType))
1149             {
1150                 behavioralAdapatations.add(new AdaptationSpeed());
1151             }
1152             if (get(this.headwayAdaptation, gtuType))
1153             {
1154                 behavioralAdapatations.add(new AdaptationHeadway());
1155             }
1156             if (get(this.laneChangeAdaptation, gtuType))
1157             {
1158                 behavioralAdapatations.add(AdaptationLaneChangeDesire.SINGLETON);
1159             }
1160             behavioralAdapatations.add(new AdaptationSituationalAwareness());
1161 
1162             // summative or anticipation reliance
1163             if (FullerImplementation.SUMMATIVE.equals(fullerImpl))
1164             {
1165                 mental = new SumFuller<>(tasks, behavioralAdapatations);
1166             }
1167             else if (FullerImplementation.ANTICIPATION_RELIANCE.equals(fullerImpl))
1168             {
1169                 mental = new ArFuller(tasks, behavioralAdapatations, get(this.primaryTask, gtuType));
1170             }
1171             else
1172             {
1173                 throw new IllegalArgumentException("Unable to load Fuller model from setting " + fullerImpl);
1174             }
1175 
1176             estimation = get(this.neighborEstimation, gtuType) ? FactorEstimation.SINGLETON : Estimation.NONE;
1177             anticipation = get(this.temporalAnticipation, gtuType) ? Anticipation.CONSTANT_SPEED : Anticipation.NONE;
1178         }
1179 
1180         // categories
1181         LanePerception perception = new CategoricalLanePerception(gtu, mental);
1182         perception.addPerceptionCategory(new DirectEgoPerception<>(perception));
1183         perception.addPerceptionCategory(new DirectInfrastructurePerception(perception));
1184         perception.addPerceptionCategory(new AnticipationTrafficPerception(perception));
1185         if (FullerImplementation.NONE.equals(get(this.fullerImplementation, gtuType)))
1186         {
1187             perception.addPerceptionCategory(new DirectNeighborsPerception(perception, PerceivedGtuType.WRAP));
1188             perception.addPerceptionCategory(new DirectIntersectionPerception(perception, PerceivedGtuType.WRAP));
1189         }
1190         else if (FullerImplementation.ATTENTION_MATRIX.equals(get(this.fullerImplementation, gtuType)))
1191         {
1192             perception.addPerceptionCategory(new NeighborsPerceptionChannel(perception, estimation, anticipation));
1193             perception.addPerceptionCategory(new IntersectionPerceptionChannel(perception, estimation, anticipation));
1194         }
1195         else
1196         {
1197             PerceivedGtuType headwayGtuType = new AnticipationPerceivedGtuType(estimation, anticipation, () ->
1198             {
1199                 return gtu.getParameters().getOptionalParameter(ParameterTypes.TR)
1200                         .orElseThrow(() -> new OtsRuntimeException("Unable to obtain reaction time parameter"));
1201             });
1202             perception.addPerceptionCategory(new DirectNeighborsPerception(perception, headwayGtuType));
1203             perception.addPerceptionCategory(new DirectIntersectionPerception(perception, headwayGtuType));
1204         }
1205         return perception;
1206     }
1207 
1208     /**
1209      * Add channel task if required.
1210      * @param taskSuppliers suppliers to add task suppliers to
1211      * @param task whether to add task
1212      * @param supplier supplier for the task
1213      */
1214     private void addChannelTask(final LinkedHashSet<Function<LanePerception, Set<ChannelTask>>> taskSuppliers,
1215             final boolean task, final Function<LanePerception, Set<ChannelTask>> supplier)
1216     {
1217         if (task)
1218         {
1219             taskSuppliers.add(supplier);
1220         }
1221     }
1222 
1223     // *************************************************************************************************************************
1224     // *********************************************** Nested Classes and Enums ************************************************
1225     // *************************************************************************************************************************
1226 
1227     /**
1228      * Provider for the correct tactical planner implementation.
1229      * @param <P> tactical planner class
1230      */
1231     public interface TacticalPlannerProvider<P extends AbstractIncentivesTacticalPlanner>
1232     {
1233         /**
1234          * Constructs an instance of the correct tactical planner class.
1235          * @param carFollowingModel car-following model
1236          * @param gtu GTU
1237          * @param lanePerception perception
1238          * @param synchronization type of synchronization
1239          * @param cooperation type of cooperation
1240          * @param gapAcceptance gap-acceptance
1241          * @param tailgating tailgating
1242          * @return instance of the correct tactical planner class
1243          */
1244         P from(CarFollowingModel carFollowingModel, LaneBasedGtu gtu, LanePerception lanePerception,
1245                 Synchronization synchronization, Cooperation cooperation, GapAcceptance gapAcceptance, Tailgating tailgating);
1246     }
1247 
1248     /**
1249      * Settings class with static instances.
1250      * @param <V> setting value type
1251      */
1252     public static final class Setting<V>
1253     {
1254         // LMRS
1255 
1256         /** Car-following model: IDM, IDM_PLUS (default) or IDM_PLUS_MULTI. */
1257         public static final Setting<BiFunction<DesiredHeadwayModel, DesiredSpeedModel, CarFollowingModel>> CAR_FOLLOWING_MODEL =
1258                 new Setting<>((factory) -> factory.carFollowingModel);
1259 
1260         /** Lane change synchronization: PASSIVE (default), PASSIVE_MOVING, ALIGN_GAP or ACTIVE. */
1261         public static final Setting<Synchronization> SYNCHRONIZATION = new Setting<>((factory) -> factory.synchronization);
1262 
1263         /** Lane change cooperation: PASSIVE (default), PASSIVE_MOVING or ACTIVE. */
1264         public static final Setting<Cooperation> COOPERATION = new Setting<>((factory) -> factory.cooperation);
1265 
1266         /** Lane change gap-acceptance: INFORMED (default) or EGO_HEADWAY. */
1267         public static final Setting<GapAcceptance> GAP_ACCEPTANCE = new Setting<>((factory) -> factory.gapAcceptance);
1268 
1269         // LMRS -> Mandatory incentives
1270 
1271         /** Mandatory lane change incentive for route (default: true). */
1272         public static final Setting<Boolean> INCENTIVE_ROUTE = new Setting<>((factory) -> factory.incentiveRoute);
1273 
1274         /** Mandatory lane change incentive to join slow traffic at split and not block other traffic (default: false). */
1275         public static final Setting<Boolean> INCENTIVE_GET_IN_LANE = new Setting<>((factory) -> factory.incentiveGetInLane);
1276 
1277         /** Custom mandatory lane change incentives. */
1278         public static final Setting<Set<Supplier<MandatoryIncentive>>> CUSTOM_MANDATORY_INCENTIVES =
1279                 new Setting<>((factory) -> factory.customMandatoryIncentives);
1280 
1281         // LMRS -> Voluntary incentives
1282 
1283         /** Voluntary lane change incentive for speed with courtesy (default: true). */
1284         public static final Setting<Boolean> INCENTIVE_SPEED_WITH_COURTESY =
1285                 new Setting<>((factory) -> factory.incentiveSpeedWithCourtesy);
1286 
1287         /** Voluntary lane change incentive for cooperative lane changes (default: false). */
1288         public static final Setting<Boolean> INCENTIVE_COURTESY = new Setting<>((factory) -> factory.incentiveCourtesy);
1289 
1290         /** Voluntary lane change incentive to join the shortest queue (default: false). */
1291         public static final Setting<Boolean> INCENTIVE_QUEUE = new Setting<>((factory) -> factory.incentiveQueue);
1292 
1293         /** Voluntary lane change incentive for trucks to stay in slowest rightmost two lanes (default: false). */
1294         public static final Setting<Boolean> INCENTIVE_STAY_ON_SLOW_LANES =
1295                 new Setting<>((factory) -> factory.incentiveStayRight);
1296 
1297         /** Voluntary lane change incentive to keep to the slow lane (default: true). */
1298         public static final Setting<Boolean> INCENTIVE_KEEP = new Setting<>((factory) -> factory.incentiveKeep);
1299 
1300         /** Custom voluntary lane change incentives. */
1301         public static final Setting<Set<Supplier<VoluntaryIncentive>>> CUSTOM_VOLUNTARY_INCENTIVES =
1302                 new Setting<>((factory) -> factory.customVoluntaryIncentives);
1303 
1304         // LMRS -> Acceleration incentives
1305 
1306         /** Acceleration incentive to slow down prior to a lower speed limit (default: false). */
1307         public static final Setting<Boolean> ACCELERATION_SPEED_LIMIT_TRANSITION =
1308                 new Setting<>((factory) -> factory.accelerationSpeedLimitTransition);
1309 
1310         /** Acceleration incentive to approach traffic lights (default: false). */
1311         public static final Setting<Boolean> ACCELERATION_TRAFFIC_LIGHTS =
1312                 new Setting<>((factory) -> factory.accelerationTrafficLights);
1313 
1314         /** Acceleration incentive to approach intersection conflicts (default: false). */
1315         public static final Setting<Boolean> ACCELERATION_CONFLICTS = new Setting<>((factory) -> factory.accelerationConflicts);
1316 
1317         /** Acceleration incentive to not overtake traffic in the left lane (default: false). */
1318         public static final Setting<Boolean> ACCELERATION_NO_SLOW_LANE_OVERTAKE =
1319                 new Setting<>((factory) -> factory.accelerationNoSlowLaneOvertake);
1320 
1321         /** Custom acceleration incentives. */
1322         public static final Setting<Set<Supplier<AccelerationIncentive>>> CUSTOM_ACCELERATION_INCENTIVES =
1323                 new Setting<>((factory) -> factory.customAccelerationIncentives);
1324 
1325         // Fuller
1326 
1327         /** Implementation of Fuller: NONE (default), SUMMATIVE, ANTICIPATION_RELIANCE or ATTENTION_MATRIX. */
1328         public static final Setting<FullerImplementation> FULLER_IMPLEMENTATION =
1329                 new Setting<>((factory) -> factory.fullerImplementation);
1330 
1331         /** ID of primary task under ANTICIPATION_RELIANCE (default: lane-changing). */
1332         public static final Setting<String> PRIMARY_TASK = new Setting<>((factory) -> factory.primaryTask);
1333 
1334         /** Enables temporal constant-speed anticipation (default: true). */
1335         public static final Setting<Boolean> TEMPORAL_ANTICIPATION = new Setting<>((factory) -> factory.temporalAnticipation);
1336 
1337         /** Enables estimation of neighboring vehicles. */
1338         public static final Setting<Boolean> ESTIMATION = new Setting<>((factory) -> factory.neighborEstimation);
1339 
1340         /** Fraction of drivers over-estimating speed and distance [0..1] (default: 0). */
1341         public static final Setting<Double> FRACTION_OVERESTIMATION =
1342                 new Setting<>((factory) -> factory.fractionOverEstimation);
1343 
1344         // Fuller -> Tasks
1345 
1346         /** Enables car-following task (default: true). */
1347         public static final Setting<Boolean> TASK_CAR_FOLLOWING = new Setting<>((factory) -> factory.carFollowingTask);
1348 
1349         /** Enables alternate car-following task (default: false). */
1350         public static final Setting<Boolean> TASK_CAR_FOLLOWING_ALTERNATE =
1351                 new Setting<>((factory) -> factory.alternateCarFollowingTask);
1352 
1353         /** Enables free acceleration task under ATTENTION_MATRIX (default: false). */
1354         public static final Setting<Boolean> TASK_FREE_ACCELERATION = new Setting<>((factory) -> factory.freeAccelerationTask);
1355 
1356         /** Enables traffic lights task under ATTENTION_MATRIX (default: false). */
1357         public static final Setting<Boolean> TASK_TRAFFIC_LIGHTS = new Setting<>((factory) -> factory.trafficLightsTask);
1358 
1359         /** Enables signal task under ATTENTION_MATRIX (default: true). */
1360         public static final Setting<Boolean> TASK_SIGNAL = new Setting<>((factory) -> factory.signalTask);
1361 
1362         /** Enables lane-changing task (default: true). */
1363         public static final Setting<Boolean> TASK_LANE_CHANGE = new Setting<>((factory) -> factory.laneChangingTask);
1364 
1365         /** Enables alternate lane-changing task (default: false). */
1366         public static final Setting<Boolean> TASK_LANE_CHANGE_ALTERNATE =
1367                 new Setting<>((factory) -> factory.alternateLaneChangingTask);
1368 
1369         /** Enables cooperation task under ATTENTION_MATRIX (default: true). */
1370         public static final Setting<Boolean> TASK_COOPERATION = new Setting<>((factory) -> factory.cooperationTask);
1371 
1372         /** Enables intersection task under ATTENTION_MATRIX (default: false). */
1373         public static final Setting<Boolean> TASK_INTERSECTION = new Setting<>((factory) -> factory.intersectionTask);
1374 
1375         /** Enables road-side distraction task (default: false). */
1376         public static final Setting<Boolean> TASK_ROADSIDE_DISTRACTION =
1377                 new Setting<>((factory) -> factory.roadSideDistractionTask);
1378 
1379         // Fuller -> Adaptations
1380 
1381         /** Enables behavioral speed adaptation (default: true). */
1382         public static final Setting<Boolean> ADAPTATION_SPEED = new Setting<>((factory) -> factory.speedAdaptation);
1383 
1384         /** Enables behavioral headway adaptation (default: true). */
1385         public static final Setting<Boolean> ADAPTATION_HEADWAY = new Setting<>((factory) -> factory.headwayAdaptation);
1386 
1387         /** Enables behavioral voluntary lane change adaptation (default: false). */
1388         public static final Setting<Boolean> ADAPTATION_LANE_CHANGE = new Setting<>((factory) -> factory.laneChangeAdaptation);
1389 
1390         /** Enables behavioral update time adaptation under ATTENTION_MATRIX (default: false). */
1391         public static final Setting<Boolean> ADAPTATION_UPDATE_TIME = new Setting<>((factory) -> factory.updateTimeAdaptation);
1392 
1393         // Social interactions
1394 
1395         /** Enables social pressure exerted to the (potential) leader (default: false). */
1396         public static final Setting<Boolean> SOCIO_PRESSURE = new Setting<>((factory) -> factory.socialPressure);
1397 
1398         /** Enables tailgating due to social pressure towards the leader (default: false). */
1399         public static final Setting<Boolean> SOCIO_TAILGATING = new Setting<>((factory) -> factory.tailgating);
1400 
1401         /** Enables lane changes due to social pressure from the (potential) follower (default: false). */
1402         public static final Setting<Boolean> SOCIO_LANE_CHANGE = new Setting<>((factory) -> factory.socioLaneChange);
1403 
1404         /** Enables speed increase due to social pressure from the follower (default: false). */
1405         public static final Setting<Boolean> SOCIO_SPEED = new Setting<>((factory) -> factory.socioSpeed);
1406 
1407         /** Function to return the right list. */
1408         private final Function<LmrsFactory<?>, List<V>> listFunction;
1409 
1410         /**
1411          * Constructor.
1412          * @param listFunction function to return the right list from the factory
1413          */
1414         private Setting(final Function<LmrsFactory<?>, List<V>> listFunction)
1415         {
1416             this.listFunction = listFunction;
1417         }
1418 
1419         /**
1420          * Returns the list function to return the right list from the factory.
1421          * @return list function to return the right list from the factory
1422          */
1423         public Function<LmrsFactory<?>, List<V>> getListFunction()
1424         {
1425             return this.listFunction;
1426         }
1427     }
1428 
1429     /**
1430      * Type of management of different tasks.
1431      */
1432     public enum FullerImplementation
1433     {
1434         /** No perception model. */
1435         NONE,
1436 
1437         /** Task demands are summed. */
1438         SUMMATIVE,
1439 
1440         /**
1441          * Task demand based on one primary and multiple auxiliary tasks. Requires parameters ALPHA and BETA and the id of the
1442          * primary task.
1443          */
1444         ANTICIPATION_RELIANCE,
1445 
1446         /** Task demand as steady-state in the attention matrix. */
1447         ATTENTION_MATRIX;
1448     }
1449 
1450     /**
1451      * Argument converter for car-following supplier.
1452      */
1453     public static class CarFollowingModelConverter
1454             implements ITypeConverter<BiFunction<DesiredHeadwayModel, DesiredSpeedModel, CarFollowingModel>>
1455     {
1456         /**
1457          * Constructor.
1458          */
1459         public CarFollowingModelConverter()
1460         {
1461             //
1462         }
1463 
1464         @Override
1465         public BiFunction<DesiredHeadwayModel, DesiredSpeedModel, CarFollowingModel> convert(final String value)
1466                 throws Exception
1467         {
1468             return switch (value.toLowerCase())
1469             {
1470                 case "idm" -> Idm::new;
1471                 case "idm_plus" -> IdmPlus::new;
1472                 case "idm_plus_multi" -> IdmPlusMultiFunction.SINGLETON;
1473                 default -> throw new IllegalArgumentException(
1474                         "Unable to parse car following model " + value + ". Use any of IDM, IDM_PLUS or IDM_PLUS_MULTI.");
1475             };
1476         }
1477     }
1478 
1479     /**
1480      * Recognition interface to add nLeaders parameter.
1481      */
1482     public static final class IdmPlusMultiFunction
1483             implements BiFunction<DesiredHeadwayModel, DesiredSpeedModel, CarFollowingModel>, Stateless<IdmPlusMultiFunction>
1484     {
1485         /** Singleton instance. */
1486         public static final IdmPlusMultiFunction SINGLETON = new IdmPlusMultiFunction();
1487 
1488         @Override
1489         public CarFollowingModel apply(final DesiredHeadwayModel t, final DesiredSpeedModel u)
1490         {
1491             return new IdmPlusMulti(t, u);
1492         }
1493 
1494         @Override
1495         public IdmPlusMultiFunction get()
1496         {
1497             return SINGLETON;
1498         }
1499     }
1500 
1501     /**
1502      * Argument converter for {@link Synchronization}.
1503      */
1504     public static class SynchronizationConverter implements ITypeConverter<Synchronization>
1505     {
1506         /**
1507          * Constructor.
1508          */
1509         public SynchronizationConverter()
1510         {
1511             //
1512         }
1513 
1514         @Override
1515         public Synchronization convert(final String value) throws Exception
1516         {
1517             switch (value.toLowerCase())
1518             {
1519                 case "passive":
1520                     return Synchronization.PASSIVE;
1521                 case "passive_moving":
1522                     return Synchronization.PASSIVE_MOVING;
1523                 case "align_gap":
1524                     return Synchronization.ALIGN_GAP;
1525                 case "active":
1526                     return Synchronization.ACTIVE;
1527                 default:
1528                     throw new IllegalArgumentException("Unable to parse synchronization " + value
1529                             + ". Use any of PASSIVE, PASSIVE_MOVING, ALIGN_GAP or ACTIVE.");
1530             }
1531         }
1532     }
1533 
1534     /**
1535      * Argument converter for {@link Cooperation}.
1536      */
1537     public static class CooperationConverter implements ITypeConverter<Cooperation>
1538     {
1539         /**
1540          * Constructor.
1541          */
1542         public CooperationConverter()
1543         {
1544             //
1545         }
1546 
1547         @Override
1548         public Cooperation convert(final String value) throws Exception
1549         {
1550             switch (value.toLowerCase())
1551             {
1552                 case "passive":
1553                     return Cooperation.PASSIVE;
1554                 case "passive_moving":
1555                     return Cooperation.PASSIVE_MOVING;
1556                 case "active":
1557                     return Cooperation.ACTIVE;
1558                 default:
1559                     throw new IllegalArgumentException(
1560                             "Unable to parse cooperation " + value + ". Use any of PASSIVE, PASSIVE_MOVING or ACTIVE.");
1561             }
1562         }
1563     }
1564 
1565     /**
1566      * Argument converter for {@link GapAcceptance}.
1567      */
1568     public static class GapAcceptanceConverter implements ITypeConverter<GapAcceptance>
1569     {
1570         /**
1571          * Constructor.
1572          */
1573         public GapAcceptanceConverter()
1574         {
1575             //
1576         }
1577 
1578         @Override
1579         public GapAcceptance convert(final String value) throws Exception
1580         {
1581             switch (value.toLowerCase())
1582             {
1583                 case "informed":
1584                     return GapAcceptance.INFORMED;
1585                 case "ego_headway":
1586                     return GapAcceptance.EGO_HEADWAY;
1587                 default:
1588                     throw new IllegalArgumentException(
1589                             "Unable to parse gap-acceptance " + value + ". Use any of INFORMED or EGO_HEADWAY.");
1590             }
1591         }
1592     }
1593 
1594 }