Skip to content

Commit

Permalink
refactoring after PR #73
Browse files Browse the repository at this point in the history
  • Loading branch information
martinlackner committed Jul 4, 2023
1 parent a6ce7f6 commit 192d085
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 34 deletions.
49 changes: 28 additions & 21 deletions abcvoting/fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"""

import os
from math import ceil
import ruamel.yaml
import preflibtools.instances as preflib
from abcvoting.preferences import Profile, Voter
Expand Down Expand Up @@ -63,7 +62,7 @@ def get_file_names(dir_name, filename_extensions=None):
return sorted(files)


def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
def read_preflib_file(filename, top_ranks=None, setsize=None, use_weights=False):
"""
Read a Preflib file (soi, toi, soc or toc).
Expand All @@ -72,18 +71,21 @@ def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
filename : str
Name of the Preflib file.
num_cats : int, default=1
The approval set is composed of the union of the first `num_cats` catefories of the instance.
top_ranks : int, default=1
The approval set consists of the top entries in each voter's ranking in the Preflib
instance. The parameter `top_ranks` determines how many ranks are joined to create
the approval set. In case of of a Preflib category files, ranks correspond to
categories.
It cannot be used if parameter `setsize` is used too.
setsize : int
setsize : int, optional
Minimum number of candidates that voters approve.
These candidates are taken from the top of ranking.
In case of ties, more than setsize candidates are approved.
It cannot be used if parameter `num_cats` is used too.
It cannot be used if parameter `top_ranks` is used too.
use_weights : bool, default=False
Use weights of voters instead of individual voters.
Expand All @@ -97,12 +99,12 @@ def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
abcvoting.preferences.Profile
Preference profile extracted from Preflib file.
"""
if num_cats is None and setsize is None:
num_cats = 1
if num_cats and setsize:
raise ValueError("Parameters num_cats and setsize cannot be used simultaneously.")
if num_cats and num_cats <= 0:
raise ValueError("Parameter num_cats must be > 0")
if top_ranks is None and setsize is None:
top_ranks = 1 # default
if top_ranks and setsize:
raise ValueError("Parameters top_ranks and setsize cannot be used simultaneously.")
if top_ranks and top_ranks <= 0:
raise ValueError("Parameter top_ranks must be > 0")
if setsize and setsize <= 0:
raise ValueError("Parameter setsize must be > 0")

Expand All @@ -118,7 +120,7 @@ def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
preflib_inst = preflib.CategoricalInstance.from_ordinal(
preflib_inst, size_truncators=[setsize]
)
elif num_cats:
elif top_ranks:
preflib_inst = preflib.CategoricalInstance.from_ordinal(
preflib_inst, num_indif_classes=[1] * preflib_inst.num_alternatives
)
Expand All @@ -143,10 +145,10 @@ def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
category += 1
if 0 < len(approval_set) < setsize:
approval_set = normalize_map.values()
elif num_cats:
elif top_ranks:
approval_set = [
normalize_map[cand]
for category in range(min(len(preferences), num_cats))
for category in range(min(len(preferences), top_ranks))
for cand in preferences[category]
]

Expand All @@ -158,7 +160,7 @@ def read_preflib_file(filename, num_cats=None, setsize=None, use_weights=False):
return profile


def read_preflib_files_from_dir(dir_name, num_cats=None, setsize=None):
def read_preflib_files_from_dir(dir_name, top_ranks=None, setsize=None):
"""
Read all Preflib files (soi, toi, soc or toc) in a given directory.
Expand All @@ -167,8 +169,11 @@ def read_preflib_files_from_dir(dir_name, num_cats=None, setsize=None):
dir_name : str
Path of the directory to be searched for Preflib files.
num_cats : int, default=1
The approval set is composed of the union of the first `num_cats` catefories of the instance.
top_ranks : int, default=1
The approval set consists of the top entries in each voter's ranking in the Preflib
instance. The parameter `top_ranks` determines how many ranks are joined to create
the approval set. In case of of a Preflib category files, ranks correspond to
categories.
It cannot be used if parameter `setsize` is used too.
Expand All @@ -178,7 +183,7 @@ def read_preflib_files_from_dir(dir_name, num_cats=None, setsize=None):
These candidates are taken from the top of ranking.
In case of ties, more than setsize candidates are approved.
It cannot be used if parameter `num_cats` is used too.
It cannot be used if parameter `top_ranks` is used too.
Returns
-------
Expand All @@ -190,14 +195,16 @@ def read_preflib_files_from_dir(dir_name, num_cats=None, setsize=None):

