0.26.0 (2020-06-26): Descriptive Statistics of the Ballots

  • In TauVector:
    • Add share_single_votes: share of single votes, i.e. votes for one candidate only.
    • Add share_double_votes: share of double votes, i.e. votes for two candidates.
  • In ProfileCardinal:
    • Add share_sincere_among_strategic_voters: share of strategic voters that happen to cast a sincere ballot (when a strategy is given).
    • Add share_sincere_among_fanatic_voters: share of fanatic voters that happen to cast a sincere ballot.
    • Add share_sincere: share of voters that happen to cast a sincere ballot (when a strategy is given). This takes sincere, fanatic and strategic voters into account.
  • In Strategy:
    • Add share_single_votes and share_double_votes: these shortcuts are defined when the strategy is defined with an embedded profile.
    • Add share_sincere_among_strategic_voters and share_sincere: these shortcuts are defined when the strategy is defined with an embedded profile, provided the profile is cardinal.

0.25.1 (2020-06-25): Welfare of a Candidate

  • ProfileCardinal now has attributes d_candidate_welfare and d_candidate_relative_welfare: for each candidate, it gives its welfare, i.e. its total utility. The relative welfare is normalized so that the candidate with maximal welfare has 1 and the one with minimal welfare has 0.
  • The function probability now accepts a tuple of tests as inputs.
  • Bug fix: the recent versions of the external package scipy changed the behavior of scipy.optimize.minimize. Since PivotTrio relies on this function, its behavior changed in an unexpected way and it sometimes lead to incorrect results, such as a positive magnitude. This version solves the problem: PivotTrio has regained its former (correct) behavior.

0.24.0 (2020-03-29): Plots for Convergence Frequency

  • Add ternary_plot_convergence and binary_plot_convergence: plot the convergence frequency, which is defined as the proportion of initializations where iterated voting or fictitious play lead to convergence within n_max_episodes iterations.

0.23.0 (2020-03-29): Improve Iterated Voting and Fictitious Play

  • Random initialization of iterated voting and fictitious play:
    • Add the option 'random_tau': a random tau-vector that is consistent with the voting rule.
    • Add the option 'random_tau_undominated': a random tau-vector where each voter randomly uses an undominated ballot. Relies on the new method Profile.random_tau_undominated.
    • Remove the option 'random_strategy': it had an unnatural behavior for Plurality and Anti-Plurality. Subsequently, remove also the method Profile.random_strategy.
  • In iterated voting and fictitious play, winning frequencies are computed from t=1 instead of t=0. The motivation is twofold. Firstly, if the result at initialization is essentially arbitrary and, for example, candidate a always wins afterwards, we consider it more natural to have a winning frequency of 1 for a. Secondly, when using the arithmetic average, the denominator is the number of steps, rather than the number of steps plus one. As a consequence, we updated the helper functions in order to account for this time translation:
    • Replace one_over_t_plus_one with one_over_t.
    • Replace one_over_sqrt_t_plus_one with one_over_sqrt_t.
    • Replace one_over_log_t_plus_two with one_over_log_t_plus_one.
    • Replace one_over_log_log_t_plus_fifteen with one_over_log_log_t_plus_fourteen.
  • Fix a rare bug: in some tau-vectors, when computing the trio event, an offset was found greater than 1, whereas theory shows that it is lower than 1. This used to cause a collateral error when computing the best response with the offset method.

0.22.0 (2020-03-22): Binary Plots

  • Implement binary plots, i.e. plots designed to study profiles based on two ranking with varying utilities. Cf. the corresponding tutorial.
    • Intensity heat maps.
    • Candidate heat maps.
    • Annotate the Condorcet regions.
  • Utilities:
    • Add d_candidate_ordinal_utility: ordinal utility of a candidate for a given preference order.
    • Add my_range: similar to range, but works also for fractions.
    • Add my_sign: sign of a number. Return an integer in {-1, 0, 1}, unlike np.sign.

