Calling a more generic method with Parametric Types

rmellema
Sun, 29 Oct 2023 14:13:07 +0000
General Usage

Hey all,

For some context, I want to do some work with the Agents.jl package in which I want to try to keep track of the movement of the agents (so I can draw their paths and manipulate them later). The easiest way I think I can make this work is by writing a more specific agent type, with a specific move_agent! method, and then use invoke to call the more generic move_agent! methods that Agents.jl provides. The problem that I’m running into though is that I cannot get the invoke call which I think has to do with the way that parametric types work in Julia.

What I have right now is that I wrote a method with signature move_agent!(::T, ::Agents.ValidPos, ::ABM{S, T}) where {S <: ContinuousSpace, T <: AbstractTurtle}. Now I want to call the method with signature move_agent!(::A, ::Agents.ValidPos, ::ABM{<:ContinuousSpace{D}, A}) where {D, A <: AbstractAgent}. Now we have that Turtle <: AbstractTurtle <: AbstractAgent, but the problem (I think) is that ABM{ContinuousSpace{2}, AbstractTurtle} <: ABM{ContinuousSpace{2}, AbstractAgent} does not hold. This causes invoke to give the error “argument type error”. However, if I make the type in the invoke call more general it becomes ambiguous.

Is there a solution out of this problem, am I just using invoke wrong, or is what I’m trying to do just impossible given the current type system and constraints? Copying the current definition of move_agent!(::A, ::Agents.ValidPos, ::ABM{<:ContinuousSpace{D}, A}) where {D, A <: AbstractAgent} into move_agent!(::T, ::Agents.ValidPos, ::ABM{S, T}) where {S <: ContinuousSpace, T <: AbstractTurtle} will of course work but a less brittle solution would have my preference.

The code that I have at the moment only depends on Agents.jl being installed and is:

using Agents

abstract type AbstractTurtle <: AbstractAgent end

@agent Turtle ContinuousAgent{2} AbstractTurtle begin end

function Agents.move_agent!(turtle::T, pos::Agents.ValidPos, model::ABM{S, T}) where {T <: AbstractTurtle, S <: ContinuousSpace}
    start = turtle.pos
    @invoke move_agent!(turtle::AbstractAgent, pos, model::ABM{S, AbstractAgent})
    println("Turtle started at $start, ended at $(turtle.pos)")
end

model = AgentBasedModel(Turtle, ContinuousSpace((50, 50)))
agent = add_agent!(model, (1, 0))
move_agent!(agent, (1,1), model)

Julia version: 1.9.3
Agents.jl version: 5.17.1

11 posts - 4 participants