diff --git a/predator_prey_generic.jl b/predator_prey_generic.jl index 3ed0548..189ea17 100644 --- a/predator_prey_generic.jl +++ b/predator_prey_generic.jl @@ -15,6 +15,10 @@ mutable struct AnimalDefinition dangers::Vector{String} food::Vector{String} end +reproduction_prop(a) = abmproperties(model)[Symbol(a.def.type*"_"*"reproduction_prob")] +Δenergy(a) = abmproperties(model)[Symbol(a.def.type*"_"*"Δenergy")] +perception(a) = abmproperties(model)[Symbol(a.def.type*"_"*"perception")] +energy_threshold(a) = abmproperties(model)[Symbol(a.def.type*"_"*"energy_threshold")] struct StartDefinition n::Int32 def::AnimalDefinition @@ -30,8 +34,8 @@ end function perceive!(a::Animal,model) - if a.def.perception > 0 - nearby = collect(nearby_agents(a, model, a.def.perception)) + if perception(a) > 0 + nearby = collect(nearby_agents(a, model, perception(a))) a.nearby_dangers = map(x -> x.pos, filter(x -> isa(x, Animal) && x.def.type ∈ a.def.dangers && isnothing(x.death_cause), nearby)) a.nearby_food = map(x -> x.pos, filter(x -> isa(x, Animal) && x.def.type ∈ a.def.food && isnothing(x.death_cause), nearby)) if "Grass" ∈ a.def.food @@ -65,7 +69,7 @@ function calculate_best_pos(a::Animal,model) push!(danger_scores,danger_score) end if !isempty(a.nearby_food) - food_score = sum(map(food -> findmax(abs.(pos.-danger))[1], a.nearby_food)) + food_score = sum(map(food -> findmax(abs.(pos.-food))[1], a.nearby_food)) push!(food_scores,food_score) end end @@ -86,7 +90,7 @@ function eat!(a::Animal, model) if !isnothing(prey) #remove_agent!(dinner, model) prey.death_cause = Predation - a.energy += prey.def.Δenergy + a.energy += Δenergy(prey) end if "Grass" ∈ a.def.food && model.fully_grown[a.pos...] model.fully_grown[a.pos...] = false @@ -95,7 +99,7 @@ function eat!(a::Animal, model) return end function reproduce!(a::Animal, model) - if a.energy > a.def.energy_threshold && rand(abmrng(model)) ≤ a.def.reproduction_prob + if a.energy > energy_threshold(a) && rand(abmrng(model)) ≤ reproduction_prop(a)#a.def.reproduction_prob a.energy /= 2 replicate!(a, model) end @@ -122,7 +126,7 @@ function move_towards!(agent, pos, model; ifempty=true) walk!(agent,direction,model; ifempty=ifempty) end function nearby_fully_grown(a::Animal, model) - nearby_pos = nearby_positions(a.pos, model, a.def.perception) + nearby_pos = nearby_positions(a.pos, model, perception(a)) fully_grown_positions = filter(x -> model.fully_grown[x...], collect(nearby_pos)) return fully_grown_positions end @@ -165,19 +169,19 @@ function initialize_model(; ## Notice how the properties are a `NamedTuple` to ensure type stability. ## define as dictionary(mutable) instead of tuples(immutable) as per https://github.com/JuliaDynamics/Agents.jl/issues/727 ## maybe instead of AnimalDefinition we build the properties dict dynamically and use model properties during the simulation + animal_defs = Vector{AnimalDefinition}() + for start_def in start_defs + push!(animal_defs,start_def.def) + end + animal_properties = generate_animal_parameters(animal_defs) properties = Dict( :events => events, :fully_grown => falses(dims), :countdown => zeros(Int, dims), :regrowth_time => regrowth_time, - :Δenergy_sheep => Δenergy_sheep, - :Δenergy_wolf => Δenergy_wolf, :Δenergy_grass => Δenergy_grass, - :sheep_reproduce => sheep_reproduce, - :wolf_reproduce => wolf_reproduce, - :sheep_perception => sheep_perception, - :wolf_perception => wolf_perception ) + properties = merge(properties,animal_properties) model = StandardABM(Animal, space; agent_step! = animal_step!, model_step! = model_step!, properties, rng, scheduler = Schedulers.Randomly(), warn = false, agents_first = false @@ -317,6 +321,28 @@ function event_handler!(model) end end +function generate_animal_parameters(defs::Vector{AnimalDefinition}) + parameter_dict = Dict() + for def in defs + parameter_dict[Symbol(def.type*"_"*"Δenergy")]=def.Δenergy + parameter_dict[Symbol(def.type*"_"*"reproduction_prob")]=def.reproduction_prob + parameter_dict[Symbol(def.type*"_"*"perception")]=def.perception + parameter_dict[Symbol(def.type*"_"*"energy_threshold")]=def.energy_threshold + end + return parameter_dict +end + +function generate_animal_parameter_ranges(defs::Vector{AnimalDefinition}) + parameter_range_dict = Dict() + for def in defs + parameter_range_dict[Symbol(def.type*"_"*"Δenergy")]=0:1:100 + parameter_range_dict[Symbol(def.type*"_"*"reproduction_prob")]=0:0.01:1 + parameter_range_dict[Symbol(def.type*"_"*"perception")]=0:1:10 + parameter_range_dict[Symbol(def.type*"_"*"energy_threshold")]=0:1:100 + end + return parameter_range_dict +end + mutable struct RecurringEvent name::String diff --git a/test_predator_prey_generic.ipynb b/test_predator_prey_generic.ipynb index 417193f..217924a 100644 --- a/test_predator_prey_generic.ipynb +++ b/test_predator_prey_generic.ipynb @@ -9,7 +9,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/SCJ/Projekt/SCJ-PredatorPrey/env`\n" + "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/Studium/SCJ-PredatorPrey/env`\n", + "\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m project...\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mSpecialFunctions\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mColorVectorSpace → SpecialFunctionsExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mSpecialFunctions → SpecialFunctionsChainRulesCoreExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mDualNumbers\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mHypergeometricFunctions\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mStatsFuns\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mStatsFuns → StatsFunsInverseFunctionsExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mStatsFuns → StatsFunsChainRulesCoreExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mDistributions\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mDistributions → DistributionsTestExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mDistributions → DistributionsChainRulesCoreExt\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mKernelDensity\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mStreamSampling\u001b[39m\n", + "\u001b[32m ✓ \u001b[39mAgents\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mMakie\u001b[39m\n", + "\u001b[32m ✓ \u001b[39m\u001b[90mAgents → AgentsVisualizations\u001b[39m\n", + "\u001b[32m ✓ \u001b[39mAgentsExampleZoo\n", + "\u001b[32m ✓ \u001b[39mCairoMakie\n", + "\u001b[32m ✓ \u001b[39mGLMakie\n", + " 19 dependencies successfully precompiled in 272 seconds. 270 already precompiled.\n" ] } ], @@ -60,22 +81,12 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 23, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1mStatus\u001b[22m\u001b[39m `~/SCJ/Projekt/SCJ-PredatorPrey/env/Manifest.toml`\n", - " \u001b[90m[46ada45e] \u001b[39mAgents v6.0.13\n", - " \u001b[90m[e9467ef8] \u001b[39mGLMakie v0.10.2\n" - ] - } - ], + "outputs": [], "source": [ "include(\"./predator_prey_generic.jl\")\n", - "Pkg.status([\"Agents\",\"GLMakie\"]; mode = Pkg.Types.PKGMODE_MANIFEST, io=stdout)\n", + "#Pkg.status([\"Agents\",\"GLMakie\"]; mode = Pkg.Types.PKGMODE_MANIFEST, io=stdout)\n", "using GLMakie\n", "GLMakie.activate!()\n", "events = RecurringEvent[]\n", @@ -86,6 +97,7 @@ "sheep_def = AnimalDefinition('●',RGBAf(1.0, 1.0, 1.0, 0.8),20, 0.3, 20, 3, \"Sheep\", [\"Wolf\",\"Bear\"], [\"Grass\"])\n", "wolf_def = AnimalDefinition('▲',RGBAf(0.2, 0.2, 0.3, 0.8),20, 0.07, 20, 1, \"Wolf\", [], [\"Sheep\"])\n", "bear_def = AnimalDefinition('■',RGBAf(1.0, 0.8, 0.5, 0.8),20, 0.07, 20, 1, \"Bear\", [], [\"Sheep\"])\n", + "parameter_ranges = generate_animal_parameter_ranges([sheep_def,wolf_def,bear_def])\n", "\n", "stable_params = (;\n", " events = events,\n", @@ -100,7 +112,7 @@ " :regrowth_time => 0:1:100,\n", " :Δenergy_grass => 0:1:50,\n", ")\n", - "\n", + "params = merge(params,parameter_ranges)\n", "sheep(a) = a.def.type == \"Sheep\"\n", "wolf(a) = a.def.type == \"Wolf\"\n", "eaten(a) = a.def.type == \"Sheep\" && a.death_cause == Predation\n",