0.21.0 (2020-03-12): Iterables and Random Factories

  • Add new iterables and random factories for profiles, tau-vectors and strategies. These iterables and random factories are very flexible: you can specify that some types have a fixed share, that only some types have a variable share, etc. Cf. the corresponding tutorials and the corresponding section in Reference.
  • Remove ExploreGridProfilesOrdinal and ExploreGridTaus: their features are included in the new iterables.
  • Remove all classes whose name began with Generator: their features are included in the new random factories.
  • All the methods that had a parameter generator now have a parameter factory instead. This choice is due to the fact that the word “generator” has another meaning in Python, which could be misleading.
  • SimplexToProfile works similarly to the new iterables and random factories. In particular it is now allowed to use the same type several times, for example in the fixed shares and in the variable shares.
  • There is a new syntax option to define a ProfileHistogram, which is especially convenient for iterables and random factories.
  • Utilities:
    • Add iterator_integers_fixed_sum: iterate over vectors of integers with a fixed sum.
    • Add iterate_simplex_grid: iterate over the points in the simplex, with rational coordinates of a given denominator.
    • Add allowed_ballots: allowed ballots in a voting rule.
  • Complete revision of the tutorials.

0.20.0 (2020-03-03): Symbolic Computation

  • Profile and its subclasses, TauVector, Asymptotic and its constructors (such as Asymptotic.poisson_value, Asymptotic.poisson_eq, etc.) accept an optional argument symbolic. If False (default), then all computations are numeric as before. If True, then almost all computations are symbolic; the only exception is when the trio event can be evaluated only via the Dual Magnitude Theorem. Please note that:
    • This feature relies on the external package sympy and works with its current version (1.5.1) but we cannot guarantee that it will still work with future versions of sympy.
    • When activated, it slows downs the computation considerably. In particular, it is strongly advised not to use fictitious play or iterated voting in symbolic mode.
  • Equality and closeness tests:
    • Asymptotic.isclose is renamed to look_equal: in numeric mode, it is still a closeness test, but in symbolic mode, it is an equality test.
    • Remove StrategyThreshold.isclose: this method was not used anymore.
  • Event and its subclasses take a TauVector as input, instead of the dictionary of its coefficients. Firstly, it speeds up computation. Secondly, it avoids a minor bug in symbolic mode.
  • Utilities:
    • Add the classes ComputationEngine, ComputationEngineNumeric and ComputationEngineSymbolic, defining how some mathematical operations are performed.
    • Add the function computation_engine: choose the computation engine.
    • Remove the utility function barycenter and include it as a method in ComputationEngine.

0.19.0 (2020-02-27): Mixed Strategies

  • StrategyThreshold: for each ranking, there is a threshold (like before) and an optional ratio_optimistic. Voters whose utility for their second candidate is equal to the threshold of the strategy are split: a share ratio_optimistic behave as if the threshold was higher (in Approval, they vote only for their top candidate) and the rest behave as if the threshold was lower (in Approval, they vote for their two first candidates). Hence the strategy is mixed. Note that this only makes a difference when the profile has “atoms” (concentration of voters on a single utility point); currently, this is only the case in ProfileDiscrete.
  • For ProfileDiscrete, fictitious play and iterated voting consider that the responses use a ratio of optimistic voters equal to 1/2.
  • Add ProfileCardinalContinuous: this abstract class is a child of ProfileCardinal and a parent class of ProfileNoisyDiscrete and ProfileHistogram. In these profiles, the ratios of optimistic voters are not important because there is no “atom”.
  • GeneratorStrategyThresholdUniform: for each ranking, the ratio of optimistic voters is also chosen uniformly.
  • The utility DictPrintingInOrderIgnoringNone now also ignores values that are iterables containing only None.

