adding deps for algo upgrade

This commit is contained in:
Thomas (Tom) C. Gorordo 2026-05-25 04:48:44 -07:00
parent 62923fefaf
commit fcf2505820
Signed by: tgorordo
GPG key ID: 0CBED22BB0D94490
7 changed files with 113 additions and 27 deletions

View file

@ -6,12 +6,11 @@ import re
import polars as pl
sys.path.insert(0,
sys.path.insert(
0,
os.path.abspath(
os.path.join(
os.path.dirname(os.path.abspath(__file__)), "../smithy/src"
)
)
os.path.join(os.path.dirname(os.path.abspath(__file__)), "../smithy/src")
),
)
from smithy import smith_set_from_rcv
@ -28,10 +27,10 @@ parts = body.split(b"--" + boundary)
spreadsheet = None
for part in parts:
if b'Content-Disposition' in part and b'name="spreadsheet"' in part:
if b"Content-Disposition" in part and b'name="spreadsheet"' in part:
header, _, data = part.partition(b"\r\n\r\n")
filename_match = re.search(br'filename="([^"]+)"', header)
filename_match = re.search(rb'filename="([^"]+)"', header)
if filename_match:
filename = filename_match.group(1).decode()
filedata = data.rstrip(b"\r\n--")
@ -41,13 +40,12 @@ for part in parts:
if spreadsheet is not None:
filename, filedata = spreadsheet
if filename and filedata:
filepath = os.path.join("/tmp", filename)
with open(filepath, 'wb') as f:
with open(filepath, "wb") as f:
f.write(filedata)
try:
@ -75,7 +73,7 @@ if spreadsheet is not None:
]
)
smiths = smith_set_from_rcv(df) # Solve!
smiths = smith_set_from_rcv(df) # Solve!
message = f"""
<h1>The Smith set winners are:</h1>
@ -89,7 +87,6 @@ if spreadsheet is not None:
<p><a href="form.html">Go Back</a></p>
"""
except Exception as e:
message = f"""
<h1>Error</h1>

View file

@ -17,8 +17,8 @@ def smith_set_brutefrom_pairmaj(pairmaj_graph: dict[str, set[str]]) -> list:
returns
---
smith_set: list
A list of the Smith set candidates - all are equally good winners;
ordering is determined lexicographically. If there is a Condorcet winner
A list of the Smith set candidates - all are equally good winners;
ordering is determined lexicographically. If there is a Condorcet winner
(single Majority winner), the Smith set will contain that single candidate.
"""
@ -42,11 +42,12 @@ def smith_set_brutefrom_pairmaj(pairmaj_graph: dict[str, set[str]]) -> list:
return []
def smith_set_from_rcv(rcv_ballots: pl.DataFrame) -> list:
"""
Compute the Smith set from a Ranked-Choice ballot.
The Smith set is the minimal set of candidates which can beat all others pairwise -
The Smith set is the minimal set of candidates which can beat all others pairwise -
if there is a single winner in the set they are guaranteed the Condorcet i.e. Majority winner.
parameters
@ -59,16 +60,19 @@ def smith_set_from_rcv(rcv_ballots: pl.DataFrame) -> list:
returns
---
smith_set : list
A list of the Smith set candidates - all are equally good winners;
ordering is determined lexicographically. If there is a Condorcet winner
A list of the Smith set candidates - all are equally good winners;
ordering is determined lexicographically. If there is a Condorcet winner
(single Majority winner), the Smith set will contain that single candidate.
"""
return smith_set_brutefrom_pairmaj(pairmaj_from_rcv(rcv_ballots))
def smith_set(df: pl.DataFrame, ballotkind="rcv") -> list:
if ballotkind == "rcv":
return smith_set_from_rcv(df)
else:
raise NotImplementedError(f"`smith_set` ballotkind={ballotkind} is not implemented.")
raise NotImplementedError(
f"`smith_set` ballotkind={ballotkind} is not implemented."
)

View file

@ -1,6 +1,7 @@
import polars as pl
from itertools import combinations
def pairmaj_from_rcv(rcv_ballots: pl.DataFrame) -> dict[str, set[str]]:
"""
Build a pairwise majority winner graph from a box of Ranked-Choice Ballots.
@ -15,7 +16,7 @@ def pairmaj_from_rcv(rcv_ballots: pl.DataFrame) -> dict[str, set[str]]:
returns
---
pairmaj_graph: dict[str, set[str]]
A pairwise majority winner graph whose nodes correspond to candidates and
A pairwise majority winner graph whose nodes correspond to candidates and
(directed) edges show which candidates they beat pairwise.
"""
candidates = rcv_ballots.columns
@ -38,9 +39,3 @@ def pairmaj_from_rcv(rcv_ballots: pl.DataFrame) -> dict[str, set[str]]:
pairmaj_graph[b].add(a)
return pairmaj_graph

View file

@ -16,16 +16,22 @@ from rich.panel import Panel
import polars as pl
from smithy import smith_set
@click.command()
@click.argument("ballots", type=click.Path(exists=True, dir_okay=False))
@click.option("--show-ballots", "-b", is_flag=True, help="Show relevant ballots (after selections).")
@click.option(
"--show-ballots",
"-b",
is_flag=True,
help="Show relevant ballots (after selections).",
)
@click.option("--pretty", "-p", is_flag=True, help="Pretty-print output.")
def cli(ballots: str, show_ballots=False, pretty=False) -> None:
"""
Compute the Smith set from a box of ranked-choice ballots -- .csv or .xls(x).
The Smith set is the minimal set of candidates which can beat all others pairwise
(simple ranking majority) - if there is a single winner in the set,
(simple ranking majority) - if there is a single winner in the set,
they are guaranteed the Condorcet i.e. Majority winner.
"""
@ -60,7 +66,6 @@ def cli(ballots: str, show_ballots=False, pretty=False) -> None:
# Compute Smith set
smiths = smith_set(df)
if show_ballots and pretty:
preview = Table(title="Ballot Box")
@ -94,5 +99,6 @@ def cli(ballots: str, show_ballots=False, pretty=False) -> None:
raise SystemExit(1)
if __name__ == "__main__":
cli()