Skip to content

Agent

This class constructs and represents an agent within the population

Source code in titan/agent.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
class Agent:
    """
    This class constructs and represents an agent within the population
    """

    # class variable for agent creation
    next_agent_id = 0

    @classmethod
    def update_id_counter(cls, last_id):
        cls.next_agent_id = last_id + 1

    def __init__(
        self,
        sex_type: str,
        age: int,
        race: str,
        drug_use: str,
        location: Location,
        id: Optional[int] = None,
    ) -> None:
        """
        Initialize an agent based on given properties

        Args:
            id: Unique agent ID
            sex_type: Name of defined sex type (e.g. MSM) [params.classes.sex_types]
            age: Agents initialization age
            race: Race of agent [params.classes.races]
            drug_use: Drug use flag [params.classes.drug_types]
        """
        # self.id is unique ID number used to track each person agent.
        if id is not None:
            self.id = id
        else:
            self.id = self.next_agent_id

        self.update_id_counter(self.id)

        # agent properties
        self.sex_type = sex_type
        self.age = age
        self.race = race
        self.drug_type = drug_use
        self.location = location
        self.component = "-1"  # updated after relationships created

        self.sex_role = "versatile"

        # agent-partner params
        self.relationships: Set[Relationship] = set()
        self.partners: Dict[str, Set] = {}
        self.mean_num_partners: Dict[str, int] = {}
        self.target_partners: Dict[str, int] = {}

        # agent exposures params
        # model features
        for exposure in exposures.BaseExposure.__subclasses__():
            setattr(self, exposure.name, exposure(self))

        # model features
        for feature in features.BaseFeature.__subclasses__():
            setattr(self, feature.name, feature(self))

    def __str__(self) -> str:
        """
        String formatting of agent object

        returns:
            String formatted tab-deliminated agent properties
        """
        return (
            f"\t{self.id}\t{self.age}\t{self.sex_type}\t{self.drug_type}\t"  # type: ignore[attr-defined]
            f"{self.race}\t{self.hiv.active}\t{self.prep.active}"  # type: ignore[attr-defined]
        )

    def __repr__(self) -> str:
        """
        Repr formatting of agent object

        returns:
            agent ID as str
        """
        return str(self.id)

    def __eq__(self, other) -> bool:
        return self.id == other.id

    def __ne__(self, other) -> bool:
        return self.id != other.id

    def __hash__(self) -> int:
        return self.id

    @property
    def age_bin(self):
        for key, val in self.location.params.classes.age_bins.items():
            if self.age >= val.min_age and self.age <= val.max_age:
                return key
        raise ValueError(
            f"Agent age ({self.age}) must be within an age bin [params.classes.age_bins]"
        )

    def iter_partners(self) -> Iterator["Agent"]:
        """
        Get an iterator over an agent's partners

        returns:
            iterator of agent partners
        """
        for partner_set in self.partners.values():
            for partner in partner_set:
                yield partner

    def has_partners(self) -> bool:
        """
        Determine whether an agent has any partners

        returns:
            whether an agent has at least one partner
        """
        return any(self.iter_partners())

    def is_msm(self) -> bool:
        """
        Determine whether an agent is a man who can have sex with men

        returns:
            if agent is MSM
        """
        sex_dict = self.location.params.classes.sex_types
        if sex_dict[self.sex_type].gender != "M":
            return False

        for sex_type in sex_dict[self.sex_type].sleeps_with:
            if sex_dict[sex_type].gender == "M":
                return True
        return False

    def get_partners(self, bond_types: Optional[Iterable[str]] = None) -> Set["Agent"]:
        """
        Get all of an agents partners or those with specific bond types

        args:
            bond_types: list of bond types which will filter the partners, otherwise all partners returned

        returns:
            set of agent's partners
        """
        if bond_types:
            partners = set()
            for bond in bond_types:
                partners.update(self.partners[bond])
        else:
            partners = {partner for partner in self.iter_partners()}

        return partners

    def get_num_partners(self, bond_types: Optional[Iterable[str]] = None) -> int:
        """
        Get the number of partners an agent has, optionally filtered by bond type

        args:
            bond_types: list of bond types which will filter the partners, otherwise total number of partners returned

        returns:
            the number of partners the agent has
        """
        return len(self.get_partners(bond_types))

__init__(sex_type, age, race, drug_use, location, id=None)

Initialize an agent based on given properties

Parameters:

Name Type Description Default
id Optional[int]

Unique agent ID

None
sex_type str

Name of defined sex type (e.g. MSM) [params.classes.sex_types]

required
age int

Agents initialization age

required
race str

Race of agent [params.classes.races]

required
drug_use str

Drug use flag [params.classes.drug_types]

