some formatting and add cli compilation

This commit is contained in:
Thomas (Tom) C. Gorordo 2026-05-20 12:04:17 -07:00
parent 8836c49091
commit 4a624a4847
Signed by: tgorordo
GPG key ID: 0CBED22BB0D94490
9 changed files with 115 additions and 61 deletions

View file

@ -0,0 +1,4 @@
from smithy import cli
if __name__ == "__main__":
cli()

View file

@ -7,23 +7,20 @@ from rich.panel import Panel
from .rcv import smith_set
console = Console()
@click.command()
@click.argument(
"spreadsheet",
type=click.Path(exists=True, dir_okay=False)
)
def main(spreadsheet: str) -> None:
@click.argument("spreadsheet", type=click.Path(exists=True, dir_okay=False))
def cli(spreadsheet: str) -> None:
"""
Compute the Smith set from a ranked-choice ballot spreadsheet.
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.
"""
try:
console = Console()
try:
# Load spreadsheet
if spreadsheet.endswith(".csv"):
df = pl.read_csv(spreadsheet)
@ -33,17 +30,21 @@ def main(spreadsheet: str) -> None:
else:
console.print(
"[bold red]Unsupported file type.[/bold red]\n"
"Use CSV or Excel."
"[bold red]Unsupported file type.[/bold red]\nUse CSV or Excel."
)
raise SystemExit(1)
# Normalize numerical dataframe entries
df = df.with_columns([ pl.col(c)
.cast(pl.Utf8)
.str.strip_chars()
.cast(pl.Int64, strict=False).fill_null(0)
for c in df.columns ])
df = df.with_columns(
[
pl.col(c)
.cast(pl.Utf8)
.str.strip_chars()
.cast(pl.Int64, strict=False)
.fill_null(0)
for c in df.columns
]
)
# Compute Smith set
smiths = smith_set(df)
@ -66,14 +67,11 @@ def main(spreadsheet: str) -> None:
Panel.fit(
"\n".join(f"{c}" for c in smiths),
title="Resulting Smith Set",
border_style="green"
border_style="green",
)
)
except Exception as e:
console.print(
f"[bold red]Error:[/bold red] {e}"
)
console.print(f"[bold red]Error:[/bold red] {e}")
raise SystemExit(1)

View file

@ -1,13 +1,14 @@
import polars as pl
from itertools import combinations
def smith_set(df: 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 - if there is a single winner
in the set they are guaranteed the Condorcet i.e. Majority winner.
parameters
---
df : pl.DataFrame
@ -27,7 +28,7 @@ def smith_set(df: pl.DataFrame) -> list:
candidates = df.columns
# Build pairwise majority graph
graph: dict[str, set[str]] = { c: set() for c in candidates }
graph: dict[str, set[str]] = {c: set() for c in candidates}
for a, b in combinations(candidates, 2):
result = df.select(
@ -46,17 +47,13 @@ def smith_set(df: pl.DataFrame) -> list:
# Find Smith set
for size in range(1, len(candidates) + 1):
for sub in combinations(candidates, size):
subset = set(sub)
out = set(candidates) - subset
dom = True
for member in subset:
# DIRECT dominance only
if not out.issubset(graph[member]):
dom = False
break