0.18.0 (2020-02-26): Improved Ternary Plots

  • Nicer colors than before. For example, an equal mix of candidate a (red) and b (green) was brownish, whereas it is now yellow. Similarly, a mix of the three candidates (red, green, blue) was gray, and it is now white. Etc.
  • Improved ternary plot shortcuts ternary_plot_n_equilibria, ternary_plot_winners_at_equilibrium and ternary_plot_winning_frequencies:
    • New versions of these functions with more options. Cf. the tutorial on ternary plots.
    • Add class SimplexToProfile to map a point of the simplex to a profile. This includes the possibility of having fixed additional voters.
  • TernaryAxesSubplotPoisson:
    • Add methods legend_color_patches and legend_palette: two different styles of legends for candidate heat maps.
    • The method heatmap_candidates has a new parameter legend_style.
    • The method annotate_condorcet has a new parameter d_order_fixed_share to account for fixed additional voters.
    • In several methods, the old parameters color_a, color_b and color_c are suppressed, because the colors for a, b, c are not modifiable anymore.
  • Random strategies:
    • Add GeneratorStrategyTwelveUniform.
    • Add method Profile.random_strategy: return a random strategy that is suitable for the profile (e.g. an ordinal strategy for an ordinal profile, etc.).
    • ProfileCardinal.iterated_voting and ProfileCardinal.fictitious_play now accept the parameter init='random' for an initialization with a random strategy.
  • Add Profile.order_and_label: order and label of a discrete type. This auxiliary function is used for the ternary plots.

0.17.0 (2020-02-24): Analyzed Strategies

  • Profile and its subclasses:
    • The method analyzed_strategies now inputs an iterator of strategies: it perform an analysis on all the strategies given by this iterator.
    • Add pre-defined iterators of strategies:
      • strategies_ordinal is defined for any profile.
      • strategies_pure is defined for any discrete profile, such as ProfileDiscrete or ProfileTwelve.
      • strategies_group is defined for any profile where a reasonable notion of “group” is defined, such as ProfileNoisyDiscrete or ProfileHistogram.
    • Add the attributes analyzed_strategies_ordinal, analyzed_strategies_pure, analyzed_strategies_group. Not only do they provide shortcuts combining analyzed_strategies with the relevant iterator, but they also have the added value of being cached properties: if the user accesses the same attribute several times, it is only computed once.
    • Remove the attribute winners_at_equilibrium. Instead, the corresponding attribute is added to the class AnalyzedStrategies. This gives more flexibility because it is defined for any AnalyzedStrategies object.
  • The consequences on ternary plots are temporary and are likely to change in the near future, with a new release focusing on improved ternary plots.
    • ternary_plot_winners_at_equilibrium becomes ternary_plot_winners_at_equilibrium_ordinal.
    • ternary_plot_n_bloc_equilibria becomes ternary_plot_n_equilibria_ordinal.
  • Strategy.deepcopy_with_attached_profile now also copies the voting rule of the given profile.

0.16.1 (2020-02-24): More Flexible Initialization of ProfileNoisyDiscrete

  • ProfileNoisyDiscrete: add a parameter noise that enables not to mention explicitly the value of the noise for each group of voters. This is especially convenient in the quite common case where all groups of voters have the same noise.

0.16.0 (2020-02-22): ProfileNoisyDiscrete

  • Add ProfileNoisyDiscrete: a profile with a discrete distribution of voters, with noise.

0.15.0 (2020-02-20): Weak Orders

  • Implement weak orders:
    • Profile now has attributes d_weak_order_share, support_in_weak_orders, contains_weak_orders, contains_rankings, d_ballot_weak_voters_sincere, d_ballot_weak_voters_fanatic.
    • Subclasses of Profile have a parameter d_weak_order_share.
    • Remove methods ProfileOrdinal.support and ProfileOrdinal.is_generic: with the presence of weak orders, their names had become misleading, whereas support_in_rankings and is_generic_in_ranking is non-ambiguous.
    • TernaryAxesSubplotPoisson.annotate_condorcet now also works with weak orders. However, it may not work on all distributions because it relies on the external package shapely. If there are only rankings, it should still work anyway.
    • Add utilities is_weak_order, is_lover, is_hater, sort_weak_order.
  • Add shortcut functions for some common ternary plots:
    • ternary_plot_n_bloc_equilibria: number of bloc equilibria.
    • ternary_plot_winners_at_equilibrium: winners at equilibrium.
    • ternary_plot_winning_frequencies: winning frequencies in fictitious play.
  • Methods ProfileCardinal.iterated_voting and ProfileCardinal.fictitious_play have a new parameter winning_frequency_update_ratio, indicating how the winning frequencies are computed in case of non-convergence. Note however that in case of convergence to a periodical orbit (for iterated voting), it remains the arithmetic average anyway.
  • Add utility my_division: division of two numbers, trying to be exact if it is reasonable.

