pref_voting 1.16.31__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pref_voting/__init__.py +1 -0
- pref_voting/analysis.py +496 -0
- pref_voting/axiom.py +38 -0
- pref_voting/axiom_helpers.py +129 -0
- pref_voting/axioms.py +10 -0
- pref_voting/c1_methods.py +963 -0
- pref_voting/combined_methods.py +514 -0
- pref_voting/create_methods.py +128 -0
- pref_voting/data/examples/condorcet_winner/minimal_Anti-Plurality.soc +16 -0
- pref_voting/data/examples/condorcet_winner/minimal_Borda.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_Bracket_Voting.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_Bucklin.soc +19 -0
- pref_voting/data/examples/condorcet_winner/minimal_Coombs.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_Coombs_PUT.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_Coombs_TB.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_Dowdall.soc +19 -0
- pref_voting/data/examples/condorcet_winner/minimal_Instant_Runoff.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_Instant_Runoff_PUT.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_Instant_Runoff_TB.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_Iterated_Removal_Condorcet_Loser.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_Pareto.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_Plurality.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_PluralityWRunoff_PUT.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_Positive-Negative_Voting.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_Simplified_Bucklin.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_Superior_Voting.soc +19 -0
- pref_voting/data/examples/condorcet_winner/minimal_Weighted_Bucklin.soc +19 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Anti-Plurality.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Borda.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Bracket_Voting.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Bucklin.soc +19 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Coombs.soc +21 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Coombs_PUT.soc +21 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Coombs_TB.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Dowdall.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Instant_Runoff.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Instant_Runoff_PUT.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Instant_Runoff_TB.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Plurality.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_PluralityWRunoff_PUT.soc +18 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Positive-Negative_Voting.soc +17 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Simplified_Bucklin.soc +20 -0
- pref_voting/data/examples/condorcet_winner/minimal_resolute_Weighted_Bucklin.soc +19 -0
- pref_voting/data/voting_methods_properties.json +414 -0
- pref_voting/data/voting_methods_properties.json.lock +0 -0
- pref_voting/dominance_axioms.py +387 -0
- pref_voting/generate_profiles.py +801 -0
- pref_voting/generate_spatial_profiles.py +198 -0
- pref_voting/generate_utility_profiles.py +160 -0
- pref_voting/generate_weighted_majority_graphs.py +506 -0
- pref_voting/grade_methods.py +184 -0
- pref_voting/grade_profiles.py +357 -0
- pref_voting/helper.py +370 -0
- pref_voting/invariance_axioms.py +671 -0
- pref_voting/io/__init__.py +0 -0
- pref_voting/io/readers.py +432 -0
- pref_voting/io/writers.py +256 -0
- pref_voting/iterative_methods.py +2425 -0
- pref_voting/maj_graph_ex1.png +0 -0
- pref_voting/mappings.py +577 -0
- pref_voting/margin_based_methods.py +2345 -0
- pref_voting/monotonicity_axioms.py +872 -0
- pref_voting/num_evaluation_method.py +77 -0
- pref_voting/other_axioms.py +161 -0
- pref_voting/other_methods.py +939 -0
- pref_voting/pairwise_profiles.py +547 -0
- pref_voting/prob_voting_method.py +105 -0
- pref_voting/probabilistic_methods.py +287 -0
- pref_voting/profiles.py +856 -0
- pref_voting/profiles_with_ties.py +1069 -0
- pref_voting/rankings.py +466 -0
- pref_voting/scoring_methods.py +481 -0
- pref_voting/social_welfare_function.py +59 -0
- pref_voting/social_welfare_functions.py +7 -0
- pref_voting/spatial_profiles.py +448 -0
- pref_voting/stochastic_methods.py +99 -0
- pref_voting/strategic_axioms.py +1394 -0
- pref_voting/swf_axioms.py +173 -0
- pref_voting/utility_functions.py +102 -0
- pref_voting/utility_methods.py +178 -0
- pref_voting/utility_profiles.py +333 -0
- pref_voting/variable_candidate_axioms.py +640 -0
- pref_voting/variable_voter_axioms.py +3747 -0
- pref_voting/voting_method.py +355 -0
- pref_voting/voting_method_properties.py +92 -0
- pref_voting/voting_methods.py +8 -0
- pref_voting/voting_methods_registry.py +136 -0
- pref_voting/weighted_majority_graphs.py +1539 -0
- pref_voting-1.16.31.dist-info/METADATA +208 -0
- pref_voting-1.16.31.dist-info/RECORD +92 -0
- pref_voting-1.16.31.dist-info/WHEEL +4 -0
- pref_voting-1.16.31.dist-info/licenses/LICENSE.txt +21 -0
@@ -0,0 +1,198 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from pref_voting.spatial_profiles import SpatialProfile
|
3
|
+
|
4
|
+
|
5
|
+
def generate_covariance(n_dimensions, std, rho):
|
6
|
+
"""
|
7
|
+
Generates a covariance matrix for a multivariate normal distribution with the given standard deviation and correlation coefficient.
|
8
|
+
|
9
|
+
Parameters
|
10
|
+
----------
|
11
|
+
n_dimensions : int
|
12
|
+
The number of dimensions.
|
13
|
+
std : float
|
14
|
+
The standard deviation.
|
15
|
+
rho : float
|
16
|
+
The correlation coefficient.
|
17
|
+
|
18
|
+
Returns
|
19
|
+
-------
|
20
|
+
cov : numpy.ndarray
|
21
|
+
The covariance matrix for a multivariate normal distribution.
|
22
|
+
"""
|
23
|
+
assert std > 0, "Standard deviation must be positive"
|
24
|
+
assert rho >= 0 and rho <= 1, "Correlation coefficient must be between 0 and 1"
|
25
|
+
assert n_dimensions > 0, "Number of dimensions must be positive"
|
26
|
+
|
27
|
+
cov = (std**2) * (np.eye(n_dimensions) + rho * (np.ones((n_dimensions, n_dimensions)) - np.eye(n_dimensions)))
|
28
|
+
|
29
|
+
return cov
|
30
|
+
|
31
|
+
def generate_spatial_profile(num_cands, num_voters, num_dims, cand_cov = None, voter_cov = None, num_profiles = 1):
|
32
|
+
|
33
|
+
"""
|
34
|
+
Generates a spatial profile with the candidate and voter positions generated by a multivariate normal distribution with num_dims dimensions and cand_cov the covariance matrix for candidates and voter_cov the covariance matrix for voters.
|
35
|
+
|
36
|
+
Parameters
|
37
|
+
----------
|
38
|
+
num_cands : int
|
39
|
+
The number of candidates.
|
40
|
+
num_voters : int
|
41
|
+
The number of voters.
|
42
|
+
num_dims : int
|
43
|
+
The number of dimensions.
|
44
|
+
cand_cov : numpy.ndarray, optional
|
45
|
+
The covariance matrix for the multivariate normal distribution for candidates. The default is None.
|
46
|
+
voter_cov : numpy.ndarray, optional
|
47
|
+
The covariance matrix for the multivariate normal distribution for voters. The default is the identity matrix.
|
48
|
+
|
49
|
+
Returns
|
50
|
+
-------
|
51
|
+
SpatialProfile
|
52
|
+
A spatial profile with the candidate and voter positions generated by a multivariate normal distribution with num_dims dimensions and cand_cov the covariance matrix for candidates and voter_cov the covariance matrix for voters.
|
53
|
+
|
54
|
+
"""
|
55
|
+
cand_cov = np.eye(num_dims) if cand_cov is None else cand_cov
|
56
|
+
voter_cov = np.eye(num_dims) if voter_cov is None else voter_cov
|
57
|
+
|
58
|
+
assert num_dims == cand_cov.shape[0] == cand_cov.shape[1], "Candidate covariance matrix must be square and have the same number of dimensions as the number of dimensions specified"
|
59
|
+
assert num_dims == voter_cov.shape[0] == voter_cov.shape[1], "Voter covariance matrix must be square and have the same number of dimensions as the number of dimensions specified"
|
60
|
+
|
61
|
+
cand_mean = np.zeros(num_dims)
|
62
|
+
voter_mean = np.zeros(num_dims)
|
63
|
+
|
64
|
+
cand_samples = np.random.multivariate_normal(cand_mean, cand_cov, size=(num_profiles,num_cands))
|
65
|
+
voter_samples = np.random.multivariate_normal(voter_mean, voter_cov, size=(num_profiles,num_voters))
|
66
|
+
|
67
|
+
profs = [SpatialProfile({c: cand_samples[pidx][c] for c in range(num_cands)},
|
68
|
+
{v: voter_samples[pidx][v] for v in range(num_voters)})
|
69
|
+
for pidx in range(num_profiles)]
|
70
|
+
|
71
|
+
return profs[0] if num_profiles == 1 else profs
|
72
|
+
|
73
|
+
def generate_spatial_profile_polarized(
|
74
|
+
cand_clusters,
|
75
|
+
voter_clusters,
|
76
|
+
cluster_types = None,
|
77
|
+
num_profiles = 1):
|
78
|
+
"""
|
79
|
+
Generates a spatial profile with polarized clusters of candidates and voters.
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
cand_clusters : list
|
84
|
+
A list of tuples of the form (mean, covariance, number of candidates) for each cluster of candidates.
|
85
|
+
voter_clusters : list
|
86
|
+
A list of tuples of the form (mean, covariance, number of voters) for each cluster of voters.
|
87
|
+
cluster_types : dict, optional
|
88
|
+
A list of the same length as cand_cluster that associates each cluster to the type of candidate. The default is None.
|
89
|
+
|
90
|
+
num_profiles : int, optional
|
91
|
+
The number of profiles to generate. The default is 1.
|
92
|
+
|
93
|
+
Returns
|
94
|
+
-------
|
95
|
+
SpatialProfile
|
96
|
+
A spatial profile with polarized clusters of candidates and voters.
|
97
|
+
"""
|
98
|
+
|
99
|
+
cluster_types = cluster_types if cluster_types is not None else list(range(len(cand_clusters)))
|
100
|
+
cand_samples = list()
|
101
|
+
candidate_types = {}
|
102
|
+
total_num_cands = 0
|
103
|
+
for cluster_idx, cand_cluster in enumerate(cand_clusters):
|
104
|
+
cand_mean, cand_cov, num_cands = cand_cluster
|
105
|
+
candidate_types.update({cidx: cluster_types[cluster_idx] for cidx in range(total_num_cands, total_num_cands+num_cands)})
|
106
|
+
total_num_cands += num_cands
|
107
|
+
cluster_samples = np.random.multivariate_normal(cand_mean, cand_cov,
|
108
|
+
size=(num_profiles,num_cands))
|
109
|
+
if len(cand_samples) == 0:
|
110
|
+
cand_samples = cluster_samples
|
111
|
+
else:
|
112
|
+
cand_samples = np.concatenate([cand_samples, cluster_samples], axis=1)
|
113
|
+
|
114
|
+
voter_samples = list()
|
115
|
+
total_num_voters = 0
|
116
|
+
for voter_cluster in voter_clusters:
|
117
|
+
voter_mean, voter_cov, num_voters = voter_cluster
|
118
|
+
total_num_voters += num_voters
|
119
|
+
cluster_samples = np.random.multivariate_normal(voter_mean, voter_cov,
|
120
|
+
size=(num_profiles,num_voters))
|
121
|
+
if len(voter_samples) == 0:
|
122
|
+
voter_samples = cluster_samples
|
123
|
+
else:
|
124
|
+
voter_samples = np.concatenate([voter_samples, cluster_samples], axis=1)
|
125
|
+
|
126
|
+
|
127
|
+
profs = [SpatialProfile({cidx: cand_samples[pidx][cidx]
|
128
|
+
for cidx in range(total_num_cands)},
|
129
|
+
{vidx: voter_samples[pidx][vidx]
|
130
|
+
for vidx in range(total_num_voters)},
|
131
|
+
candidate_types=candidate_types)
|
132
|
+
for pidx in range(num_profiles)]
|
133
|
+
|
134
|
+
return profs[0] if num_profiles == 1 else profs
|
135
|
+
|
136
|
+
|
137
|
+
def generate_spatial_profile_polarized_cands_randomly_polarized_voters(
|
138
|
+
cand_clusters,
|
139
|
+
num_voters,
|
140
|
+
voter_distributions,
|
141
|
+
cluster_types = None,
|
142
|
+
num_profiles = 1):
|
143
|
+
"""
|
144
|
+
Generates a spatial profile with polarized clusters of candidates and voters.
|
145
|
+
|
146
|
+
Parameters
|
147
|
+
----------
|
148
|
+
cand_clusters : list
|
149
|
+
A list of tuples of the form (mean, covariance, number of candidates) for each cluster of candidates.
|
150
|
+
num_voters : int
|
151
|
+
The number of voters.
|
152
|
+
voter_distributions : list
|
153
|
+
A list of tuples of the form (mean, covariance, prob) for each distribution of voters, where prob is the probability that a voter is assigned to this cluster.
|
154
|
+
cluster_types : dict, optional
|
155
|
+
A list of the same length as cand_cluster that associates each cluster to the type of candidate. The default is None.
|
156
|
+
num_profiles : int, optional
|
157
|
+
The number of profiles to generate. The default is 1.
|
158
|
+
|
159
|
+
Returns
|
160
|
+
-------
|
161
|
+
SpatialProfile
|
162
|
+
A spatial profile with polarized clusters of candidates and voters.
|
163
|
+
"""
|
164
|
+
|
165
|
+
cluster_types = cluster_types if cluster_types is not None else list(range(len(cand_clusters)))
|
166
|
+
cand_samples = list()
|
167
|
+
candidate_types = {}
|
168
|
+
total_num_cands = 0
|
169
|
+
for cluster_idx, cand_cluster in enumerate(cand_clusters):
|
170
|
+
cand_mean, cand_cov, num_cands = cand_cluster
|
171
|
+
candidate_types.update({cidx: cluster_types[cluster_idx] for cidx in range(total_num_cands, total_num_cands+num_cands)})
|
172
|
+
total_num_cands += num_cands
|
173
|
+
cluster_samples = np.random.multivariate_normal(cand_mean, cand_cov, size=(num_profiles,num_cands))
|
174
|
+
if len(cand_samples) == 0:
|
175
|
+
cand_samples = cluster_samples
|
176
|
+
else:
|
177
|
+
cand_samples = np.concatenate([cand_samples, cluster_samples], axis=1)
|
178
|
+
|
179
|
+
all_potential_voters = list()
|
180
|
+
voter_cluster_probs = list()
|
181
|
+
for voter_distribution in voter_distributions:
|
182
|
+
voter_mean, voter_cov, prob = voter_distribution
|
183
|
+
all_potential_voters.append(np.random.multivariate_normal(voter_mean, voter_cov, size=(num_profiles, num_voters)))
|
184
|
+
voter_cluster_probs.append(prob)
|
185
|
+
|
186
|
+
# for each profile, randomly assign voters to clusters
|
187
|
+
|
188
|
+
#voters = range(num_voters)
|
189
|
+
|
190
|
+
voters_clusters_assignment = np.random.choice(len(all_potential_voters), size=(num_profiles, num_voters), p = voter_cluster_probs)
|
191
|
+
profs = [SpatialProfile({cidx: cand_samples[pidx][cidx]
|
192
|
+
for cidx in range(total_num_cands)},
|
193
|
+
{vidx: all_potential_voters[voters_clusters_assignment[pidx][vidx]][pidx][vidx]
|
194
|
+
for vidx in range(num_voters)},
|
195
|
+
candidate_types=candidate_types)
|
196
|
+
for pidx in range(num_profiles)]
|
197
|
+
|
198
|
+
return profs[0] if num_profiles == 1 else profs
|
@@ -0,0 +1,160 @@
|
|
1
|
+
|
2
|
+
'''
|
3
|
+
File: generate_utility_profiles.py
|
4
|
+
Author: Wes Holliday (wesholliday@berkeley.edu) and Eric Pacuit (epacuit@umd.edu)
|
5
|
+
Date: May 26, 2023
|
6
|
+
|
7
|
+
Functions to generate utility profiles.
|
8
|
+
'''
|
9
|
+
|
10
|
+
|
11
|
+
from math import ceil
|
12
|
+
import numpy as np
|
13
|
+
from scipy.spatial import distance
|
14
|
+
from functools import partial
|
15
|
+
|
16
|
+
from pref_voting.utility_profiles import UtilityProfile
|
17
|
+
from pref_voting.utility_functions import *
|
18
|
+
|
19
|
+
# turn off future warnings.
|
20
|
+
# getting the following warning when calling tabulate to display a profile:
|
21
|
+
# /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/tabulate.py:1027: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
|
22
|
+
# if headers == "keys" and not rows:
|
23
|
+
# see https://stackoverflow.com/questions/40659212/futurewarning-elementwise-comparison-failed-returning-scalar-but-in-the-futur
|
24
|
+
#
|
25
|
+
import warnings
|
26
|
+
warnings.simplefilter(action='ignore', category=FutureWarning)
|
27
|
+
|
28
|
+
|
29
|
+
def generate_utility_profile_uniform(num_candidates, num_voters, num_profiles = 1):
|
30
|
+
"""
|
31
|
+
Generate a utility profile where each voter assigns a random number between 0 and 1 to each candidate.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
num_candidates (int): The number of candidates.
|
35
|
+
num_voters (int): The number of voters.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
UtilityProfile: A utility profile.
|
39
|
+
|
40
|
+
"""
|
41
|
+
|
42
|
+
cand_utils = np.random.uniform(size=(num_profiles, num_voters, num_candidates))
|
43
|
+
|
44
|
+
uprofs = [UtilityProfile([{c: cand_utils[pidx][v][c]
|
45
|
+
for c in range(num_candidates)}
|
46
|
+
for v in range(num_voters)])
|
47
|
+
for pidx in range(num_profiles)]
|
48
|
+
|
49
|
+
return uprofs if num_profiles > 1 else uprofs[0]
|
50
|
+
|
51
|
+
def generate_utility_profile_normal(num_candidates, num_voters, std = 0.1, normalize = None, num_profiles = 1):
|
52
|
+
"""
|
53
|
+
Generate a utility profile where each voter assigns a random number drawn from a normal distribution with a randomly chosen mean (between 0 and 1) with standard deviation ``std`` to each candidate.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
num_candidates (int): The number of candidates.
|
57
|
+
num_voters (int): The number of voters.
|
58
|
+
std (float): The standard deviation of the normal distribution. The default is 0.1.
|
59
|
+
normalize (str): The normalization method to use. The default is None.
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
UtilityProfile: A utility profile.
|
63
|
+
"""
|
64
|
+
|
65
|
+
mean_utilities = {c: np.random.uniform(0, 1) for c in range(num_candidates)}
|
66
|
+
cand_utils = {c: np.random.normal(mean_utilities[c], std, size=(num_profiles, num_voters)) for c in range(num_candidates)}
|
67
|
+
|
68
|
+
if normalize == "range":
|
69
|
+
uprofs = [UtilityProfile([{c: cand_utils[c][pidx][vidx]
|
70
|
+
for c in range(num_candidates)}
|
71
|
+
for vidx in range(num_voters)]).normalize_by_range()
|
72
|
+
for pidx in range(num_profiles)]
|
73
|
+
elif normalize == "score":
|
74
|
+
uprofs = [UtilityProfile([{c: cand_utils[c][pidx][vidx]
|
75
|
+
for c in range(num_candidates)}
|
76
|
+
for vidx in range(num_voters)]).normalize_by_standard_score()
|
77
|
+
for pidx in range(num_profiles)]
|
78
|
+
else: # do not normalize
|
79
|
+
uprofs = [UtilityProfile([{c: cand_utils[c][pidx][vidx]
|
80
|
+
for c in range(num_candidates)}
|
81
|
+
for vidx in range(num_voters)])
|
82
|
+
for pidx in range(num_profiles)]
|
83
|
+
|
84
|
+
|
85
|
+
return uprofs if num_profiles > 1 else uprofs[0]
|
86
|
+
utility_functions = {
|
87
|
+
"RM": {
|
88
|
+
"func": mixed_rm_utility,
|
89
|
+
"param": 1
|
90
|
+
},
|
91
|
+
"Linear": {
|
92
|
+
"func": linear_utility,
|
93
|
+
"param": None
|
94
|
+
},
|
95
|
+
"Quadratic":
|
96
|
+
{
|
97
|
+
"func": quadratic_utility,
|
98
|
+
"param": None
|
99
|
+
},
|
100
|
+
"Shepsle": {
|
101
|
+
"func": shepsle_utility,
|
102
|
+
"param": None
|
103
|
+
},
|
104
|
+
"City Block": {
|
105
|
+
"func": city_block_utility,
|
106
|
+
"param": None
|
107
|
+
},
|
108
|
+
"Matthews": {
|
109
|
+
"func": matthews_utility,
|
110
|
+
"param": None
|
111
|
+
}
|
112
|
+
|
113
|
+
}
|
114
|
+
def generate_spatial_utility_profile(num_cands,
|
115
|
+
num_voters,
|
116
|
+
num_dims = 2,
|
117
|
+
utility_function = "Quadratic",
|
118
|
+
utility_function_param = None):
|
119
|
+
|
120
|
+
"""
|
121
|
+
Create a spatial utility profile using specified utility functions.
|
122
|
+
|
123
|
+
|
124
|
+
Args:
|
125
|
+
num_cands (int): The number of candidates.
|
126
|
+
num_voters (int): The number of voters.
|
127
|
+
num_dims (int): The number of dimensions. The default is 2.
|
128
|
+
utility_function (str): The utility function to use. The default is "Linear".
|
129
|
+
utility_function_param (float): The parameter of the utility function. The default is None.
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
UtilityProfile: A spatial utility profile.
|
133
|
+
"""
|
134
|
+
|
135
|
+
# the first component of the parameter is the number of dimensions,
|
136
|
+
# the second component is used to define the mixed model:
|
137
|
+
# beta = 1 is proximity model (i.e., squared Euclidean distance)
|
138
|
+
|
139
|
+
mean = [0] * num_dims # mean is 0 for each dimension
|
140
|
+
cov = np.diag([1] * num_dims) # diagonal covariance
|
141
|
+
|
142
|
+
_utility_fnc = utility_functions[utility_function]["func"]
|
143
|
+
|
144
|
+
if utility_functions[utility_function]["param"] is not None or utility_function_param is not None:
|
145
|
+
util_parm = utility_function_param if utility_function_param is not None else utility_functions[utility_function]["param"]
|
146
|
+
utility_fnc = partial(_utility_fnc, util_parm)
|
147
|
+
|
148
|
+
else:
|
149
|
+
utility_fnc = _utility_fnc
|
150
|
+
|
151
|
+
# sample candidate/voter positions using a multivariate normal distribution
|
152
|
+
cand_positions = np.random.multivariate_normal(np.array(mean), cov, num_cands)
|
153
|
+
voter_positions = np.random.multivariate_normal(np.array(mean), cov, num_voters)
|
154
|
+
|
155
|
+
utilities = [{c: utility_fnc(v_pos, c_pos) for c, c_pos in enumerate(cand_positions)}
|
156
|
+
for _, v_pos in enumerate(voter_positions)]
|
157
|
+
|
158
|
+
return UtilityProfile(utilities)
|
159
|
+
|
160
|
+
|