required
Source code in titan/agent.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def __init__(
    self,
    sex_type: str,
    age: int,
    race: str,
    drug_use: str,
    location: Location,
    id: Optional[int] = None,
) -> None:
    """
    Initialize an agent based on given properties

    Args:
        id: Unique agent ID
        sex_type: Name of defined sex type (e.g. MSM) [params.classes.sex_types]
        age: Agents initialization age
        race: Race of agent [params.classes.races]
        drug_use: Drug use flag [params.classes.drug_types]
    """
    # self.id is unique ID number used to track each person agent.
    if id is not None:
        self.id = id
    else:
        self.id = self.next_agent_id

    self.update_id_counter(self.id)

    # agent properties
    self.sex_type = sex_type
    self.age = age
    self.race = race
    self.drug_type = drug_use
    self.location = location
    self.component = "-1"  # updated after relationships created

    self.sex_role = "versatile"

    # agent-partner params
    self.relationships: Set[Relationship] = set()
    self.partners: Dict[str, Set] = {}
    self.mean_num_partners: Dict[str, int] = {}
    self.target_partners: Dict[str, int] = {}

    # agent exposures params
    # model features
    for exposure in exposures.BaseExposure.__subclasses__():
        setattr(self, exposure.name, exposure(self))

    # model features
    for feature in features.BaseFeature.__subclasses__():
        setattr(self, feature.name, feature(self))

__repr__()

Repr formatting of agent object

Returns:

Type Description
str

agent ID as str

Source code in titan/agent.py
 94
 95
 96
 97
 98
 99
100
101
def __repr__(self) -> str:
    """
    Repr formatting of agent object

    returns:
        agent ID as str
    """
    return str(self.id)

__str__()

String formatting of agent object

Returns:

Type Description
str

String formatted tab-deliminated agent properties

Source code in titan/agent.py
82
83
84
85
86
87
88
89
90
91
92
def __str__(self) -> str:
    """
    String formatting of agent object

    returns:
        String formatted tab-deliminated agent properties
    """
    return (
        f"\t{self.id}\t{self.age}\t{self.sex_type}\t{self.drug_type}\t"  # type: ignore[attr-defined]
        f"{self.race}\t{self.hiv.active}\t{self.prep.active}"  # type: ignore[attr-defined]
    )

get_num_partners(bond_types=None)

Get the number of partners an agent has, optionally filtered by bond type

Parameters:

Name Type Description Default
bond_types Optional[Iterable[str]]

list of bond types which will filter the partners, otherwise total number of partners returned

None

Returns:

Type Description
int

the number of partners the agent has

Source code in titan/agent.py
176
177
178
179
180
181
182
183
184
185
186
def get_num_partners(self, bond_types: Optional[Iterable[str]] = None) -> int:
    """
    Get the number of partners an agent has, optionally filtered by bond type

    args:
        bond_types: list of bond types which will filter the partners, otherwise total number of partners returned

    returns:
        the number of partners the agent has
    """
    return len(self.get_partners(bond_types))

get_partners(bond_types=None)

Get all of an agents partners or those with specific bond types

Parameters:

Name Type Description Default
bond_types Optional[Iterable[str]]

list of bond types which will filter the partners, otherwise all partners returned

None

Returns:

Type Description
Set[Agent]

set of agent's partners

Source code in titan/agent.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def get_partners(self, bond_types: Optional[Iterable[str]] = None) -> Set["Agent"]:
    """
    Get all of an agents partners or those with specific bond types

    args:
        bond_types: list of bond types which will filter the partners, otherwise all partners returned

    returns:
        set of agent's partners
    """
    if bond_types:
        partners = set()
        for bond in bond_types:
            partners.update(self.partners[bond])
    else:
        partners = {partner for partner in self.iter_partners()}

    return partners

has_partners()

Determine whether an agent has any partners

Returns:

Type Description
bool

whether an agent has at least one partner

Source code in titan/agent.py
132
133
134
135
136
137
138
139
def has_partners(self) -> bool:
    """
    Determine whether an agent has any partners

    returns:
        whether an agent has at least one partner
    """
    return any(self.iter_partners())

is_msm()

Determine whether an agent is a man who can have sex with men

Returns:

Type Description
bool

if agent is MSM

Source code in titan/agent.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def is_msm(self) -> bool:
    """
    Determine whether an agent is a man who can have sex with men

    returns:
        if agent is MSM
    """
    sex_dict = self.location.params.classes.sex_types
    if sex_dict[self.sex_type].gender != "M":
        return False

    for sex_type in sex_dict[self.sex_type].sleeps_with:
        if sex_dict[sex_type].gender == "M":
            return True
    return False

iter_partners()

Get an iterator over an agent's partners

Returns:

Type Description
Iterator[Agent]

iterator of agent partners

Source code in titan/agent.py
121
122
123
124
125
126
127
128
129
130
def iter_partners(self) -> Iterator["Agent"]:
    """
    Get an iterator over an agent's partners

    returns:
        iterator of agent partners
    """
    for partner_set in self.partners.values():
        for partner in partner_set:
            yield partner