0.14.0 (2020-02-16): Flexible Initialization of Iterated Voting / Fictitious Play

  • Instead of a parameter strategy_ini, the methods ProfileCardinal.iterated_voting and ProfileCardinal.fictitious_play now have a parameter init that can be either a strategy (like before), or a tau-vector, or a string 'sincere' or 'fanatic'.

0.13.0 (2020-02-16): Ternary Plots

  • Draw plots on the simplex where points have 3 coordinates summing to 1. Cf. the corresponding tutorial.
    • Intensity heat maps.
    • Candidate heat maps.
    • Annotate the Condorcet regions.
  • Add Profile.winners_at_equilibrium: for the classes of profile that have a method analyzed_strategies, give the set of winners at equilibrium.

0.12.0 (2020-02-09): GeneratorProfileHistogramSinglePeakedUniform

  • Add GeneratorProfileHistogramSinglePeakedUniform: a generator of single-peaked histogram-profiles following the uniform distribution.
  • Add examples of functions to be used as update ratios for ProfileCardinal.fictitious_play: one_over_t_plus_one, one_over_sqrt_t_plus_one, one_over_log_t_plus_two, one_over_log_log_t_plus_fifteen.

0.11.0 (2020-02-09): Winning frequencies in iterated voting / fictitious play

  • ProfileCardinal.iterated_voting and ProfileCardinal.fictitious_play now also output the winning frequency of each candidate (limit frequency in case of convergence, frequency over the history otherwise).
  • New utilities:
    • Add candidates_to_d_candidate_probability: convert a set of candidates to a dictionary of probabilities (random tie-break)
    • Add candidates_to_probabilities: convert a set of candidates to an array of probabilities (random tie-break).
    • Add array_to_d_candidate_value: convert an array to a dictionary of candidates and values.
    • Add d_candidate_value_to_array: convert a dictionary of candidates and values to an array.

0.10.0 (2020-02-09): ProfileDiscrete.analyzed_strategies

  • Implement ProfileDiscrete.analyzed_strategies: exhaustive analysis of all pure strategies of the profile.

0.9.0 (2020-02-09): Plurality and Anti-plurality

  • Implement Plurality and Anti-plurality (cf. the corresponding tutorial).
  • Python 3.5 is not officially supported anymore. However, in practice, the package should still essentially work with Python 3.5, the only notable difference being the order in which the dictionaries are printed.
  • New utilities:
    • Add ballot_two: ballot for the second candidate of a ranking (used for Plurality).
    • Add ballot_one_three: ballot against the second candidate of a ranking (used for Anti-plurality).
    • Add ballot_low_u and ballot_high_u: the ballot chosen by the voters who have a low (resp. high) utility for their middle candidate, depending on the voting rule.
    • Add product_dict: Cartesian product for a dictionary of iterables.
    • Add DictPrintingInOrderIgnoringNone: dictionary that prints in the order of the keys, ignoring value None.
    • In the UtilCache module, add property_deleting_cache: define a property that deletes the cache when set or deleted. This is used for parameters like ratio_sincere, voting_rule, etc.