profiles = {}
for f in files:
profile = read_preflib_file(os.path.join(dir_name, f), num_cats=num_cats, setsize=setsize)
profile = read_preflib_file(
os.path.join(dir_name, f), top_ranks=top_ranks, setsize=setsize
)
profiles[f] = profile
return profiles


def write_profile_to_preflib_cat_file(filename, profile):
"""
Write a profile to a Preflib .toi file.
Write a profile to a Preflib category file (.cat).
Parameters
----------
Expand Down
18 changes: 11 additions & 7 deletions examples/handling_preflib_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,29 @@
# Write a profile to toi file
profile = Profile(5, "ABCDE")
profile.add_voters([{0, 1}, {1, 3, 4}, {2}, {3}, {3}])
fileio.write_profile_to_preflib_cat_file(currdir + "/toi-files/new_example.cat", profile)
fileio.write_profile_to_preflib_cat_file(
os.path.join(currdir, "preflib-files/new_example.cat"), profile
)


# Read a directory of Preflib files (using parameter `num_cats`)
profiles = fileio.read_preflib_files_from_dir(currdir + "/toi-files/", num_cats=3)
# Read a directory of Preflib files (using parameter `top_ranks`)
profiles = fileio.read_preflib_files_from_dir(os.path.join(currdir, "preflib-files"), top_ranks=3)
# Compute PAV for each profile
committeesize = 2
for profile in profiles.values():
print("Computing a committee of size", committeesize, end=" ")
print("with the Proportional Approval Voting (PAV) rule")
print("given a", profile)
print(
f"Computing a committee of size {committeesize} "
"with the Proportional Approval Voting (PAV) rule"
)
print(f"given a {profile}")
print("Output:")
committees = abcrules.compute_pav(profile, committeesize)
print(str_sets_of_candidates(committees))
print("****************************************")


# Read a Preflib file (using parameter `setsize`)
profile = fileio.read_preflib_file(currdir + "/toi-files/example.toi", setsize=1)
profile = fileio.read_preflib_file(os.path.join(currdir, "preflib-files/example.toi"), setsize=1)
# Compute Phragmen's sequential rule for this profile
print("Computing a committee of size", committeesize, end=" ")
print("with Phragmen's sequential rule")
Expand Down
12 changes: 6 additions & 6 deletions tests/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@pytest.mark.parametrize("filename", ["test1.toi", "test2.soi", "test3.toc"])
def test_readfile(filename):
currdir = os.path.dirname(os.path.abspath(__file__))
profile = fileio.read_preflib_file(currdir + "/data/" + filename, num_cats=2)
profile = fileio.read_preflib_file(currdir + "/data/" + filename, top_ranks=2)
assert len(profile) == 5
assert profile.has_unit_weights()

Expand All @@ -23,7 +23,7 @@ def test_readfromdir():
for filename, profile in profiles.items():
assert isinstance(filename, str)
for voter in profile:
assert len(voter.approved) >= 2 or len(voter.approved) == 0
assert len(voter.approved) >= 2
assert profile.has_unit_weights()


Expand All @@ -38,7 +38,7 @@ def test_readfile_setsize(filename):
@pytest.mark.parametrize("filename", ["test2.soi", "test3.toc"])
def test_readfile_numcats(filename):
currdir = os.path.dirname(os.path.abspath(__file__))
profile = fileio.read_preflib_file(currdir + "/data/" + filename, num_cats=2)
profile = fileio.read_preflib_file(currdir + "/data/" + filename, top_ranks=2)
for voter in profile:
assert len(voter.approved) == 2

Expand Down Expand Up @@ -66,7 +66,7 @@ def test_readfile_setsize_with_ties(filename, setsize, expected):


@pytest.mark.parametrize(
"filename,num_cats,expected",
"filename,top_ranks,expected",
[
("test1.toi", 1, [1, 1, 1, 2, 1]),
("test1.toi", 2, [2, 3, 3, 3, 2]),
Expand All @@ -79,9 +79,9 @@ def test_readfile_setsize_with_ties(filename, setsize, expected):
("test4.cat", 4, [3, 1, 1, 3, 3]),
],
)
def test_readfile_num_cats_with_ties(filename, num_cats, expected):
def test_readfile_top_ranks_with_ties(filename, top_ranks, expected):
currdir = os.path.dirname(os.path.abspath(__file__))
profile = fileio.read_preflib_file(currdir + "/data/" + filename, num_cats=num_cats)
profile = fileio.read_preflib_file(currdir + "/data/" + filename, top_ranks=top_ranks)
assert [len(voter.approved) for voter in profile] == expected
for voter in profile:
assert voter.weight == 1
Expand Down

0 comments on commit 192d085

Please sign in to comment.