Objectives: The goal here is to complete the coding for single-flagellated bacteria by enabling them to detect nutrients, divide, and mutate.
With the movement mode you coded in the previous step, a single-flagellated bacterium moves only straight ahead. It can only rely on pure chance (nutrients on its path) to feed itself while moving. If there are few nutrient sources, its chances of survival are low.
We will now improve this model by making the bacterium sensitive to a nutrient concentration gradient.
Instead of modeling thousands of small particles emitted by a nutrient source, we will assume that there is a nutrient concentration gradient proportional to the distance from the center of the source. Single-flagellated bacteria will perceive this gradient, which may cause them to change direction and influence their movement.
The perception of the gradient from a given position p is determined by calculating a score associated with p.
The score of p relative to a nutrient source s is calculated as:
score(p) = taille(s) / (distance(p,centre(s))puissance
If there are multiple nutrient sources, the score for p will be the sum of the scores for each nutrient source.
Thus, the score will be higher the closer one is to more numerous or larger nutrient sources.
Start by adding a method getPositionScore(const Vec2d&) to Laboratory that returns the score for a given position.
[Question Q4.1] How should you modify CultureDish to implement this functionality ? Answer this question in your file REPONSES and then implement the suggested features.
The power attribute is one of the elements intended to be controllable via the graphical interface. This is the "Gradient exponent" parameter, which is displayed in the graphical interface below "Temperature".
You will therefore proceed in the same way as you did for temperatures : add the methods increaseGradientExponent(), decreaseGradientExponent() and getGradientExponent() in the appropriate locations. You will also have to call these methods appropriately in Application.cpp. Finally, remember to adapt the handling of the 'C' key (when the configuration file is reloaded, you must recalculate power, following the same procedure as during construction).
To improve its chances of accessing nutrients, a single-flagellated bacterium will attempt to tilt (at regular intervals) to change its direction of movement.
The initial probability of tilting is a property of the bacterium. This probability will change based on the perception of the gradient (i.e., the score): the higher this perception, the lower the probability of switching will become.
Thus, if the bacterium moves in a direction leading to nutrients, it will have less and less chance of switching. Conversely, if its perception of the gradient weakens, its chances of switching will increase.
ou are now asked to complete the movement method of the single-flagellated bacterium so that, following the existing steps, there is :
Here is a very simple version, which you can improve later :
Let previous_score be the bacterium's score during the previous simulation step and score its current score.
The probability p of switching is calculated according to an exponential growth law:
p = 1 - exp(-t/lambda)where t is the time elapsed since the last flip and lambda is the weight associated with the deterioration or improvement of the score.
This function ensures that the probability of switching is greater the longer the time elapsed between two switches and the more the score has deteriorated between two movements of the bacterium.
[Question Q4.2] What attributes do you suggest adding to the representation of bacteria (monotrichous or generic) to enable the implementation of this algorithm? How should these attributes be initialized, and where should they be updated ?
Explain and justify your choices in your file REPONSES.
Multiple variants are possible:
To allow you to experiment with different variations, you can use the values associated with ["tumble"]["algo"] in the configuration file.
For example, if the value associated with these tags is "single random vector" execute strategy 1 above; if the value is "best of N" choose the second one, and so on.
For strategy 1, simply calling this function once is sufficient to implement the change in direction.
For strategy 2, we generate N (for example, 20) and select the one such that the Vec2D with coordinates bacteria_position + random_direction has the highest score.
You are asked to code the two first strategies, as mentioned above.
Now integrate the direction change into the movement of the single-flagellated bacterium.
We will now discuss the final features related to bacteria in general, namely division and mutation. For simplicity, we assume that all bacteria can divide and mutate in ways that can be considered the same for all of them. During division, the bacterium splits to produce another identical bacterium (method Bacterium* clone());
The mutation method for a bacterium (regardless of its type) simply consists of calling the mutation method on each of its mutable parameters. This may result in actual mutations of certain parameters (but not necessarily).
[Question Q4.3] In which class do you propose adding the mutation method ? Explain and justify your choice in your REPONSES file.
You will assume that a single-flagellated bacterium has the following mutable properties :
To implement the management of mutable properties, you will start by adding the methods addProperty(const string&, MutableNumber) and getProperty(const string&) to your bacteria class hierarchy, allowing you to add a given mutable numeric value to the set of mutable numeric parameters of the bacterium or to retrieve a mutable value associated with a given key.
[Question Q4.4] In which class do you propose adding these methods ? Explain and justify your choice in your REPONSES file and implement the suggested methods.
auto paire = une_map.find(key);If no entry has the key key, then pair will contain the value a_map.end() (we will look at all this in detail in our course on the standard library).
Modify the constructor of the MonotrichousBacterium class so that it adds the desired mutable parameters as follows:
The division method is the same for all bacteria :
The clone method must therefore create a polymorphic copy. The exercise 1 in Series 21 provides guidance on this.
[Question Q4.5] Where do you choose to place the method for dividing a bacterium ? Answer this question in your REPONSES file, justifying your choice.
Now complete the Bacterium::update method so that, after the collision test with the nutrients, the division method is called (which will call the mutation method).
We saw in the previous step that modifying the size of a collection whilst iterating over it is potentially problematic. In the previous step, the risk was linked to the removal of dead or exhausted elements. We have the same problem now, but due to the addition of new bacteria during cloning.
To avoid this problem, we suggest that you first store the bacteria created by cloning in a separate vector (class attribute). You can then merge this vector with the collection of bacteria before iterating over it. This way, all the bacteria obtained by cloning during the previous simulation step can be incorporated into the simulation.
The append function provided in Utility.hpp allows you to add the contents of one vector to another (for example, append(v1, v2) adds all the elements of v1 to v2 by inserting them in order at the end of v2).
You should see the populations grow and decline: the population grows because the bacteria divide. They sometimes become too numerous for the available nutrients, and the population then declines. After a while, colour mutations should become observable:
|
← Here, the simulation is based on this content from the file app.json (the file app_original.json corresponds to the data originally provided in the archive, should you wish to restore this content) |
Here, you can only visually test how the colour changes. As the project progresses, you will add the plotting of trend lines for certain parameters to your programme, making it easier to observe how the variable parameters change.