-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcumulative_voting.py
More file actions
142 lines (129 loc) · 4.95 KB
/
Copy pathcumulative_voting.py
File metadata and controls
142 lines (129 loc) · 4.95 KB
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
import ast
import logging
from typing import Any, Optional
from mallm.agents.panelist import Panelist
from mallm.decision_protocols.protocol import DecisionProtocol
from mallm.models.discussion.ResponseGenerator import ResponseGenerator
from mallm.utils.config import Config
from mallm.utils.enums import DecisionAlteration
from mallm.utils.types import Agreement, VotingResult, VotingResultList, WorkerFunctions
logger = logging.getLogger("mallm")
class CumulativeVoting(DecisionProtocol):
"""
The Cumulative Voting decision protocol allows panelists to distribute 10 points among the solutions.
The solution with the highest total points is selected as the final decision.
"""
_name = "cumulative_voting"
def __init__(
self,
panelists: list[Panelist],
num_neutral_agents: int,
worker_functions: WorkerFunctions,
vote_turn: int = 3,
) -> None:
super().__init__(panelists, num_neutral_agents, worker_functions)
self.vote_turn = vote_turn
def make_decision(
self,
agreements: list[Agreement],
turn: int,
agent_index: int,
task: str,
question: str,
config: Config,
) -> tuple[str, bool, list[Agreement], str, Optional[VotingResultList]]:
if len(agreements) > self.total_agents:
agreements = agreements[-self.total_agents :]
if turn < self.vote_turn or agent_index != self.total_agents - 1:
return "", False, agreements, "", None
final_answers_with_confidence, voting_process_string = (
self.generate_final_answers(agreements, question, task)
)
decision, final_answer, results, voting_process_string = (
self.vote_with_alterations(
final_answers_with_confidence,
question,
task,
voting_process_string,
self._name,
ResponseGenerator.generate_cumulative_voting_prompt,
config.voting_protocols_with_alterations,
)
)
return (
final_answer,
decision,
agreements,
voting_process_string,
results,
)
def process_results(
self,
all_votes: dict[str, VotingResult],
alteration: DecisionAlteration,
final_answers: list[str],
votes: Any,
) -> dict[str, VotingResult]:
# Aggregate points for each solution
total_points = [0] * len(final_answers)
for points in votes:
for index, point in points.items():
total_points[index] += point
# Determine the solution with the highest points, break ties by selecting the first solution and go for another round
max_points = max(total_points)
best_solution_index = total_points.index(max_points)
best_answers = [
final_answers[i]
for i, score in enumerate(total_points)
if score == max_points
]
if len(best_answers) == 1:
all_votes[alteration.value] = VotingResult(
votes=votes,
most_voted=best_solution_index,
final_answer=final_answers[best_solution_index],
agreed=True,
)
logger.info(
f"Selected answer from agent {self.panelists[best_solution_index].short_id} with {max_points} points"
)
else:
all_votes[alteration.value] = VotingResult(
votes=votes,
most_voted=-1,
final_answer="",
agreed=False,
)
logger.info("There was a tie. Going for another round of voting.")
return all_votes
def process_votes(
self,
final_answers: list[str],
panelist: Panelist,
vote_str: str,
vote: Any,
voting_process_string: str,
) -> tuple[str, Any, bool, str]:
success = False
vote_str = vote_str.replace("\n", "").replace(" ", "").strip()
points_dict = ast.literal_eval(vote_str)
points_dict = {int(k): int(v) for k, v in points_dict.items()}
if self.validate_points_distribution(points_dict, len(final_answers)):
vote.append(points_dict)
logger.info(f"{panelist.persona} allocated points: {points_dict}")
voting_process_string += (
f"{panelist.persona} allocated points: {points_dict}\n"
)
success = True
return vote_str, vote, success, voting_process_string
@staticmethod
def validate_points_distribution(
points_dict: dict[int, int], num_solutions: int
) -> bool:
total_points = sum(points_dict.values())
if total_points != 10:
return False
for index in points_dict:
if not isinstance(index, int) or not (0 <= index < num_solutions):
return False
return not any(x < 0 for x in points_dict.values())