0.8.1 (2020-02-04): Better Handling of Edge Cases in BestResponse

  • BestResponse: the focus of this release is to correct rare bugs that used to happen when some offsets are very close to 1.
    • API change: BestResponse now takes as parameters the tau-vector and the ranking, instead of all the events that are used for the computation.
    • Exchanged the justifications 'Easy vs difficult pivot' and 'Difficult vs easy pivot' (their usages were switched, even if the result itself was correct).
    • Use the asymptotic method only when there are two consecutive zeros in the “compass diagram” of the tau-vector (instead of: whenever it gives a result). The motivation is that the asymptotic method may rely on events that rely more on numerical approximation than the limit pivot theorem approach.
    • To determine whether pivots are easy or difficult, we rely on expected scores in the duo events, instead of the pseudo-offsets of the trio. The motivation is that in some cases, the trio is computed with a numerical optimizer that relies more on numerical approximation than the duo events, which use only basic operations like addition, multiplication, etc. In the rare cases where the two methods differ, the latter is thus more reliable.
    • Add a sub-algorithm of the “Offset method”, called “Offset method with trio approximation correction”. This is used in some rare cases where both pivots are difficult, but the numeric approximations of the trio event lead to an offset that is equal or even slightly greater than 1 (which is abnormal and leads to infinite geometric sums). In those cases, we now consider that the offset is lower and infinitely close to 1.
    • Corrected a bug in the asymptotic method that could happen when the two personalized pivots had very close magnitudes. This uses the correction of Asymptotic.limit mentioned below.
  • TauVector: added the attribute has_two_consecutive_zeros.
  • Event: now computes the pseudo-offsets, e.g. psi_a, psi_ab, etc.
  • Asymptotic: handles some edge cases more nicely.
    • __str__ displays a coefficient as 0, 1 or -1 only if it is equal to that value. Close is not enough.
    • limit does not use closeness to 0. It is not its role to decide what coefficients are negligible in the context. Only operations like multiplication are allowed to use closeness: for example, if mu_1 and - mu_2 are relatively close, the multiplication operator is allowed to decide that mu_1 + mu_2 is equal to 0.
    • In multiplication, when the two magnitudes are close, the resulting magnitude is now always equal to the maximum. The same applies for the resulting nu when the nu’s are also equal.
  • cached_property: corrected a bug. In the case of nested cached properties, the inner one was sometimes not recorded in cache. It did not lead to incorrect results but slowed down the program.

0.8.0 (2020-01-30): Fanatic voters

  • Implement the notion of fanatic voting, a variant of sincere voting: a given ratio of voters vote for their top candidate only. This is implemented for all subclasses of Profile.
  • The utility barycenter now accepts iterables.
  • Corrected bug: Profile.standardized_version now takes into account the auxiliary parameters like ratio_sincere, well_informed_voters, etc.

0.7.0 (2020-01-30): ProfileDiscrete

  • Add ProfileDiscrete: a profile with a discrete distribution of voters.
  • Subclasses of Profile: better handling of the additional parameters like well_informed_voters or ratio_sincere. In the conversions to string (str or repr), they are now mentioned. They are also used in the equality tests between two profiles.

0.6.0 (2020-01-29): Fictitious Play

  • Implement ProfileCardinal.fictitious_play, where the update ratios of the perceived tau-vector and the actual tau-vector can be functions of the time. It is also faster that ProfileCardinal.iterated_voting, but can not detect cycles (only convergence).
  • ProfileCardinal.iterated_voting_taus is renamed to ProfileCardinal.iterated_voting. It has been generalized by implementing a notion of perceived tau-vector, like for ProfileCardinal.fictitious_play. The syntax has been modified in consequence.
  • ProfileCardinal.iterated_voting_strategies is deprecated and suppressed.
  • Iterated voting and fictitious play do not need a StrategyThreshold as initial strategy, but any strategy that is consistent with the profile subclass. For example, with ProfileTwelve, you can use a StrategyTwelve.
  • Strategy.profile is now a property that can be reassigned after the creation of the object.
  • Add Strategy.deepcopy_with_attached_profile: make a deep copy and attach a given profile.
  • Add the utility to_callable: convert an object to a callable (making it a constant function if it is not callable already).

0.5.1 (2020-01-18): Configure Codecov and Improve Coverage

  • Configure Codecov.
  • Reach 100% coverage for this version.

0.5.0 (2020-01-11): Sincere Voting and Progressive Update in Iterated Voting

  • In iterated voting, implement the possibility to move only progressively towards the best response:
    • Add ProfileCardinal.iterated_voting_taus: at each iteration, a given ratio of voters update their ballot.
    • Replace the former method ProfileCardinal.iterated_voting by ProfileCardinal.iterated_voting_strategies: as in former versions, at each iteration, the threshold utility of each ranking’s strategy is moved in the direction of the best response’s threshold utility. The method now returns a cycle of tau-vectors and the corresponding cycle of best response strategies, in order to be consistent with ProfileCardinal.iterated_voting_taus.
    • Add the utility barycenter: compute a barycenter while respecting the type of one input if the other input has weight 0.
    • Accelerate the algorithm used in iterated voting.
  • In ProfileCardinal, add the possibility of partial sincere voting:
    • Add parameter ratio_sincere: ratio of sincere voters.
    • Add property tau_sincere: the tau-vector if all voters vote sincerely.
    • The former method tau is renamed tau_strategic: the tau_vector if all voters vote strategically.
    • The new method tau takes both sincere and strategic voting into account.
    • The method is_equilibrium has a new implementation to take this feature into account.
  • Add TauVector.isclose: whether the tau-vector is close to another tau-vector (in the sense of math.isclose). This method is used by the new version of ProfileCardinal.is_equilibrium.
  • Add Profile.best_responses_to_strategy: convert a dictionary of best responses to a StrategyThreshold that mentions only the rankings that are present in the profile.
  • In random generators of profiles (GeneratorProfileOrdinalUniform, GeneratorProfileOrdinalGridUniform, GeneratorProfileOrdinalVariations, GeneratorProfileHistogramUniform): instead of having explicit arguments like well_informed_voters or ratio_sincere, there are **kwargs that are directly passed to the __init__ of the relevant Profile subclass.
  • Update the tutorials with these new features.

0.4.0 (2020-01-08): Add image_distribution

  • Add image_distribution: estimate the distribution of f(something) for a random something.
  • Update the tutorial on mass simulations with this new feature.

0.3.0 (2020-01-08): New Random Generators

  • Add new random generators:
    • GeneratorExamples: run another generator until the generated object meets a given test.
    • GeneratorStrategyOrdinalUniform: draw a StrategyOrdinal uniformly.
    • GeneratorProfileOrdinalGridUniform: draw a ProfileOrdinal uniformly on a grid of rational numbers.
    • GeneratorTauVectorGridUniform: draw a TauVector uniformly on a grid of rational numbers.
  • Utilities:
    • Add rand_integers_fixed_sum: draw an array of integers with a given sum.
    • Add rand_simplex_grid: draw a random point in the simplex, with rational coordinates of a given denominator.
    • Update probability: allow for a tuple of generators.
  • Tutorials:
    • Add a tutorial on asymptotic developments.
    • Update the tutorial on mass simulations with the new features.

0.2.1 (2020-01-05): Fix Deployment on PyPI

  • Relaunch deployment.

0.2.0 (2020-01-05): Add Tutorials + Various Minor Improvements

  • Add GeneratorProfileStrategyThreshold.
  • Add ProfileHistogram.plot_cdf.
  • Modify masks_distribution: remove the trailing zeros. This has the same impact on ProfileOrdinal.distribution_equilibria.
  • Modify NiceStatsProfileOrdinal.plot_cutoff: center the textual indications.
  • Replace all notations r with profile and sigma with strategy.
  • Add tutorials.

0.1.1 (2019-12-24): Convert all the Documentation to NumPy Format

  • Convert all the documentation to NumPy format, making it more readable in plain text.

0.1.0 (2019-12-20): First release on PyPI

  • First release on PyPI.
  • Implement only the case of 3 candidates.
  • Deal with ordinal or cardinal profiles.
  • Compute the asymptotic developments of the probability of pivot events when the number of players tends to infinity.
  • Compute the best response to a given tau-vector.
  • Explore automatically a grid of ordinal profiles or a grid of tau-vectors.
  • Perform Monte-Carlo experiments on profiles or tau-vectors.