nation_optimizer / tests /unit /test_rule_based_adapters.py
thewildofficial
Merge main and fix benchmark adapter review issues
046ac0f
Raw
History Blame Contribute Delete
4.97 kB
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),
)