mirror of
https://github.com/tgorordo/carousel.git
synced 2026-06-14 21:32:14 -07:00
tweak cgi html form with TODOs
This commit is contained in:
parent
5da4a21a3f
commit
6d9d8978cf
4 changed files with 65 additions and 50 deletions
|
|
@ -144,56 +144,8 @@ def check_stable(*args, **kwargs):
|
||||||
return not check_unstable(*args, **kwargs)
|
return not check_unstable(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def deferred_acceptance(applicant_rankings, reviewer_rankings):
|
from .brute import *
|
||||||
"""Find the Gale-Shapley deferred-acceptance stable matching for preferences A, R."""
|
from .def_acc import *
|
||||||
reviewer_rankings = reviewer_rankings.rename(
|
|
||||||
{reviewer_rankings.columns[0]: "applicant"}
|
|
||||||
)
|
|
||||||
|
|
||||||
app_prefs = rank_to_pref(applicant_rankings)
|
|
||||||
offers = app_prefs.transpose(
|
|
||||||
include_header=True,
|
|
||||||
header_name="applicant",
|
|
||||||
column_names=["pref" + str(i + 1) for i in range(app_prefs.width)],
|
|
||||||
).with_columns(pl.coalesce(pl.all().exclude("applicant")).alias("offer"))
|
|
||||||
|
|
||||||
# offers = pl.concat(pl.align_frames(offers, reviewer_rankings, on="applicant"), how="horizontal")
|
|
||||||
offers = pl.concat([offers, reviewer_rankings], how="align_left")
|
|
||||||
|
|
||||||
match = pl.DataFrame(
|
|
||||||
{
|
|
||||||
r: offers.select(pl.col("applicant", "offer").sort_by(r))
|
|
||||||
.select(
|
|
||||||
pl.when(pl.col("offer").eq(r)).then(pl.col("applicant")).otherwise(None)
|
|
||||||
)
|
|
||||||
.select(pl.all().fill_null(strategy="backward").first())
|
|
||||||
.to_series()
|
|
||||||
for r in reviewer_rankings.columns[1:]
|
|
||||||
}
|
|
||||||
) # .select(pl.all().fill_null(strategy="backward").first())
|
|
||||||
|
|
||||||
# while check_unstable(match, applicant_rankings, reviewer_rankings):
|
|
||||||
while match.select(pl.any_horizontal(pl.all().has_nulls())).item():
|
|
||||||
# TODO null applicant preferences that rejected
|
|
||||||
|
|
||||||
rejected_applicants = offers.select(
|
|
||||||
pl.col("applicant").is_in(match.row(0)).alias("matched")
|
|
||||||
)
|
|
||||||
|
|
||||||
return match
|
|
||||||
|
|
||||||
offers = offers.with_columns(pl.col("pref"))
|
|
||||||
|
|
||||||
offers = offers.with_columns(
|
|
||||||
pl.coalesce(
|
|
||||||
# TODO: select prefn columns using a regex
|
|
||||||
).alias("offer")
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO update match
|
|
||||||
|
|
||||||
# else if stable
|
|
||||||
return match
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
|
||||||
3
src/carousel/brute.py
Normal file
3
src/carousel/brute.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
def brute(applicant_rankings, reviewer_rankings):
|
||||||
|
"""Brute force search for stable matches."""
|
||||||
|
pass
|
||||||
50
src/carousel/def_acc.py
Normal file
50
src/carousel/def_acc.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
def deferred_acceptance(applicant_rankings, reviewer_rankings):
|
||||||
|
"""Find Gale-Shapley deferred-acceptance stable matchings for preferences A, R."""
|
||||||
|
reviewer_rankings = reviewer_rankings.rename(
|
||||||
|
{reviewer_rankings.columns[0]: "applicant"}
|
||||||
|
)
|
||||||
|
|
||||||
|
app_prefs = rank_to_pref(applicant_rankings)
|
||||||
|
offers = app_prefs.transpose(
|
||||||
|
include_header=True,
|
||||||
|
header_name="applicant",
|
||||||
|
column_names=["pref" + str(i + 1) for i in range(app_prefs.width)],
|
||||||
|
).with_columns(pl.coalesce(pl.all().exclude("applicant")).alias("offer"))
|
||||||
|
|
||||||
|
# offers = pl.concat(pl.align_frames(offers, reviewer_rankings, on="applicant"), how="horizontal")
|
||||||
|
offers = pl.concat([offers, reviewer_rankings], how="align_left")
|
||||||
|
|
||||||
|
match = pl.DataFrame(
|
||||||
|
{
|
||||||
|
r: offers.select(pl.col("applicant", "offer").sort_by(r))
|
||||||
|
.select(
|
||||||
|
pl.when(pl.col("offer").eq(r)).then(pl.col("applicant")).otherwise(None)
|
||||||
|
)
|
||||||
|
.select(pl.all().fill_null(strategy="backward").first())
|
||||||
|
.to_series()
|
||||||
|
for r in reviewer_rankings.columns[1:]
|
||||||
|
}
|
||||||
|
) # .select(pl.all().fill_null(strategy="backward").first())
|
||||||
|
|
||||||
|
# while check_unstable(match, applicant_rankings, reviewer_rankings):
|
||||||
|
while match.select(pl.any_horizontal(pl.all().has_nulls())).item():
|
||||||
|
# TODO null applicant preferences that rejected
|
||||||
|
|
||||||
|
rejected_applicants = offers.select(
|
||||||
|
pl.col("applicant").is_in(match.row(0)).alias("matched")
|
||||||
|
)
|
||||||
|
|
||||||
|
return match
|
||||||
|
|
||||||
|
offers = offers.with_columns(pl.col("pref"))
|
||||||
|
|
||||||
|
offers = offers.with_columns(
|
||||||
|
pl.coalesce(
|
||||||
|
# TODO: select prefn columns using a regex
|
||||||
|
).alias("offer")
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO update match
|
||||||
|
|
||||||
|
# else if stable
|
||||||
|
return match
|
||||||
|
|
@ -399,8 +399,14 @@
|
||||||
|
|
||||||
<h3>Tabular Input</h3>
|
<h3>Tabular Input</h3>
|
||||||
You can enter tables of preferences directly in the first tab of the form above.
|
You can enter tables of preferences directly in the first tab of the form above.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
<h4>Example:</h4>
|
<h4>Example:</h4>
|
||||||
|
Suppose we want to figure out a Grad TA-to-Class assignment. Graduate students will be our "Applicants"
|
||||||
|
- each one will be assigned a class to TA -, and classes will be our "Reviewers" - taking a quota of needed TAs.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
<h3>File Upload</h3>
|
<h3>File Upload</h3>
|
||||||
|
|
||||||
|
|
@ -410,8 +416,12 @@
|
||||||
Two file formats are supported, Excel and CSV:
|
Two file formats are supported, Excel and CSV:
|
||||||
|
|
||||||
<h4>Excel</h4>
|
<h4>Excel</h4>
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
<h4>CSV</h4>
|
<h4>CSV</h4>
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue