Coverage for src/scicom/randomletters/agents.py: 0%

1 import mesa

2 import numpy as np

3

4

5 class LetterAgent(mesa.Agent):

6 """An agent with fixed initial start position.

7

8 Each agent has a personal topic vector representing

9 the shares the agent has of topics 1 to 10 with values

10 between 0 and 1.

11 Each agent has two different ranges, moveRange for deciding

12 to move to another agents position, and letterRange to find

13 potential correspondence partners. In addition a threshold

14 value determines the necessary similarity between topic vectors

15 to send a letter or not.

16

17 Received and send letters are kept track of with two additional

18 internal variables.

19 """

20

21 def __init__(

22 self,

23 unique_id,

24 model,

25 pos,

26 topicVec,

27 updateTopic,

28 moveRange,

29 letterRange,

30 minSep,

31 threshold

32 ):

33 """Create letter with position, topic vector and parameters."""

34 super().__init__(unique_id, model)

35 self.pos = np.array(pos)

36 self.topicVec = topicVec

37 self.updateTopic = updateTopic

38 self.threshold = threshold

39 self.moveRange = moveRange

40 self.letterRange = letterRange

41 self.topicLedger = []

42 self.lettersReceived = []

43 self.numLettersReceived = 0

44 self.lettersSend = []

45 self.numLettersSend = 0

46

47 def move(self, neighbors):

48 """The agent can randomly move to neighboring positions."""

49 if neighbors:

50 weights = []

51 possible_steps = []

52 for n in neighbors:

53 possible_steps.append(n.pos)

54 weights.append(n.lettersReceived)

55 move = np.random.choice([0, 0, 0, 0, 0, 0, 0, 1])

56 if move == 1:

57 new_position = self.random.choice(possible_steps)

58 self.model.space.move_agent(self, new_position)

59

60 def sendLetter(self, neighbors):

61 """Sending a letter based on an urn model."""

62 possibleRec = []

63 senders = self.lettersReceived

64 receivers = self.lettersSend

65 possibleRec.extend(senders)

66 possibleRec.extend(receivers)

67 if neighbors:

68 neighborRec = []

69 for n in neighbors:

70 if n.numLettersReceived > 0:

71 nMult = [n.unique_id] * n.numLettersReceived

72 neighborRec.extend(nMult)

73 else:

74 neighborRec.append(n.unique_id)

75 possibleRec.extend(neighborRec)

76 if possibleRec:

77 recipientNr = np.random.choice(possibleRec)

78 recipient = self.model.schedule.agents[recipientNr]

79 topicChoices = self.topicLedger.copy()

80 topicChoices.extend(recipient.topicLedger.copy())

81 if topicChoices:

82 randix = np.random.choice(list(range(len(topicChoices))))

83 initTopic = topicChoices[randix]

84 else:

85 initTopic = self.topicVec

86 distance = np.linalg.norm(recipient.topicVec - initTopic)

87 if distance < self.threshold:

88 recipient.numLettersReceived += 1

89 recipient.lettersReceived.append(self.unique_id)

90 self.numLettersSend += 1

91 self.lettersSend.append(recipient.unique_id)

92 # Update model social network

93 self.model.G.add_edge(self.unique_id, recipient.unique_id)

94 self.model.G.nodes()[self.unique_id]['numLettersSend'] = self.numLettersSend

95 self.model.G.nodes()[recipient.unique_id]['numLettersReceived'] = recipient.numLettersReceived

96 # Update agents topic vector

97 updateTopicVec = self.topicVec + self.updateTopic * np.random.uniform(0, 1) * (recipient.topicVec - self.topicVec)

98 self.model.letterLedger.append(

99 (self.unique_id, recipient.unique_id, self.pos, recipient.pos, updateTopicVec, self.model.schedule.steps)

100 )

101 self.topicLedger.append(

102 self.topicVec

103 )

104 self.topicVec = updateTopicVec

105

106 def step(self):

107 neighborsMove = self.model.space.get_neighbors(self.pos, self.moveRange, False)

108 neighborsSend = self.model.space.get_neighbors(self.pos, self.letterRange, False)

109 self.sendLetter(neighborsSend)

110 self.move(neighborsMove)

111

112

113 class LetterNode(mesa.Agent):

114 """An agent representing the network node.

115

116 Only necessary for visualization purposes.

117 """

118

119 def __init__(

120 self,

121 unique_id,

122 model,

123 topicVec

124 ):

125 """Create letter with position, topic vector and parameters."""

126 super().__init__(unique_id, model)

127 self.topicVec = topicVec

128 self.lettersReceived = 0

129 self.lettersSend = 0