# -*- coding: utf-8 -*-
"""
Created on Fri Sep 26 09:51:31 2014
Copyright François Durand 2014, 2015
fradurand@gmail.com
This file is part of SVVAMP.
SVVAMP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SVVAMP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SVVAMP. If not, see <http://www.gnu.org/licenses/>.
"""
import numpy as np
from svvamp.Utils import MyLog
[docs]class ElectionResult(MyLog.MyLog):
# _options_parameters is a dictionary of allowed and default options.
# Allowed is a minimal check that will be performed before launching big
# simulations, but other checks might be performed when setting the
# option. Allowed is either a list of values, like ['lazy', 'fast',
# 'exact'], or a function checking if the parameter is correct.
# Example: {'max_grade': dict(allowed=np.isfinite, default=1),
# 'option_example': dict(allowed=[42, 51], default=42)}
_options_parameters = {}
@property
def options_parameters(self):
"""Display options.
Display a overview of available options, their default values and a
minimal indication about what values are allowed for each option. For
more details about a specific option, see its documentation.
"""
return self._options_parameters
def __init__(self, population, **kwargs):
"""Create a simple election (without manipulation).
This is an 'abstract' class. As an end-user, you should always use its
subclasses :attr:`~svvamp.Approval`, :attr:`~svvamp.Plurality`, etc.
:param population: A :class:`~svvamp.Population` object.
:param kwargs: additional keyword parameters. See
:attr:`~svvamp.ElectionResult.options_parameters`.
>>> import svvamp
>>> pop = svvamp.PopulationSpheroid(V=100, C=5)
>>> election = svvamp.Approval(pop, approval_comparator='>=')
"""
super().__init__()
self._log_identity = "ELECTION_RESULT"
# These lines are useless and should pose problems for Exhaustive
# ballot
# TODO: remove these lines after some tests
# self._pop = None
# self._scores = None
# self._ballots = None
# self._w = None
# self._candidates_by_scores_best_to_worst = None
# self._score_w = None
# self._scores_best_to_worst = None
self.pop = population
self._initialize_options(**kwargs)
def _initialize_options(self, **kwargs):
"""Initialize options.
Arguments: option1=value1, option2=value2, etc.
Checks iff option1, option2 are known in self.options_parameters.
For each option in self.options_parameters:
* If a value is given, option is set to this value.
* Otherwise, the default value is used.
N.B.: validity check on the value are not performed here, but in the
setter method for the option.
"""
self._mylog('Initialize options', 1)
for option in kwargs:
if option not in self.options_parameters.keys():
raise ValueError('Unknown option:', option)
for option in self.options_parameters:
if option in kwargs.keys():
setattr(self, option, kwargs[option])
else:
setattr(self, option,
self.options_parameters[option]['default'])
def _forget_all_computations(self):
"""Initialize / forget all computations
Typically used when the population is modified: all results of the
election are initialized then.
In the subclass Election, this will also initialize all manipulation
computations.
"""
self._forget_results()
def _forget_results(self):
"""Initialize / forget election results
This concerns only the results of the election, not the manipulation
computations.
"""
self._scores = None
self._ballots = None
self._w = None
self._candidates_by_scores_best_to_worst = None
self._score_w = None
self._scores_best_to_worst = None
self._forget_results_subclass()
def _forget_results_subclass(self):
"""Initialize / forget election results, specific to a voting system
If a specific voting system has additional variables about the result
of the election, they can be initialized here.
"""
pass
#%% The population
@property
def pop(self):
"""A :class:`~svvamp.Population` object. The population running the
election.
"""
return self._pop
@pop.setter
def pop(self, value):
self._pop = value
# We forget everything: results of an election. In the subclass
# Election, we will also forget manipulation computations.
self._forget_all_computations()
#%% Counting ballots
# Attributes to be implemented in subclasses.
@property
def scores(self):
"""Scores of the candidates in the election.
This function is not implemented in the superclass
:class:`~svvamp.ElectionResult`\ . See specific documentation for each
voting system.
Typical type in most subclasses:
1d or 2d array.
Typical behavior in most subclasses:
If ``scores`` is a 1d array, then ``scores[c]`` is the numerical
score for candidate ``c``.
If ``scores`` is a 2d array, then ``scores[:, c]`` is the score
vector for candidate ``c``.
"""
# It is not mandatory to follow the default expected behavior.
raise NotImplementedError
#%% Counting ballots
# Attributes with default, but frequently redefined in subclasses
@property
def ballots(self):
"""Ballots cast by the voters.
Default type in superclass :class:`~svvamp.ElectionResult`\ :
2d array of integers.
Default behavior in superclass :class:`~svvamp.ElectionResult`\ :
``ballots[v, k]`` =
:attr:`~svvamp.Population.preferences_rk`\ ``[v, k]``.
"""
# This can be overridden by specific voting systems.
# This general method is ok only for ordinal voting systems (and
# even in this case, it can be redefined for something more practical).
if self._ballots is None:
self._mylog("Compute ballots", 1)
self._ballots = self.pop.preferences_rk
return self._ballots
@property
def w(self):
"""Integer (winning candidate).
Default behavior in superclass :class:`~svvamp.ElectionResult`\ :
The candidate with highest value in vector
:attr:`~svvamp.ElectionResult.scores` is declared the
winner. In case of a tie, the tied candidate with lowest index
wins.
"""
# This general method works only if scores are scalar and the best
# score wins.
if self._w is None:
self._mylog("Compute winner", 1)
self._w = np.argmax(self.scores)
return self._w
@property
def candidates_by_scores_best_to_worst(self):
"""1d array of integers. All candidates, sorted from the winner to
the last candidate in the result of the election.
Default behavior in superclass :class:`~svvamp.ElectionResult`\ :
``candidates_by_scores_best_to_worst[k]`` is the
candidate with ``k``\ :sup:`th` highest value in
:attr:`~svvamp.ElectionResult.scores`.
By definition, ``candidates_by_scores_best_to_worst[0]`` =
:attr:`~svvamp.ElectionResult.w`.
"""
# This can be overridden by specific voting systems.
# This general method works only if scores are scalar and the best
# score wins. If the lowest score wins, then
# candidates_by_scores_best_to_worst need to be sorted by ascending
# score...
if self._candidates_by_scores_best_to_worst is None:
self._mylog("Compute candidates_by_scores_best_to_worst", 1)
self._candidates_by_scores_best_to_worst = np.argsort(
-self.scores, kind='mergesort')
return self._candidates_by_scores_best_to_worst
@property
def _v_might_IM_for_c(self):
"""2d array of booleans. _v_might_IM_for_c[v, c] is True unless it is
clearly and easily excluded that v has an individual manipulation in
favor of c. Typically, if v is not pivotal (at all), then it is
False. Specific implementations of this function in subclasses can
also test if v is interested in manipulating for c, but it is not
mandatory.
A non-trivial redefinition of this function is useful for voting
systems where computing IM is costly. For voting systems where it is
cheap, it it not worth the effort.
"""
return np.ones((self.pop.V, self.pop.C), dtype=np.bool)
#%% Counting ballots
# Attributes that are almost always computed here in the superclass.
@property
def score_w(self):
"""Score of the sincere winner.
Default type in superclass :class:`~svvamp.ElectionResult`\ :
Number or 1d array.
Default behavior in superclass :class:`~svvamp.ElectionResult`\ :
If :attr:`~svvamp.ElectionResult.scores` is a 1d array,
then ``score_w`` is
:attr:`~svvamp.ElectionResult.w`'s numerical score:
``score_w = scores[w]``.
If :attr:`~svvamp.ElectionResult.scores` is a 2d array, then
``score_w`` is :attr:`~svvamp.ElectionResult.w`'s score vector:
``score_w = scores[:, w]``.
"""
# Exception: if scores are read in rows (Schulze, Ranked pairs), this
# needs to be redefined.
if self._score_w is None:
self._mylog("Compute winner's score", 1)
if self.scores.ndim == 1:
self._score_w = self.scores[self.w]
elif self.scores.ndim == 2:
self._score_w = self.scores[:, self.w]
else:
raise ValueError(
"'scores' is usually a 1d or 2d array. If you really "
"want it to be something else, you need to redefine "
"'score_w'.")
return self._score_w
@property
def scores_best_to_worst(self):
"""Scores of the candidates, from the winner to the last candidate
of the election.
Default type in superclass :class:`~svvamp.ElectionResult`\ :
1d or 2d array.
Default behavior in superclass :class:`~svvamp.ElectionResult`\ :
``scores_best_to_worst`` is derived from
:attr:`~svvamp.ElectionResult.scores` and
:attr:`~svvamp.ElectionResult.candidates_by_scores_best_to_worst`.
If :attr:`~svvamp.ElectionResult.scores` is a 1d array, then so is
``scores_best_to_worst``. It is defined by
``scores_best_to_worst`` =
``scores[candidates_by_scores_best_to_worst]``.
Then by definition, ``scores_best_to_worst[0]`` =
:attr:`~svvamp.ElectionResult.score_w`.
If :attr:`~svvamp.ElectionResult.scores` is a 2d array, then so is
``scores_best_to_worst``. It is defined by
``scores_best_to_worst`` =
``scores[:, candidates_by_scores_best_to_worst]``.
Then by definition, ``scores_best_to_worst[:, 0]`` =
:attr:`~svvamp.ElectionResult.score_w`.
"""
# Exception: if scores are read in rows (Schulze, Ranked pairs), this
# needs to be redefined.
if self._scores_best_to_worst is None:
self._mylog("Compute scores_best_to_worst", 1)
if self.scores.ndim == 1:
self._scores_best_to_worst = self.scores[
self.candidates_by_scores_best_to_worst]
elif self.scores.ndim == 2:
self._scores_best_to_worst = self.scores[
:, self.candidates_by_scores_best_to_worst]
else:
raise ValueError("'scores' is usually a 1d or 2d " +
"array. If you really want it to be " +
"something else, you need to redefine " +
"'scores_best_to_worst'.")
return self._scores_best_to_worst
@property
def total_utility_w(self):
"""Float. The total utility for the sincere winner
:attr:`~svvamp.ElectionResult.w`. Be careful, this
makes sense only if interpersonal comparison of utilities makes sense.
"""
return self.pop.total_utility_c[self.w]
@property
def mean_utility_w(self):
"""Float. The mean utility for the sincere winner
:attr:`~svvamp.ElectionResult.w`. Be careful, this
makes sense only if interpersonal comparison of utilities makes sense.
"""
return self.pop.mean_utility_c[self.w]
#%% Condorcet efficiency and variants
@property
def w_is_condorcet_admissible(self):
"""Boolean. ``True`` iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is Condorcet-admissible.
Cf. :attr:`~svvamp.Population.condorcet_admissible_candidates`.
"""
return self.pop.condorcet_admissible_candidates[self.w]
@property
def w_is_not_condorcet_admissible(self):
"""Boolean. ``True`` iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a Condorcet-admissible
candidate (whether some exist or not).
Cf. :attr:`~svvamp.Population.condorcet_admissible_candidates`.
"""
return not self.w_is_condorcet_admissible
@property
def w_missed_condorcet_admissible(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
Condorcet-admissible candidate, despite the fact that at least one
exists.
Cf. :attr:`~svvamp.Population.condorcet_admissible_candidates`.
"""
return (self.pop.nb_condorcet_admissible > 0 and
not self.w_is_condorcet_admissible)
@property
def w_is_weak_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a Weak Condorcet winner.
Cf. :attr:`~svvamp.Population.weak_condorcet_winners`.
"""
return self.pop.weak_condorcet_winners[self.w]
@property
def w_is_not_weak_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a Weak Condorcet
winner (whether some exist or not).
Cf. :attr:`~svvamp.Population.weak_condorcet_winners`.
"""
return not self.w_is_weak_condorcet_winner
@property
def w_missed_weak_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a Weak Condorcet
winner, despite the fact that at least one exists.
Cf. :attr:`~svvamp.Population.weak_condorcet_winners`.
"""
return (self.pop.nb_weak_condorcet_winners > 0 and
not self.w_is_weak_condorcet_winner)
@property
def w_is_condorcet_winner_rk_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_rk_ctb`.
"""
return self.w == self.pop.condorcet_winner_rk_ctb
@property
def w_is_not_condorcet_winner_rk_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_rk_ctb`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_rk_ctb
@property
def w_missed_condorcet_winner_rk_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_rk_ctb`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_rk_ctb) and
not self.w_is_condorcet_winner_rk_ctb)
@property
def w_is_condorcet_winner_rk(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_rk`.
"""
return self.w == self.pop.condorcet_winner_rk
@property
def w_is_not_condorcet_winner_rk(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_rk`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_rk
@property
def w_missed_condorcet_winner_rk(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_rk`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_rk) and
not self.w_is_condorcet_winner_rk)
@property
def w_is_condorcet_winner_ut_rel_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`.
"""
return self.w == self.pop.condorcet_winner_ut_rel_ctb
@property
def w_is_not_condorcet_winner_ut_rel_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_ut_rel_ctb
@property
def w_missed_condorcet_winner_ut_rel_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_ut_rel_ctb) and
not self.w_is_condorcet_winner_ut_rel_ctb)
@property
def w_is_condorcet_winner_ut_rel(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_ut_rel`.
"""
return self.w == self.pop.condorcet_winner_ut_rel
@property
def w_is_not_condorcet_winner_ut_rel(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_ut_rel`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_ut_rel
@property
def w_missed_condorcet_winner_ut_rel(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_ut_rel`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_ut_rel) and
not self.w_is_condorcet_winner_ut_rel)
@property
def w_is_condorcet_winner_ut_abs_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`.
"""
return self.w == self.pop.condorcet_winner_ut_abs_ctb
@property
def w_is_not_condorcet_winner_ut_abs_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_ut_abs_ctb
@property
def w_missed_condorcet_winner_ut_abs_ctb(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_ut_abs_ctb`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_ut_abs_ctb) and
not self.w_is_condorcet_winner_ut_abs_ctb)
@property
def w_is_condorcet_winner_ut_abs(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.condorcet_winner_ut_abs`.
"""
return self.w == self.pop.condorcet_winner_ut_abs
@property
def w_is_not_condorcet_winner_ut_abs(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.condorcet_winner_ut_abs`
(whether one exists or not).
"""
return not self.w_is_condorcet_winner_ut_abs
@property
def w_missed_condorcet_winner_ut_abs(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.condorcet_winner_ut_abs`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.condorcet_winner_ut_abs) and
not self.w_is_condorcet_winner_ut_abs)
@property
def w_is_resistant_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is a
:attr:`~svvamp.Population.resistant_condorcet_winner`.
"""
return self.w == self.pop.resistant_condorcet_winner
@property
def w_is_not_resistant_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not a
:attr:`~svvamp.Population.resistant_condorcet_winner`
(whether one exists or not).
"""
return not self.w_is_resistant_condorcet_winner
@property
def w_missed_resistant_condorcet_winner(self):
"""Boolean. True iff the sincere winner
:attr:`~svvamp.ElectionResult.w` is not the
:attr:`~svvamp.Population.resistant_condorcet_winner`,
despite the fact that she exists.
"""
return (not np.isnan(self.pop.resistant_condorcet_winner) and
not self.w_is_resistant_condorcet_winner)
def demo(self, log_depth=1):
"""Demonstrate the methods of :class:`~svvamp.ElectionResult` class.
s
:param log_depth: Integer from 0 (basic info) to 3 (verbose).
"""
old_log_depth = self._log_depth
self._log_depth = log_depth
MyLog.print_big_title('Population Class')
self.pop.demo()
MyLog.print_big_title('ElectionResult Class')
MyLog.print_title("Results")
MyLog.printm("pop.preferences_ut (reminder) =",
self.pop.preferences_ut)
# MyLog.printm("pop.preferences_borda_ut =",
# self.pop.preferences_borda_ut)
# MyLog.printm("pop.preferences_borda_rk =",
# self.pop.preferences_borda_rk)
MyLog.printm("pop.preferences_rk (reminder) =",
self.pop.preferences_rk)
MyLog.printm("ballots =", self.ballots)
MyLog.printm("scores =", self.scores)
MyLog.printm("candidates_by_scores_best_to_worst",
self.candidates_by_scores_best_to_worst)
MyLog.printm("scores_best_to_worst", self.scores_best_to_worst)
print("w =", self.w)
print("score_w =", self.score_w)
print("total_utility_w =", self.total_utility_w)
MyLog.print_title("Condorcet efficiency (rk)")
print("w (reminder) =", self.w)
print("")
print("condorcet_winner_rk_ctb =",
self.pop.condorcet_winner_rk_ctb)
print("w_is_condorcet_winner_rk_ctb =",
self.w_is_condorcet_winner_rk_ctb)
print("w_is_not_condorcet_winner_rk_ctb =",
self.w_is_not_condorcet_winner_rk_ctb)
print("w_missed_condorcet_winner_rk_ctb =",
self.w_missed_condorcet_winner_rk_ctb)
print("")
print("condorcet_winner_rk =",
self.pop.condorcet_winner_rk)
print("w_is_condorcet_winner_rk =",
self.w_is_condorcet_winner_rk)
print("w_is_not_condorcet_winner_rk =",
self.w_is_not_condorcet_winner_rk)
print("w_missed_condorcet_winner_rk =",
self.w_missed_condorcet_winner_rk)
MyLog.print_title("Condorcet efficiency (relative)")
print("w (reminder) =", self.w)
print("")
print("condorcet_winner_ut_rel_ctb =",
self.pop.condorcet_winner_ut_rel_ctb)
print("w_is_condorcet_winner_ut_rel_ctb =",
self.w_is_condorcet_winner_ut_rel_ctb)
print("w_is_not_condorcet_winner_ut_rel_ctb =",
self.w_is_not_condorcet_winner_ut_rel_ctb)
print("w_missed_condorcet_winner_ut_rel_ctb =",
self.w_missed_condorcet_winner_ut_rel_ctb)
print("")
print("condorcet_winner_ut_rel =",
self.pop.condorcet_winner_ut_rel)
print("w_is_condorcet_winner_ut_rel =",
self.w_is_condorcet_winner_ut_rel)
print("w_is_not_condorcet_winner_ut_rel =",
self.w_is_not_condorcet_winner_ut_rel)
print("w_missed_condorcet_winner_ut_rel =",
self.w_missed_condorcet_winner_ut_rel)
MyLog.print_title("Condorcet efficiency (absolute)")
print("w (reminder) =", self.w)
print("")
MyLog.printm("condorcet_admissible_candidates =",
self.pop.condorcet_admissible_candidates)
print("w_is_condorcet_admissible =",
self.w_is_condorcet_admissible)
print("w_is_not_condorcet_admissible =",
self.w_is_not_condorcet_admissible)
print("w_missed_condorcet_admissible =",
self.w_missed_condorcet_admissible)
print("")
MyLog.printm("weak_condorcet_winners =",
self.pop.weak_condorcet_winners)
print("w_is_weak_condorcet_winner =",
self.w_is_weak_condorcet_winner)
print("w_is_not_weak_condorcet_winner =",
self.w_is_not_weak_condorcet_winner)
print("w_missed_weak_condorcet_winner =",
self.w_missed_weak_condorcet_winner)
print("")
print("condorcet_winner_ut_abs_ctb =",
self.pop.condorcet_winner_ut_abs_ctb)
print("w_is_condorcet_winner_ut_abs_ctb =",
self.w_is_condorcet_winner_ut_abs_ctb)
print("w_is_not_condorcet_winner_ut_abs_ctb =",
self.w_is_not_condorcet_winner_ut_abs_ctb)
print("w_missed_condorcet_winner_ut_abs_ctb =",
self.w_missed_condorcet_winner_ut_abs_ctb)
print("")
print("condorcet_winner_ut_abs =",
self.pop.condorcet_winner_ut_abs)
print("w_is_condorcet_winner_ut_abs =",
self.w_is_condorcet_winner_ut_abs)
print("w_is_not_condorcet_winner_ut_abs =",
self.w_is_not_condorcet_winner_ut_abs)
print("w_missed_condorcet_winner_ut_abs =",
self.w_missed_condorcet_winner_ut_abs)
print("")
print("resistant_condorcet_winner =",
self.pop.resistant_condorcet_winner)
print("w_is_resistant_condorcet_winner =",
self.w_is_resistant_condorcet_winner)
print("w_is_not_resistant_condorcet_winner =",
self.w_is_not_resistant_condorcet_winner)
print("w_missed_resistant_condorcet_winner =",
self.w_missed_resistant_condorcet_winner)
self._log_depth = old_log_depth