File size: 4,969 Bytes
ba3f404
5f8887d
 
acb2712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5f8887d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ba3f404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
046ac0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
acb2712
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
from agents.rule_based import ConservativeAdapter, EqualSplitAdapter, GreedyAdapter, RandomAdapter
from schemas.actions import ActionType, VoteChoice
from schemas.observations import Observation, OwnDepartmentObservation, ProposalObservation
from schemas.phases import Phase


def test_greedy_adapter_requests_visible_treasury_for_own_department() -> None:
    observation = _proposal_observation(treasury=900.0, department="Defense")
    action = GreedyAdapter().act(
        observation=observation,
        valid_actions={"PROPOSE_BUDGET"},
        agent_id="Defense",
    )

    assert action.type is ActionType.PROPOSE_BUDGET
    assert action.department == "Defense"
    assert action.amount == 900.0


def test_equal_split_adapter_requests_one_department_share() -> None:
    observation = _proposal_observation(treasury=900.0, department="Health")
    action = EqualSplitAdapter(department_count=6).act(
        observation=observation,
        valid_actions={"PROPOSE_BUDGET"},
        agent_id="Health",
    )

    assert action.type is ActionType.PROPOSE_BUDGET
    assert action.department == "Health"
    assert action.amount == 150.0


def test_random_adapter_samples_legal_proposal_amount() -> None:
    observation = _proposal_observation(treasury=900.0, department="Health")
    action = RandomAdapter(seed=123).act(
        observation=observation,
        valid_actions={"PROPOSE_BUDGET"},
        agent_id="Health",
    )

    assert action.type is ActionType.PROPOSE_BUDGET
    assert action.department == "Health"
    assert 0.0 <= action.amount <= 900.0


def test_random_adapter_votes_only_on_other_departments_proposals() -> None:
    observation = Observation(
        round=1,
        phase=Phase.VOTING,
        treasury=900.0,
        own_department=OwnDepartmentObservation(name="Health"),
        proposals=(
            ProposalObservation(proposal_id="own", department="Health", amount=90.0),
            ProposalObservation(proposal_id="other", department="Defense", amount=100.0),
        ),
    )

    action = RandomAdapter(seed=1).act(
        observation=observation,
        valid_actions={"VOTE"},
        agent_id="Health",
    )

    assert action.type is ActionType.VOTE
    assert action.proposal_id == "other"
    assert action.vote in set(VoteChoice)


def test_random_adapter_vote_candidates_keep_each_proposal_id() -> None:
    observation = Observation(
        round=1,
        phase=Phase.VOTING,
        treasury=900.0,
        own_department=OwnDepartmentObservation(name="Health"),
        proposals=(
            ProposalObservation(proposal_id="defense", department="Defense", amount=100.0),
            ProposalObservation(proposal_id="education", department="Education", amount=120.0),
        ),
    )

    candidates = RandomAdapter(seed=1)._candidate_actions(
        observation=observation,
        valid_actions={"VOTE"},
        agent_id="Health",
    )

    proposal_ids = {candidate().proposal_id for candidate in candidates}
    assert proposal_ids == {"defense", "education"}


def test_rule_based_adapters_vote_on_other_pending_proposal() -> None:
    observation = Observation(
        round=1,
        phase=Phase.VOTING,
        treasury=900.0,
        own_department=OwnDepartmentObservation(name="Health"),
        proposals=(
            ProposalObservation(proposal_id="own", department="Health", amount=90.0),
            ProposalObservation(proposal_id="other", department="Defense", amount=100.0),
        ),
    )

    for adapter in (GreedyAdapter(), EqualSplitAdapter(), ConservativeAdapter()):
        action = adapter.act(
            observation=observation,
            valid_actions={"VOTE"},
            agent_id="Health",
        )

        assert action.type is ActionType.VOTE
        assert action.proposal_id == "other"


def test_rule_based_adapters_skip_proposals_they_already_voted_on() -> None:
    observation = Observation(
        round=1,
        phase=Phase.VOTING,
        treasury=900.0,
        own_department=OwnDepartmentObservation(name="Health"),
        proposals=(
            ProposalObservation(
                proposal_id="already-voted",
                department="Defense",
                amount=100.0,
                votes={"Health": VoteChoice.YES.value},
            ),
            ProposalObservation(proposal_id="next", department="Education", amount=120.0),
        ),
    )

    for adapter in (GreedyAdapter(), EqualSplitAdapter(), ConservativeAdapter()):
        action = adapter.act(
            observation=observation,
            valid_actions={"VOTE"},
            agent_id="Health",
        )

        assert action.type is ActionType.VOTE
        assert action.proposal_id == "next"


def _proposal_observation(treasury: float, department: str) -> Observation:
    return Observation(
        round=1,
        phase=Phase.PROPOSAL,
        treasury=treasury,
        own_department=OwnDepartmentObservation(name=department),
    )