projectmesa/mesa

Document possible agent reporter inputs in the datacollector

EwoutH opened this issue · 8 comments

Currently in the data collector documentation its defined very well which inputs model reporters can take:

Notes:
If you want to pickle your model you must not use lambda functions.
If your model includes a large number of agents, you should *only*
use attribute names for the agent reporter, it will be much faster.
Model reporters can take four types of arguments:
lambda like above:
{"agent_count": lambda m: m.schedule.get_agent_count() }
method of a class/instance:
{"agent_count": self.get_agent_count} # self here is a class instance
{"agent_count": Model.get_agent_count} # Model here is a class
class attributes of a model
{"model_attribute": "model_attribute"}
functions with parameters that have placed in a list
{"Model_Function":[function, [param_1, param_2]]}
"""
self.model_reporters = {}
self.agent_reporters = {}

However, this isn't done for the agent reports. Could this documentation be added?

rht commented

I checked the code. I can't find any that implements

             functions with parameters that have placed in a list 
             {"Model_Function":[function, [param_1, param_2]]} 

in the latest main.

rht commented

I found it in

self.model_vars[var].append(reporter[0](*reporter[1]))
. Was added in 80511e2#diff-72396865b218fb20682afecba66d3b794e1306841d39490ed4037e26cba31b29L165. @tpike3 is the reason why you added the feature was for pickling issue in multiprocessing?

I would be fine with removing the "Functions with parameters placed in a list" behaviour by the way, as long as we keep the syntax for agent_reporters and model_reporters identical (and thus remove it from both).

rht commented

I agree with removing it in both agent and model reporters. I haven't compiled the list of breaking changes for Mesa 3.0 yet.

Then I would propose removing it for the agent-reporter immediately, and adding a deprecation warning to the model-reporter ASAP.

To summerize, we propose to remove method nr 4 as it's practically identical to nr 1.

Model reporters can take four types of arguments:
        1. Lambda function:
           {"agent_count": lambda m: m.schedule.get_agent_count()}
        2. Method of a class/instance:
           {"agent_count": self.get_agent_count} # self here is a class instance
           {"agent_count": Model.get_agent_count} # Model here is a class
        3. Class attributes of a model:
           {"model_attribute": "model_attribute"}
        4. Functions with parameters that have been placed in a list:
           {"Model_Function": [function, [param_1, param_2]]}

        Agent reporters can similarly take:
        1. Attribute name (string) referring to agent's attribute:
           {"energy": "energy"}
        2. Lambda function:
           {"energy": lambda a: a.energy}
        3. Method of an agent class/instance:
           {"agent_action": self.do_action} # self here is an agent class instance
           {"agent_action": Agent.do_action} # Agent here is a class
        4. Functions with parameters placed in a list:
           {"Agent_Function": [function, [param_1, param_2]]}

@tpike3 @jackiekazil @Corvince curious what you think.

Agree with removing #4, but I think #1 and #2 are also the same, unless I am missing something.

I would say removing #4 leaves us with two possibilities: either as an attribute string or a function-like object that takes either model or agent as its only argument. It shouldn't matter if it's a lambda type, class/instance method or normal function. Or am I missing something?

Got a question that's related to #4. If a function has extra parameters, how should it be used in reporters?

For example for agent reports

def some_func(agent, param_1, param_2):
    result = ... # do something with agent and parameters
    return result

should it be used like this

from functools import partial


agent_reporters = {
    "reported_value": partial(some_func, param_1=some_value, param_2=some_other_value)
}

I found it in

self.model_vars[var].append(reporter[0](*reporter[1]))

. Was added in 80511e2#diff-72396865b218fb20682afecba66d3b794e1306841d39490ed4037e26cba31b29L165. @tpike3 is the reason why you added the feature was for pickling issue in multiprocessing?

Sorry for the delay, but yes @rht reason was because of pickling issue for multiprocessing, so if I am understnading correctly removing option 4 would cause some issues with batch_run