test adding condorcet vote
This commit is contained in:
parent
1e8adfa5d5
commit
0a30f39eb4
182
A.Global_Example.php
Normal file
182
A.Global_Example.php
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\ {Condorcet, Election};
|
||||||
|
use CondorcetPHP\Condorcet\Utils\CondorcetUtil;
|
||||||
|
|
||||||
|
require_once __DIR__ . 'condorcet/__CondorcetAutoload.php';
|
||||||
|
|
||||||
|
Condorcet::$UseTimer = true;
|
||||||
|
$election = new Election;
|
||||||
|
|
||||||
|
// Inluding Data
|
||||||
|
|
||||||
|
require_once 'vote_data'.\DIRECTORY_SEPARATOR.'ComplexeVoteConf.php';
|
||||||
|
|
||||||
|
\define('TEST_NAME', 'Condorcet Global Example');
|
||||||
|
|
||||||
|
// View :
|
||||||
|
?><!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title><?php echo TEST_NAME; ?></title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.votant {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 2cm;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header style="text-align:center;">
|
||||||
|
<img src="../../condorcet-logo.png" alt="Condorcet Class" style="width:15%;">
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<h1><?php echo TEST_NAME; ?></h1>
|
||||||
|
|
||||||
|
<em style="font-weight:bold;"><a href="https://github.com/julien-boudry/Condorcet" target="_blank">Condorcet Class</a> version : <?php echo Condorcet::getVersion(); ?></em><br>
|
||||||
|
|
||||||
|
<em>
|
||||||
|
Number of Candidates :
|
||||||
|
<?php echo $election->countCandidates(); ?>
|
||||||
|
|
|
||||||
|
Number of votes :
|
||||||
|
<?php echo $election->countVotes(); ?>
|
||||||
|
</em>
|
||||||
|
|
||||||
|
<h2>Candidates list :</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
foreach ($election->getCandidatesList() as $candidatName) {
|
||||||
|
echo '<li>'.$candidatName.'</li>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Registered votes details :</h2>
|
||||||
|
<?php
|
||||||
|
foreach ($election->getVotesList() as $vote) {
|
||||||
|
echo '<div class="votant">';
|
||||||
|
|
||||||
|
echo '<strong style="color:green;">'.implode(' / ', $vote->getTags()).'</strong><br>';
|
||||||
|
|
||||||
|
echo '<ol>';
|
||||||
|
|
||||||
|
foreach ($vote as $rank => $value) {
|
||||||
|
if ($rank === 'tag') {
|
||||||
|
continue;
|
||||||
|
} ?>
|
||||||
|
|
||||||
|
<li><?php echo implode(',', $value); ?></li>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</ol><br></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hr style="clear:both;">
|
||||||
|
|
||||||
|
<h2>Winner by <a target="blank" href="http://en.wikipedia.org/wiki/Condorcet_method">natural Condorcet</a> :</h2>
|
||||||
|
|
||||||
|
<strong style="color:green;">
|
||||||
|
<?php
|
||||||
|
if ($election->getWinner() !== null) {
|
||||||
|
echo $election->getWinner();
|
||||||
|
} else {
|
||||||
|
echo '<span style="color:red;">The votes of this group do not allow natural Condorcet winner because of <a href="http://fr.wikipedia.org/wiki/Paradoxe_de_Condorcet" target="_blank">Condorcet paradox</a>.</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<br>
|
||||||
|
<em style="color:green;">computed in <?php echo number_format($election->getLastTimer(), 5); ?> second(s).</em> </strong>
|
||||||
|
|
||||||
|
<h2>Loser by <a target="blank" href="http://en.wikipedia.org/wiki/Condorcet_method">natural Condorcet</a> :</h2>
|
||||||
|
|
||||||
|
<strong style="color:green;">
|
||||||
|
<?php
|
||||||
|
if ($election->getLoser() !== null) {
|
||||||
|
echo $election->getLoser();
|
||||||
|
} else {
|
||||||
|
echo '<span style="color:red;">The votes of this group do not allow natural Condorcet loser because of <a href="http://fr.wikipedia.org/wiki/Paradoxe_de_Condorcet" target="_blank">Condorcet paradox</a>.</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<br>
|
||||||
|
<em style="color:green;">computed in <?php echo number_format($election->getLastTimer(), 5); ?> second(s).</em> </strong>
|
||||||
|
</strong>
|
||||||
|
|
||||||
|
<br><br><hr>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) { ?>
|
||||||
|
|
||||||
|
<h2>Ranking by <?php echo $method; ?>:</h2>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$result = $election->getResult($method);
|
||||||
|
$lastTimer = $election->getLastTimer();
|
||||||
|
|
||||||
|
if ($method === 'Kemeny–Young' && !empty($result->getWarning(\CondorcetPHP\Condorcet\Algo\Methods\KemenyYoung\KemenyYoung::CONFLICT_WARNING_CODE))) {
|
||||||
|
$kemeny_conflicts = explode(';', $result->getWarning(\CondorcetPHP\Condorcet\Algo\Methods\KemenyYoung\KemenyYoung::CONFLICT_WARNING_CODE)[0]['msg']);
|
||||||
|
|
||||||
|
echo '<strong style="color:red;">Arbitrary results: Kemeny-Young has '.$kemeny_conflicts[0].' possible solutions at score '.$kemeny_conflicts[1].'</strong>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<?php var_dump(CondorcetUtil::format($result)); ?>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<em style="color:green;">computed in <?php echo $lastTimer; ?> second(s).</em>
|
||||||
|
|
||||||
|
<?php }
|
||||||
|
|
||||||
|
?>
|
||||||
|
<br><br><hr><br>
|
||||||
|
<strong style="color:green;">Total computed in <?php echo number_format($election->getGlobalTimer(), 5); ?> second(s).</strong>
|
||||||
|
<br>
|
||||||
|
<?php var_dump($election->getTimerManager()->getHistory()); ?>
|
||||||
|
<br><br><hr>
|
||||||
|
|
||||||
|
<h2>Computing statistics :</h2>
|
||||||
|
|
||||||
|
<h3>Pairwise :</h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<?php var_dump(CondorcetUtil::format($election->getPairwise())); ?>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) { ?>
|
||||||
|
<h3>Stats for <?php echo $method; ?>:</h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<?php var_dump(CondorcetUtil::format($election->getResult($method)->getStats())); ?>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
<br><br><hr>
|
||||||
|
|
||||||
|
<h2>Debug Data :</h2>
|
||||||
|
|
||||||
|
<h4>Defaut method (not used explicitly before) :</h4>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<?php var_dump(CondorcetUtil::format(Condorcet::getDefaultMethod())); ?>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!-- <h4>CondorcetUtil::format (for debug only) :</h4>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<?php // CondorcetUtil::format($election);?>
|
||||||
|
</pre> -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
include/Condorcet/Assets/Logos/condorcet-logo.png
Normal file
BIN
include/Condorcet/Assets/Logos/condorcet-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
BIN
include/Condorcet/Assets/Logos/condorcet-logo.psd
Normal file
BIN
include/Condorcet/Assets/Logos/condorcet-logo.psd
Normal file
Binary file not shown.
37
include/Condorcet/Benchmarks/AddVotesBench.php
Normal file
37
include/Condorcet/Benchmarks/AddVotesBench.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Election;
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
ini_set('memory_limit', '51200M');
|
||||||
|
|
||||||
|
class AddVotesBench
|
||||||
|
{
|
||||||
|
protected Election $election;
|
||||||
|
|
||||||
|
#[Bench\OutputTimeUnit('seconds')]
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(3)]
|
||||||
|
#[Bench\Revs(1)]
|
||||||
|
public function benchVotesWithManyCandidates(): void
|
||||||
|
{
|
||||||
|
$randomizer = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar('CondorcetReproductibleRandomSeed'));
|
||||||
|
|
||||||
|
$this->election = $election = new Election;
|
||||||
|
|
||||||
|
$candidates = [];
|
||||||
|
|
||||||
|
for ($i=0; $i < 100; $i++) {
|
||||||
|
$candidates[] = $election->addCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < 1_000; $i++) {
|
||||||
|
$oneVote = $randomizer->shuffleArray($candidates);
|
||||||
|
$election->addVote($oneVote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
include/Condorcet/Benchmarks/History/AddVotesBench.md
Normal file
45
include/Condorcet/Benchmarks/History/AddVotesBench.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# v4.0-beta1 Branch
|
||||||
|
|
||||||
|
* AMD Ryzen 9 5900X
|
||||||
|
|
||||||
|
PHPBench (1.2.5)
|
||||||
|
with PHP version 8.1.6, xdebug ❌, opcache ✔ (with JIT Tracing)
|
||||||
|
|
||||||
|
```php
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(3)]
|
||||||
|
#[Bench\Revs(1)]
|
||||||
|
```
|
||||||
|
|
||||||
|
# v4.0-beta1 Branch
|
||||||
|
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
| 0 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 59,269,648b | 0.714s | -1.14σ | -0.10% |
|
||||||
|
| 1 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 58,871,856b | 0.715s | -0.16σ | -0.01% |
|
||||||
|
| 2 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 58,871,856b | 0.716s | +1.30σ | +0.12% |
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
|
||||||
|
|
||||||
|
# v3.3.3
|
||||||
|
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
| 0 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 59,029,584b | 18.906s | -1.00σ | -0.69% |
|
||||||
|
| 1 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 59,029,504b | 18.990s | -0.36σ | -0.25% |
|
||||||
|
| 2 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 59,030,016b | 19.218s | +1.36σ | +0.94% |
|
||||||
|
+------+---------------+------------------------------+-----+------+-------------+----------+--------------+----------------+
|
||||||
|
|
||||||
|
# v3.2
|
||||||
|
|
||||||
|
+------+---------------+------------------------------+-----+------+--------------+----------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------+------------------------------+-----+------+--------------+----------+--------------+----------------+
|
||||||
|
| 0 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 117,355,360b | 18.869s | +0.96σ | +0.84% |
|
||||||
|
| 1 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 117,023,280b | 18.488s | -1.38σ | -1.20% |
|
||||||
|
| 2 | AddVotesBench | benchVotesWithManyCandidates | | 1 | 117,023,280b | 18.780s | +0.42σ | +0.36% |
|
||||||
|
+------+---------------+------------------------------+-----+------+--------------+----------+--------------+----------------+
|
1539
include/Condorcet/Benchmarks/History/MethodsBench.md
Normal file
1539
include/Condorcet/Benchmarks/History/MethodsBench.md
Normal file
File diff suppressed because it is too large
Load Diff
61
include/Condorcet/Benchmarks/History/WeakRef_v3.3.md
Normal file
61
include/Condorcet/Benchmarks/History/WeakRef_v3.3.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Conclusion
|
||||||
|
When the garbage collector is actively used, there is no significant difference (memory used). If not, the implementation of weak references is much more economic.
|
||||||
|
|
||||||
|
# v3.2 Branch
|
||||||
|
|
||||||
|
## Time Centric
|
||||||
|
```
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------------+----------------------+-----+------+-------------+---------------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------------+----------------------+-----+------+-------------+---------------+--------------+----------------+
|
||||||
|
| 0 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 27,103,632b | 258,943.200μs | -0.10σ | -0.05% |
|
||||||
|
| 1 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 27,103,632b | 257,405.200μs | -1.24σ | -0.65% |
|
||||||
|
| 2 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 27,103,632b | 261,179.300μs | +1.55σ | +0.81% |
|
||||||
|
| 3 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 27,103,632b | 258,782.800μs | -0.22σ | -0.11% |
|
||||||
|
+------+---------------------+----------------------+-----+------+-------------+---------------+--------------+----------------+
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Centric
|
||||||
|
```
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
| 0 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 6,883,080b | 2,605,364.000μs | -0.60σ | -0.42% |
|
||||||
|
| 1 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 6,883,080b | 2,591,650.000μs | -1.33σ | -0.95% |
|
||||||
|
| 2 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 6,883,080b | 2,633,507.000μs | +0.92σ | +0.65% |
|
||||||
|
| 3 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 6,883,080b | 2,635,192.000μs | +1.01σ | +0.72% |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# v3.3 Branch
|
||||||
|
|
||||||
|
## Time Centric
|
||||||
|
```
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+---------------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+---------------+--------------+----------------+
|
||||||
|
| 0 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,045,952b | 279,167.000μs | -0.30σ | -0.12% |
|
||||||
|
| 1 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,045,952b | 281,010.000μs | +1.30σ | +0.54% |
|
||||||
|
| 2 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,045,952b | 280,016.000μs | +0.43σ | +0.18% |
|
||||||
|
| 3 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,045,952b | 277,863.500μs | -1.43σ | -0.59% |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+---------------+--------------+----------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Centric
|
||||||
|
```
|
||||||
|
Subjects: 1, Assertions: 0, Failures: 0, Errors: 0
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
| iter | benchmark | subject | set | revs | mem_peak | time_avg | comp_z_value | comp_deviation |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
| 0 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,041,560b | 2,847,455.000μs | +1.37σ | +0.80% |
|
||||||
|
| 1 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,041,560b | 2,801,896.000μs | -1.40σ | -0.81% |
|
||||||
|
| 2 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,041,560b | 2,829,893.000μs | +0.30σ | +0.18% |
|
||||||
|
| 3 | IntensiveUsageBench | benchSimpleManyVotes | | 10 | 7,041,560b | 2,820,355.000μs | -0.28σ | -0.16% |
|
||||||
|
+------+---------------------+----------------------+-----+------+------------+-----------------+--------------+----------------+
|
||||||
|
```
|
39
include/Condorcet/Benchmarks/Instructions.md
Normal file
39
include/Condorcet/Benchmarks/Instructions.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
## Instructions
|
||||||
|
|
||||||
|
``` composer require --dev phpbench/phpbench ```
|
||||||
|
|
||||||
|
### Simple Suite
|
||||||
|
#### Time Centric
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/SimpleUsageBench.php --report=default ```
|
||||||
|
#### Memory Centric
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/SimpleUsageBench.php --report=default --executor=memory_centric_microtime ```
|
||||||
|
|
||||||
|
|
||||||
|
### Intensive Suite
|
||||||
|
#### Time Centric
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/IntensiveUsageBench.php --report=default ```
|
||||||
|
#### Memory Centric
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/IntensiveUsageBench.php --report=default --executor=memory_centric_microtime ```
|
||||||
|
|
||||||
|
|
||||||
|
### Run Specifics developement benchmarks
|
||||||
|
|
||||||
|
#### Pairwise Optimisation on Update (between commits)
|
||||||
|
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/PairwiseUpdateOptimizationBench.php --report=default --executor=memory_centric_microtime ```
|
||||||
|
|
||||||
|
#### Pairwse and addVote performance related to election number of candidates
|
||||||
|
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/PairwiseNumberOfCandidatesBench.php --report=default ```
|
||||||
|
|
||||||
|
#### Methods speed test by Candidates numbers
|
||||||
|
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/MethodsNonProportionalBench.php --report=aggregate ```
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/MethodsProportionalBench.php --report=aggregate ```
|
||||||
|
|
||||||
|
#### Add Votes (1000 votes with 100 candidates)
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/AddVotesBench.php --report=default ```
|
||||||
|
|
||||||
|
#### Kemeny-Young Speed & Memory Test
|
||||||
|
|
||||||
|
``` ./vendor/bin/phpbench run Benchmarks/KemenyYoungBench.php --report=default --executor=memory_centric_microtime ```
|
67
include/Condorcet/Benchmarks/IntensiveUsageBench.php
Normal file
67
include/Condorcet/Benchmarks/IntensiveUsageBench.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\{Condorcet, Election};
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
class IntensiveUsageBench
|
||||||
|
{
|
||||||
|
#[Bench\Warmup(3)]
|
||||||
|
#[Bench\Iterations(5)]
|
||||||
|
#[Bench\Revs(10)]
|
||||||
|
#[Bench\OutputTimeUnit('milliseconds')]
|
||||||
|
public function benchSimpleManyVotes(): void
|
||||||
|
{
|
||||||
|
$election = new Election;
|
||||||
|
$election->allowsVoteWeight(true);
|
||||||
|
$election->setNumberOfSeats(2);
|
||||||
|
|
||||||
|
$election->parseCandidates('A;B;C;D;E;F');
|
||||||
|
|
||||||
|
$election->parseVotes('
|
||||||
|
Ultimate Question of Life || A>B>C ^42 * 42
|
||||||
|
C=A>B ^2 * 200
|
||||||
|
B>C
|
||||||
|
E > B > C > A ^80 *50
|
||||||
|
F > B > G > H > A* 250
|
||||||
|
D = B = E > F ^6 * 48
|
||||||
|
');
|
||||||
|
|
||||||
|
$election->getCondorcetWinner();
|
||||||
|
$election->getCondorcetLoser();
|
||||||
|
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$election->getResult($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
$election->setImplicitRanking(false);
|
||||||
|
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$election->getResult($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
$election->allowsVoteWeight(false);
|
||||||
|
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$election->getResult($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
$election->parseVotes('
|
||||||
|
Ultimate Question of Life || C>B>A ^42 * 42
|
||||||
|
C=A=B ^2 * 200
|
||||||
|
B>C
|
||||||
|
A > C >E ^80 *50
|
||||||
|
G > B > H > F* 250
|
||||||
|
C = B = E > A ^6 * 48
|
||||||
|
');
|
||||||
|
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$election->getResult($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
$votes = $election->getVotesListAsString();
|
||||||
|
}
|
||||||
|
}
|
47
include/Condorcet/Benchmarks/KemenyYoungBench.php
Normal file
47
include/Condorcet/Benchmarks/KemenyYoungBench.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Algo\Methods\KemenyYoung\KemenyYoung;
|
||||||
|
use CondorcetPHP\Condorcet\Election;
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
ini_set('memory_limit', '51200M');
|
||||||
|
|
||||||
|
// Must use --executor=memory_centric_microtime
|
||||||
|
|
||||||
|
class KemenyYoungBench
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
KemenyYoung::$MaxCandidates = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideCandidatesCount(): \Generator
|
||||||
|
{
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
yield $i => ['candidatesCount' => $i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[Bench\ParamProviders(['provideCandidatesCount'])]
|
||||||
|
#[Bench\OutputTimeUnit('milliseconds')]
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(3)]
|
||||||
|
#[Bench\Revs(4)]
|
||||||
|
public function benchKemenyYoung(array $params): void
|
||||||
|
{
|
||||||
|
$election = new Election;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $params['candidatesCount']; $i++) {
|
||||||
|
$candidates[] = $election->addCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
$election->addVote($candidates);
|
||||||
|
|
||||||
|
$result = $election->getResult('Kemeny–Young');
|
||||||
|
}
|
||||||
|
}
|
89
include/Condorcet/Benchmarks/MethodsNonProportionalBench.php
Normal file
89
include/Condorcet/Benchmarks/MethodsNonProportionalBench.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Algo\Methods\KemenyYoung\KemenyYoung;
|
||||||
|
use CondorcetPHP\Condorcet\Algo\Methods\RankedPairs\RankedPairs_Core;
|
||||||
|
use CondorcetPHP\Condorcet\Algo\StatsVerbosity;
|
||||||
|
use CondorcetPHP\Condorcet\{Condorcet, Election};
|
||||||
|
use CondorcetPHP\Condorcet\Throwable\MethodLimitReachedException;
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
ini_set('memory_limit', '51200M');
|
||||||
|
|
||||||
|
class MethodsNonProportionalBench
|
||||||
|
{
|
||||||
|
public bool $IS_A_PROPORTIONAL_BENCH = false;
|
||||||
|
|
||||||
|
public array $numberOfCandidates = [3, 5, 6, 7, 8, 9, 10, 11, 20, 30, 40, 50, 60, 70, 80, 90, 100];
|
||||||
|
|
||||||
|
protected Election $election;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
RankedPairs_Core::$MaxCandidates = null;
|
||||||
|
KemenyYoung::$MaxCandidates = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function buildElection(int $numberOfCandidates, int $numberOfVotes): void
|
||||||
|
{
|
||||||
|
$randomizer = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar('CondorcetReproductibleRandomSeed'));
|
||||||
|
|
||||||
|
$this->election = $election = new Election;
|
||||||
|
$this->election->setNumberOfSeats(max(1, (int) ($numberOfCandidates / 3)));
|
||||||
|
$this->election->setStatsVerbosity(StatsVerbosity::STD);
|
||||||
|
|
||||||
|
$candidates = [];
|
||||||
|
|
||||||
|
for ($i=0; $i < $numberOfCandidates; $i++) {
|
||||||
|
$candidates[] = $election->addCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $numberOfVotes; $i++) {
|
||||||
|
$oneVote = $randomizer->shuffleArray($candidates);
|
||||||
|
$election->addVote($oneVote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideMethods(): \Generator
|
||||||
|
{
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$class = Condorcet::getMethodClass($method);
|
||||||
|
|
||||||
|
if ($class::IS_PROPORTIONAL === $this->IS_A_PROPORTIONAL_BENCH) {
|
||||||
|
yield $method => ['method' => $method];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideNumberOfCandidates(): \Generator
|
||||||
|
{
|
||||||
|
foreach ($this->numberOfCandidates as $n) {
|
||||||
|
yield $n => ['numberOfCandidates' => $n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp(array $params): void
|
||||||
|
{
|
||||||
|
$this->buildElection($params['numberOfCandidates'], 1_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Bench\OutputTimeUnit('seconds')]
|
||||||
|
#[Bench\ParamProviders(['provideMethods', 'provideNumberOfCandidates'])]
|
||||||
|
#[Bench\BeforeMethods('setUp')]
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(3)]
|
||||||
|
#[Bench\Revs(1)]
|
||||||
|
public function benchByCandidates(array $params): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = $this->election->getResult($params['method']);
|
||||||
|
} catch (MethodLimitReachedException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->election->cleanupCalculator();
|
||||||
|
}
|
||||||
|
}
|
21
include/Condorcet/Benchmarks/MethodsProportionalBench.php
Normal file
21
include/Condorcet/Benchmarks/MethodsProportionalBench.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Algo\Methods\STV\CPO_STV;
|
||||||
|
|
||||||
|
ini_set('memory_limit', '51200M');
|
||||||
|
|
||||||
|
class MethodsProportionalBench extends MethodsNonProportionalBench
|
||||||
|
{
|
||||||
|
public bool $IS_A_PROPORTIONAL_BENCH = true;
|
||||||
|
|
||||||
|
public array $numberOfCandidates = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 70, 80, 90, 100];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
CPO_STV::$MaxOutcomeComparisons = 200_000;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Algo\Methods\RankedPairs\RankedPairs_Core;
|
||||||
|
use CondorcetPHP\Condorcet\Election;
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
ini_set('memory_limit', '51200M');
|
||||||
|
|
||||||
|
class PairwiseNumberOfCandidatesBench
|
||||||
|
{
|
||||||
|
public array $numberOfCandidates = [3, 5, 7, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
|
||||||
|
public array $numberOfVotes = [10, 100, 1000, 10000];
|
||||||
|
|
||||||
|
|
||||||
|
protected Election $election;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
RankedPairs_Core::$MaxCandidates = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function buildElection(int $numberOfCandidates, int $numberOfVotes): void
|
||||||
|
{
|
||||||
|
$randomizer = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar('CondorcetReproductibleRandomSeed'));
|
||||||
|
|
||||||
|
$this->election = $election = new Election;
|
||||||
|
$this->election->setNumberOfSeats((int) ($numberOfCandidates / 3));
|
||||||
|
|
||||||
|
$candidates = [];
|
||||||
|
|
||||||
|
for ($i=0; $i < $numberOfCandidates; $i++) {
|
||||||
|
$candidates[] = $election->addCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $numberOfVotes; $i++) {
|
||||||
|
$oneVote = $randomizer->shuffleArray($candidates);
|
||||||
|
$election->addVote($oneVote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideNumberOfCandidates(): \Generator
|
||||||
|
{
|
||||||
|
foreach ($this->numberOfCandidates as $n) {
|
||||||
|
yield $n => ['numberOfCandidates' => $n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideNumberOfVotes(): \Generator
|
||||||
|
{
|
||||||
|
foreach ($this->numberOfVotes as $n) {
|
||||||
|
yield $n => ['numberOfVotes' => $n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Bench\OutputTimeUnit('seconds')]
|
||||||
|
#[Bench\ParamProviders(['provideNumberOfCandidates', 'provideNumberOfVotes'])]
|
||||||
|
#[Bench\Warmup(0)]
|
||||||
|
#[Bench\Iterations(1)]
|
||||||
|
#[Bench\Revs(1)]
|
||||||
|
public function benchByCandidates(array $params): void
|
||||||
|
{
|
||||||
|
$this->buildElection($params['numberOfCandidates'], $params['numberOfVotes']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Election;
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
class PairwiseUpdateOptimizationBench
|
||||||
|
{
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(2)]
|
||||||
|
#[Bench\Revs(4)]
|
||||||
|
public function benchPairwiseOptimization(): void
|
||||||
|
{
|
||||||
|
$election = new Election;
|
||||||
|
|
||||||
|
$election->parseCandidates('A;B;C;D;E;F;G');
|
||||||
|
|
||||||
|
$election->parseVotes('
|
||||||
|
E > B > C > A > G * 2500
|
||||||
|
F > B > G > H > A * 2500
|
||||||
|
H > B > G > E > A * 2500
|
||||||
|
A = B = C > D > E = F > G * 2500
|
||||||
|
G = E = C > F > A * 2500
|
||||||
|
C > D = G > A > B * 2500
|
||||||
|
');
|
||||||
|
|
||||||
|
$election->getWinner();
|
||||||
|
|
||||||
|
$vote = $election->addVote('A>B>C');
|
||||||
|
|
||||||
|
$election->removeVote($vote);
|
||||||
|
|
||||||
|
$vote->setRanking('C>B>A');
|
||||||
|
|
||||||
|
$election->getWinner();
|
||||||
|
}
|
||||||
|
}
|
42
include/Condorcet/Benchmarks/SimpleUsageBench.php
Normal file
42
include/Condorcet/Benchmarks/SimpleUsageBench.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Benchmarks;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\{Condorcet, Election};
|
||||||
|
use PhpBench\Attributes as Bench;
|
||||||
|
|
||||||
|
class SimpleUsageBench
|
||||||
|
{
|
||||||
|
#[Bench\Warmup(1)]
|
||||||
|
#[Bench\Iterations(10)]
|
||||||
|
#[Bench\Revs(10)]
|
||||||
|
#[Bench\OutputTimeUnit('milliseconds')]
|
||||||
|
public function benchSimpleManyVotes(): void
|
||||||
|
{
|
||||||
|
$election = new Election;
|
||||||
|
$election->allowsVoteWeight(true);
|
||||||
|
|
||||||
|
$election->parseCandidates('A;B;C;D;E;F');
|
||||||
|
|
||||||
|
$election->parseVotes('
|
||||||
|
Ultimate Question of Life || A>B>C ^42 * 42
|
||||||
|
C=A>B ^2 * 250
|
||||||
|
B>C
|
||||||
|
E > B > C > A ^80 *257
|
||||||
|
F > B > G > H > A* 250
|
||||||
|
D = B = E > F ^6 * 100
|
||||||
|
B>F=A>C * 100
|
||||||
|
');
|
||||||
|
|
||||||
|
$winner = $election->getCondorcetWinner();
|
||||||
|
$loser = $election->getCondorcetLoser();
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach (Condorcet::getAuthMethods() as $method) {
|
||||||
|
$result[] = $election->getResult($method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
768
include/Condorcet/CHANGELOG.md
Normal file
768
include/Condorcet/CHANGELOG.md
Normal file
@ -0,0 +1,768 @@
|
|||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [v4.2.0] - 2022-08-23
|
||||||
|
### Added
|
||||||
|
- Support for PHP 8.2
|
||||||
|
- [Console] Redesign console, add many styles, colors, and logo.
|
||||||
|
- [Console] Improve interactive mode.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- [Methods] Fix a rare crash on HighestAverage methods.
|
||||||
|
- New namespace `CondorcetPHP\Condorcet\Utils`and move `CondorcetUtil` and `VoteUtil` classes to it.
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
- Refactor Vote entry parser to new class `CondorcetPHP\Condorcet\Utils\VoteEntryParser`: Better architecture and reduce code duplication.
|
||||||
|
|
||||||
|
### Dev
|
||||||
|
- [Benchmarks] Use a random deterministic seed for generating votes. (Benchmarks now require PHP 8.2 at least)
|
||||||
|
- [Tests] Use a random deterministic if available (PHP >= 8.2) for generating votes.
|
||||||
|
- [Coding Style] Improve rules.
|
||||||
|
|
||||||
|
## [v4.1.1] - 2022-07-07
|
||||||
|
### Changed
|
||||||
|
- Composer: Fix ext-mbstring dependency.
|
||||||
|
- HighestAverage & LargestRemainder methods: Fix a bug with empty ranking in context (or non valid rank in a vote)
|
||||||
|
|
||||||
|
## [v4.1.0] - 2022-06-26
|
||||||
|
|
||||||
|
### Description
|
||||||
|
Implements new proportional methods
|
||||||
|
|
||||||
|
### Added
|
||||||
|
#### Voting Methods
|
||||||
|
- Sainte-Laguë / Webster method from HighestAverage method class.
|
||||||
|
- Thomas Jefferson / D'Hondt method from HighestAverage method class.
|
||||||
|
- Largest Remainder with all STV Quotas (Hare/Droop/Hagenbach-Bischof/Imperiali) as method options (like STV or CPO-STV).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Default max length of a candidate name is now 100 UTF-8 characters instead of 30
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Migrates the entire code base to a strict application of PSR-12 standards (and many other rules). It's debatable because our alternative syntax was lovely, but it's now standard and no longer iconoclastic, it's the age of reason. The respect for coding standards is now controlled by Laravel Pint.
|
||||||
|
|
||||||
|
## [v4.0.0] - 2022-06-17
|
||||||
|
### Description
|
||||||
|
Implement the CPO-STV method, the second official module for a proportional method. Comes with many performance improvements for some methods and elections with a lot of candidates.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
#### Core
|
||||||
|
- Adds `Election->setStatsVerbosity()` and `Election->getStatsVerbosity()` methods. This allows controlling the level of stats returned in the Result object by some methods. And to save memory and processing time if needed.
|
||||||
|
#### Voting Methods
|
||||||
|
- New proportional method: **CPO-STV** Look at the [VOTING_METHODS.md](VOTING_METHODS.md) for more details
|
||||||
|
#### TieBreaker
|
||||||
|
- New Tie Breaker method `TieBreaker::TieBreakerWithAnotherMethods`, a chaining method to break a tie
|
||||||
|
- Condorcet Election Format: Ability to parse candidates directly from votes, if not specified with the parameters first. According to the V1 specification of the format.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
#### General
|
||||||
|
- Main source code moving to `src` folder instead of `lib` folder. Must change nothing if autoloaders are used. (but forks, if any, can need vigilance)
|
||||||
|
- A candidate's name can be equal to the string "0"
|
||||||
|
- Methods options can technically be string or array, first use for the CPO-STV tie breaker
|
||||||
|
- Use the native `JsonException` instead of custom `JsonFormatException`.
|
||||||
|
|
||||||
|
#### Voting Methods
|
||||||
|
- Ranked Pairs default limit of candidates up from 40 to 60, thanks to performance optimizations
|
||||||
|
- Kemeny-Young now accepts 10 candidates by default thanks to performance optimizations. Up to 12 candidates without spending the night. And up to infinity without burning too much memory.
|
||||||
|
- `Throwable\CandidatesMaxNumberReachedException` used in Kemeny-Young and Ranked Pairs now extends `Throwable\MethodLimitReachedException`, and you should prefer to catch the second one.
|
||||||
|
- Some methods like Kemeny-Young or CPO-STV methods, send fewer stats than before to the `Result->getStats()` returning an array. To get back full details, you need to specify `Election->setStatsVerbosity(StatsVerbosity::FULL)` or `Election->setStatsVerbosity(StatsVerbosity::HIGH)`. This change speedup some methods and can use less memory.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
#### Engine
|
||||||
|
- `Permutation` class was renamed to `Permutations`
|
||||||
|
- Use of `\SplFixedArray` in some methods, improving memory and performances in some cases and for some methods.
|
||||||
|
- Extensive rewriting of the Kemeny-Young voting method engine, twice as fast as before, consuming 42X less memory and allowing easy use 10-candidate with good performances. Do not use any disk cache file on disk anymore. However, since it uses real-time generators, reading its complete statistics (excluding rankings) may require more memory (but less than before).
|
||||||
|
- Many performance improvements, especially for some methods and elections with a lot of candidates.
|
||||||
|
- Methods can use a `Vote->getContextualRankingWithoutSort()` cache at the vote level, with a new internal API based on a WeakMap.
|
||||||
|
- New `Combinations` class.
|
||||||
|
- `Permutations` asn the new `Combinations` class can work internally with integer bigger than `PHP_MAX_INT` if installed from composer. But will always return an interger <= `PHP_MAX_INT` or throw a new exception `CondorcetPHP\Condorcet\Throwable\Internal\IntegerOverflowException`
|
||||||
|
|
||||||
|
#### Dev
|
||||||
|
- Add Configuration for PHPStan
|
||||||
|
- Add and improve benchmarks
|
||||||
|
- Fix some env bugs for console tests
|
||||||
|
- New `InternalModulesAPI` attribute (yet unused in doc)
|
||||||
|
|
||||||
|
## [v3.3.3] - 2022-05-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- ```Election::getVotesListAsString()``` will be ordered in a strict and predictable manner.
|
||||||
|
- Some methods (based on Borda, Majority, STV) they now work with a lower level of decimal precision. This avoids the accumulation of rounding differences, leading in some cases to tiny differences in statistics and extremely rarely, in differences in results (in case of extremely close elections with ties on ballot allowed) depending on the order in which the votes were entered in the election. This can result in unpredictable behavior that is uncomfortable for testing or accurate reproducibility. However, the behavior in these extreme cases can not be guaranteed 100%, even if it becomes even more rare and impractical. Pairwise methods (typically Condorcet methods) are not affected by this change.
|
||||||
|
|
||||||
|
## [v3.3.2] - 2022-05-01
|
||||||
|
### Added
|
||||||
|
- Condorcet Election Format: Compatibility with specification of ```/EMPTY_RANKING/``` keyword. (import and export)
|
||||||
|
### Changed
|
||||||
|
- Vote ranking from string input, cannot have empty rank (will be skipped silently instead of "" as candidate name)
|
||||||
|
|
||||||
|
## [v3.3.1] - 2022-04-30
|
||||||
|
### Changed
|
||||||
|
- Fix a regression on Kemmeny-Young stats since v3.3.0 (should not affect the final ranking, but still dangerous and incorrect).
|
||||||
|
|
||||||
|
## [v3.3.0] - 2022-04-29
|
||||||
|
### Description
|
||||||
|
This release adds Converters classes able to parse and convert to a Condorcet Election object, the textual votes file (synthetic, with all votes) from David Hill format, Debian format, and a new (and better) Condorcet format. An Election can also be exported to this new Condorcet format.
|
||||||
|
|
||||||
|
Internally, circular references have been eliminated in favor of PHP8 weak references. It improve memory consumption before garbage collector call, prevents memory leaks from the PHP engine or Condorcet itself and removes some ugly code that was previously necessary to prevent them.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
#### Converters classes
|
||||||
|
- New Condorcet Format (specifications, converter to an Election, converter to a file)
|
||||||
|
- David Hill format (converter to an Election)
|
||||||
|
- Debian Format (converter to an Election)
|
||||||
|
|
||||||
|
#### Console
|
||||||
|
- Options to import from Condorcet, David Hill, Debian formats.
|
||||||
|
- Bugfix: (display only) Wrong value for implicit voting
|
||||||
|
|
||||||
|
#### Others
|
||||||
|
- ```Election::getVotesListAsString($withContext = true)``` get this new optional parameter, to ignore election context (restituate vote as they are submited, without any interpretation).
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
#### Structure
|
||||||
|
- Migration from circular references to PHP8 weak references. Improving memory consumption before garbage collector, and preventing memory leaks in the engine without any call (and sometimes successive call) to ```gc_collect_cycles()```. _Only complex users, creating simulations with many election objects and vote/candidates sharing between elections, in the same run, will experience factually the improvement. Or those who use some external data handler as Sqlite and needed to close connexion before the end of the script._
|
||||||
|
|
||||||
|
#### Internal API for methods modules or extended classes
|
||||||
|
- ```getLinks()``` internal API will now return a ```\Weakmap```
|
||||||
|
- About methods module extending the abstract class ```Algo\Method```, the ```$_selfElection``` property is now a ```\WeakReference```. And must to exclude it from serialization.
|
||||||
|
- ```Algo\MethodInterface``` now required the ```setElection(Election $election)``` method because she is a part of unserialize from Condorcet unserialize process.
|
||||||
|
|
||||||
|
=======
|
||||||
|
## [v3.2.3] - 2022-04-25
|
||||||
|
### Changed
|
||||||
|
- Update the dev. dependencies and in particular phploc (broken)
|
||||||
|
- Use Symfony Console attribute 'AsCommand' (before deprecation)
|
||||||
|
- Bugfix: Infinite loop in Instant-Runoff method (very rare)
|
||||||
|
## [v3.2.2] - 2021-12-14
|
||||||
|
### Changed
|
||||||
|
- Fix crash on ```Vote::addTags([])``` and add tests.
|
||||||
|
## [v3.2.1] - 2021-12-07
|
||||||
|
### Changed
|
||||||
|
- Console: Improve column width, prevent most of table cuts depending on the width of the terminal.
|
||||||
|
## [v3.2.0] - 2021-12-01
|
||||||
|
### Description
|
||||||
|
An important technical upgrade without many notable users changes.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Use PHP 8.1 new features (and minimal requirements). Resulting in more modern code & performances improvements.
|
||||||
|
- Result class now offers some publics (PHP 8.1) readonly properties in addition to getter methods.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- New Exceptions class and Exceptions hierarchies. Users must review all usage with exceptions captures. All new Exceptions extend the old CondorcetException class. But exceptions codes are no more used. (thanks @toddy15 for help and initiative)
|
||||||
|
- Improved documentation.
|
||||||
|
- Method::setOption() now only accept BackEnum or int parameter.
|
||||||
|
- StvQuotas parameters is now an Enum instead of a string.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Improved and refactored documentation generator tool.
|
||||||
|
- Add some dev & quality tools like Infection resulting in code quality improvements and news tests (thanks @toddy15 for help and initiative).
|
||||||
|
- Reduce Docker image size
|
||||||
|
|
||||||
|
## [v3.1.2] - 2021-11-23
|
||||||
|
### Changed
|
||||||
|
Bug fix: Command-line fatal error on NULL natural Condorcet winner / loser #72
|
||||||
|
|
||||||
|
## [v3.1.1] - 2021-08-03
|
||||||
|
### Added
|
||||||
|
- __CondorcetAutoloader check for the minimal PHP version #56
|
||||||
|
### Changed
|
||||||
|
- Bugfix: KemenyYoung wrong results when using Election::removeCandidates()
|
||||||
|
- Various documentation fixes and improvements
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Docker: Upgrade Debian base image to Bullseye
|
||||||
|
|
||||||
|
## [v3.1.0] - 2021-08-03
|
||||||
|
### Description
|
||||||
|
Introduces support for proportional methods. And adds some.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Minimal support for proportional methods
|
||||||
|
- New Single Transferable Vote (STV) method, a proportional one.
|
||||||
|
- New Options system for methods with parameters. Easier to use that extend and register class. Include new API methods.
|
||||||
|
- New methods Multiple Round system replace Two-round system and takes advantage of the method options. This change is backward compatible.
|
||||||
|
- Add IRV as an alias for Instant Runoff #48
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- getResult() Fix arbitrary candidate ordering on a rank. Now have consistency with getRanking and others.
|
||||||
|
- Some console improvements in style.
|
||||||
|
- Console: Shorten show-method-stats to method-stats #49
|
||||||
|
- Compatibility with PHP 8.1
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Small optimizations for InstantRunoff
|
||||||
|
- Static class for tie-breaking. Used by InstantRunoff but can be useful for further uses.
|
||||||
|
|
||||||
|
### Dev changes
|
||||||
|
- CondorcetDocumentator now using PHP8 attribtues.
|
||||||
|
|
||||||
|
## [v3.0.2] - 2021-04-28
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Fix typos in command line options
|
||||||
|
- Add command line option: --show-method-stats
|
||||||
|
|
||||||
|
## [v3.0.1] - 2020-12-08
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Bugfix Issue #32
|
||||||
|
|
||||||
|
## [v3.0.0] - 2020-12-01
|
||||||
|
### Description
|
||||||
|
Use latest PHP 8.0 functionality and improvements.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Documentation tools code is now included in this main repository instead of composer dependency. (and it's completely refactored)
|
||||||
|
- Most of the documentation use PHP8 Attributes instead of a big Yaml base file.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Refactoring Kemeny–Young code and cache system.
|
||||||
|
- PHP8 syntax and functionality.
|
||||||
|
|
||||||
|
## [v2.2.1] - 2020-10-17
|
||||||
|
### Changed
|
||||||
|
- Timer functionality is now deactivated by default for performance reason. Can be reactivated manually: ```php Condorcet:$UseTimer = true;```
|
||||||
|
- Code cleanup and update for PHP 8.0
|
||||||
|
|
||||||
|
## [v2.2.0] - 2020-05-18
|
||||||
|
### Description
|
||||||
|
Include the new vote method "Two-round voting System", and some minors fix and optimizations.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Two-round voting system. Useful to compare Condorcet with traditional lections.
|
||||||
|
- New Majority_Core class is the parent class for First-Past-The-Post and two-round system. It can easily be extended with variant parameters or code for creating easily many new majority voting methods (number of rounds, number of candidates retained after each round...).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Complete rewrite of First-Past-The-Post code. No user changes.
|
||||||
|
- Provides the right acronyms for First-Past-The-Post voting method.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Developments dependency upgrades.
|
||||||
|
|
||||||
|
## [v2.1.0] - 2019-12-29
|
||||||
|
### Description
|
||||||
|
Move to PHP 7.4 version. And add a console application for command line usage!
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- New Condorcet Application from the command line. Easy to use for non-technical users. And faster to use for everyone for most use cases.
|
||||||
|
- Docker file for building Condorcet image. For very easy access to the command line application.
|
||||||
|
- Official compiled PHAR files are now available for each version on the release page.
|
||||||
|
- Json input can include vote weight.
|
||||||
|
- New method ```Election::parseVotesWithoutFail()``` allowing to ignore the bad vote, and useful for low and constant memory usage.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- PHP 7.4 is the new minimal PHP version required.
|
||||||
|
- MBSTRING PHP extension is not requiered anymore.
|
||||||
|
- ```Election::allowVoteWeight()``` renamed to Election::allowsVoteWeight()
|
||||||
|
- ```Vote::getSimpleRanking()``` allow a new optional parameter $displayWeight.
|
||||||
|
- ```Vote::getWeight()``` allow a new optional parameter $context and if providing returning ranking in context of an election instead theorical ranking.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Use PHP 7.4 new types on property. For security and performance reasons.
|
||||||
|
|
||||||
|
## [v2.0.1] - 2019-12-29
|
||||||
|
### Description
|
||||||
|
The 2.0 branch is now legacy.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Harmonize parseVotes & parseJson
|
||||||
|
- Use Github Actions instead of Travis CI.
|
||||||
|
|
||||||
|
## [v2.0.0] - 2019-09-07
|
||||||
|
### Description
|
||||||
|
Small but many API changes (renaming, rationalization), sometimes on main methods. Very important internal optimizations. Also, use a new namespace!
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Very significant efforts about the documentation. Still in progress.
|
||||||
|
- Add two distincts methods Election::getCondorcetWinner() & Election::getCondorcetLoser(). the result are strictly equivalent to ```Election::getWinner(null)``` & ```Election::getLoser(null)``` but it's more explicit. And it is consistent with the homonymous methods of the result object.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Use new vendor namespace ```\CondorcetPHP``` instead ```\Condorcet``` because we don't have the Github Condorcet ID for this last one. The new base namespace is ```\CondorcetPHP\Condorcet\```
|
||||||
|
- Adding votes or candidates from Json or string parsing, will not check if all of them are valid. And only if all are valid, then they are registered. Previously, an exception was sent to the first error, but the status remained partially recorded.
|
||||||
|
- Many methods have been renamed or divided for greater consistency and intelligibility. Some parameters may have changed or used a more strict type.
|
||||||
|
- CondorcertException class moves to a new namespace ```Throwable\CondorcetException```. Condorcet can now also throw Trowable\CondorcetInternalError error.
|
||||||
|
- Some change on "Schulze Ratio" method computation, can affect the result of some type of election. It's still imperfect due to a case that the theory doesn't take into account. However, very small or very typical elections will have more logical results. The more common Winning & Margin methods are not affected.
|
||||||
|
- Many other various fixes.
|
||||||
|
- New Condorcet logo.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removes the slightly twisted method Election::ignoreMaxVote
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- Adding, changing or removing vote after requesting the firsts Result, will prevent recomputing all the pairwise and prefer to update it. Can be a small optimization for most use case, or a very huge performances improvements if you manage a very large number of votes or use an external data handler for storing them.
|
||||||
|
- Parse Vote (text or Json) is faster, save huge memory consumption on big input if you use the if use the multiplication symbol for equal votes. And memory is now predictable, linear, and as smart as other input vote methods.
|
||||||
|
- Overall, significant savings in memory usage.
|
||||||
|
- Many other performance optimizations.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Voting Method extending PairwiseStatsBased_Core must use static constant COUNT_TYPE instead of $\_countType property.
|
||||||
|
- Add many tests.
|
||||||
|
- Add benchmarks with phpbench.
|
||||||
|
|
||||||
|
## [v1.8.2] - 2019-02-16
|
||||||
|
### Description
|
||||||
|
Allow development environment for PHP 7.4.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Use PHP UNIT 8.x (compatible up to PHP 7.4) for PHP version >= 7.2.
|
||||||
|
- Compatibility with PHP Unit 8.x serie
|
||||||
|
|
||||||
|
## [v1.8.1] - 2019-01-05
|
||||||
|
### Description
|
||||||
|
Tests for PHP 7.3 and prevent PHP >=7.4 deprecations.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Tests for PHP 7.3
|
||||||
|
- Prevent PHP 7.4 deprecations.
|
||||||
|
|
||||||
|
## [v1.8.0] - 2018-07-22
|
||||||
|
### Description
|
||||||
|
You can add a custom constraint to force votes to meet certain criteria.
|
||||||
|
Constraints are designed as free modules (external class to load into each election). A first module is officially proposed (disabled by default): Preventing votes from including ties.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Vote constraints functionality
|
||||||
|
- First official vote constraint module: Disallow vote tie on any rank in the election context.
|
||||||
|
- Tested with PHP 7.3.
|
||||||
|
- Always better code!
|
||||||
|
|
||||||
|
## [v1.7.0] - 2018-05-26
|
||||||
|
### Description
|
||||||
|
Adds for the first time methods unrelated to Condorcet's criteria (Borda, Alternative Voting, FTPT).
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- New voting method: Borda Count
|
||||||
|
- New voting method: Dowdall System (Nauru), a Borda Count variant.
|
||||||
|
- New voting method: Instant-runoff (also know as Alternative Voting or Preferential Voting)
|
||||||
|
- New voting method: First-past-the-post
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Result object (iterator and his other methods) is now ordered by key from the first rank to the last rank. However, no method officially implemented before version 1.7 was affected by this theoretical problem. This never affected the correct rank allocation but could cause misinterpretation if carelessly repeated in a loop.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Code cleanup & test improvements
|
||||||
|
|
||||||
|
## [v1.6.0] - 2018-01-28
|
||||||
|
### Description
|
||||||
|
Publication centred on two axes:
|
||||||
|
Firstly, the improvement and finishing of the internal structure, often for the purpose of readability of the code and good practices. And an extension of the tests.
|
||||||
|
The second part concerns the continued improvement of the management of the very large elections.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add ```\CondorcetPHP\Election::getVotesListGenerator``` and ```\CondorcetPHP\DataManager\VotesManager::getVotesListGenerator``` methods. Same as getVotesList method, but output a PHP generator instead of full array. Useful only for working on vera large election with an external DataHandler.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- ```\CondorcetPHP\Condorcet::format()``` method move to \CondorcetPHP\CondorcetUtil::format()
|
||||||
|
- ```\CondorcetPHP\CondorcetUtil::format()``` can no longer optionally produce a var_dump(). You must do it yourself.
|
||||||
|
- Remove ```\CondorcetPHP\Election::getVoteByKey(```) method
|
||||||
|
- Fix ```\CondorcetPHP\Election``` cloning issues
|
||||||
|
- Simply DataHandlerDriverInterface
|
||||||
|
- Optimize ```\CondorcetPHP\Election::countVotes``` and ```\CondorcetPHP\DataManager\VotesManager::countVotes``` methods performance and memory usage in case of using an external DataHandler.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- Cut out some classes and functions into smaller sub-groups.
|
||||||
|
- New dev tools in a new dedicated folder (update documentation, generate Kemeny–Young cache)
|
||||||
|
- Documentation generator code move to a new repository
|
||||||
|
- Git force Unix style line-ending (This could cause unexpected behavior in some tests related to the export of votes in string output.)
|
||||||
|
- Various optimizations & bugfix
|
||||||
|
- Test coverage up to 95%
|
||||||
|
- Wonderful new files headers
|
||||||
|
|
||||||
|
## [v1.5.0] - 2018-01-08
|
||||||
|
### Description
|
||||||
|
This release focuses on the management of very large elections.
|
||||||
|
It more rigorously reviews the functioning of the DataHandler, which is an advanced way to manage a very large number of votes, which is more stable, mature and tested.
|
||||||
|
It adds, as an alternative and as a complement (both can be used in consort) the notion of the weight of a vote. This may be useful for elections in which voters are not equal. Or to emulate a big election (without too many possible combinations!) if you don't need to store the details of each vote at Condorcet level.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- It is now possible to add weight (integer >= 1) to each vote. If you enable this mode at the election level (deactivated by default) then the votes will be proportional to their weight when calculating all the algorithms. for example, if the weight is 2, then the vote will count double.
|
||||||
|
This is an alternative and complementary to adding multiple votes. Using this mode of operation can save you (for large elections) a high cost in RAM or the configuration/development of a DataHandler, which can be complex. However, if you need to keep the information of each elector at Condorcet level, this functionality will not satisfy you, it is useful if at this level the voting information is useless or if it makes no sense.
|
||||||
|
- Using a DataHandler to externalize vote data is now compatible with vote tags.
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- More mature and tested management of external DataHandler. Your custom drivers need to be updated.
|
||||||
|
- News tests
|
||||||
|
- Minors clean-up, changes & optimizations
|
||||||
|
|
||||||
|
## [v1.4.1] - 2017-12-21
|
||||||
|
### Changed
|
||||||
|
- Add some aliases for Ranked Pairs
|
||||||
|
|
||||||
|
## [v1.4.0] - 2017-12-11
|
||||||
|
### Description
|
||||||
|
Rewrite and extend old and experimental implementation with a new one. After a lot of reading and some exchanges with Nicolaus Tideman.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Ranked Pairs method is no more experimental thanks to a completely new implementation. It has also been divided into two methods: "Ranked Pairs Margin" which is favored by Nicolaus Tideman and Ranked Pairs Winning which is the variant most often mentioned in other documentation, including the English Wikipedia.
|
||||||
|
Regarding compatibility with the old version, "Ranked Pairs" or "RankedPairs" calls now use Ranked Pairs Margin. Note that the old implementation, although failing in other respects, used a Winning version. which in some very specific cases can change your results.
|
||||||
|
*[More information on Condorcet Wiki](https://github.com/julien-boudry/Condorcet/wiki/I-%23-Installation---Basic-Configuration-%23-2.-Condorcet-Methods)*
|
||||||
|
|
||||||
|
- New method: [Election::getVotesListAsString](https://github.com/julien-boudry/Condorcet/blob/master/Documentation/Election%20Class/public%20Election--getVotesListAsString.md)
|
||||||
|
- New method: [Result::Election::getResultAsString](https://github.com/julien-boudry/Condorcet/blob/master/Documentation/Result%20Class/public%20Result--getResultAsString.md)
|
||||||
|
|
||||||
|
### Internal changes
|
||||||
|
- News tests
|
||||||
|
- Minors clean-up, changes & optimisations
|
||||||
|
|
||||||
|
## [v1.3.4] - 2017-11-29
|
||||||
|
### Fixed
|
||||||
|
- Potentially backward-incompatible change if you use the rare and useless Dodgson method**
|
||||||
|
Fix #19 (thanks to @janmotl) : Our implementation of Dodgson was wrong. Or rather: used Tideman's approximation without knowing it. This could potentially lead to false results in some cases on this method.
|
||||||
|
Dodgson's original will not be implemented because of the work it would represent and strong performance limitations (number of candidates, number of votes).
|
||||||
|
|
||||||
|
Instead, we kept "Tideman approximation" but renamed it. And we added another approximation: "Dodgson Quick". We recommend this second solution, being the best of both, even if the two may be right in different cases or wrong together.
|
||||||
|
More explanations here: https://www.maa.org/sites/default/files/pdf/cmj_ftp/CMJ/September%202010/3%20Articles/6%2009-229%20Ratliff/Dodgson_CMJ_Final.pdf
|
||||||
|
|
||||||
|
No longer any method use the call "Dodgson", please look at the [documentation](https://github.com/julien-boudry/Condorcet/wiki/I-%23-Installation---Basic-Configuration-%23-2.-Condorcet-Methods) to know which calls to use for either one.
|
||||||
|
|
||||||
|
## [v1.3.3] - 2017-10-04
|
||||||
|
### Fixed
|
||||||
|
- Critical bugfix: Result cache was frozen after serializing/unserializing an Election object. You can register or remove votes, but each result eventually computed before serializing stays frozen and potentially false.
|
||||||
|
If you do not store the Election object by serializing it, you are not affected.
|
||||||
|
|
||||||
|
## [v1.3.2] - 2017-09-24
|
||||||
|
### Fixed
|
||||||
|
- Minor bugfix release. Fix PHP errors on very small elections (Ranked Pairs / Minimax).
|
||||||
|
|
||||||
|
## [v1.3.1] - 2017-09-18
|
||||||
|
### Fixed
|
||||||
|
- Bugfix : ```Vote::getSimpleVote()```
|
||||||
|
- ```Vote::getContextualVote()``` is renamed ```Vote::getContextualRanking()```
|
||||||
|
|
||||||
|
## [v1.3.0] - 2017-09-17
|
||||||
|
### Description
|
||||||
|
Optional management of a new mode: if a vote does not specify the last rank. Then there is no last rank. This can significantly change the outcome of an election.
|
||||||
|
Previously (and still by default), if the last rank was not specified, it was automatically deducted.
|
||||||
|
This functionality is managed at the level of an election, it is possible to switch from one to the other without affecting the votes. The latter may even participate simultaneously in several elections using different modes.
|
||||||
|
|
||||||
|
Also add Dodgson method.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Adds [Dodgson method](https://en.wikipedia.org/wiki/Dodgson%27s_method)
|
||||||
|
- Previously, if within a ranking, you do not specify all candidates participating in an election. It was considered that you placed the missing ones implicitly on the last rank.
|
||||||
|
This is always the default behavior. Alternative behavior is now added so that the missing candidates are ignored when calculating the results, which can significantly change the results. Please refer to the documentation.
|
||||||
|
- Add Kemeny-Young 'bestScore' information on Result::getStats()
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- If you vote using Candidate object. They will no longer be converted into another Candidate object with the same name if this one exists into the target election. They will be two different candidates... with the same name. It's more strict and prevents error in this strange case.
|
||||||
|
However, it can strongly be advised to not to mix different candidates with the same name, so that you do not mislead yourself! However, Condorcet now manages this case correctly.
|
||||||
|
If you vote by string or Json input : Nothing changes. Either a new candidate will be created or they will be converted with the candidate object with the same name in the first election of the voting object in which they will participate.
|
||||||
|
- Improved Condorcet::format()
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fix Result::getWinner && Result::getLoser()
|
||||||
|
* Vote:getContextualVote() return stricter rank array key, from 1 to n.
|
||||||
|
|
||||||
|
### Internals changes
|
||||||
|
- Adds [PHPUnit](https://phpunit.de/) with many tests in particular to monitor the results.
|
||||||
|
- Refactoring Copeland and Minimax code. With the new Dodgson method, they now all using the same lightweight code based on the improved PairwiseStats class.
|
||||||
|
- Many code refactoring.
|
||||||
|
|
||||||
|
## [v1.2.3] - 2017-09-03
|
||||||
|
### Changed
|
||||||
|
- The method ```Candidate::getName``` no longer takes an argument.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- More strict array key on ```Vote::getContextualVote``` method
|
||||||
|
- Various bugfix
|
||||||
|
- First PHP Unit tests
|
||||||
|
|
||||||
|
## [v1.2.2] - 2017-08-31
|
||||||
|
### Fixed
|
||||||
|
- Bugfix & Support for PHP 7.2
|
||||||
|
- Bugfix for KemenyYoung conflict detection API
|
||||||
|
|
||||||
|
## [v1.2.1] - 2017-07-28
|
||||||
|
### Fixed
|
||||||
|
- Bugfix Version ( thanks @hboomsma : https://github.com/julien-boudry/Condorcet/issues/15 )
|
||||||
|
|
||||||
|
## [v1.2.0] - 2016-12-11
|
||||||
|
### Changed
|
||||||
|
- Use the news PHP 7.1 syntax. PHP 7.1 is now require for 1.2.x branch and above.
|
||||||
|
|
||||||
|
## [v1.1.0] - 2016-09-11
|
||||||
|
### Added
|
||||||
|
- New Result class. The results are no longer provided as array but as a result object. Coming with many methods (get it as an array, check metadata, get others results from infos at the generation time...). It implements Iterator / Countable / ArrayAccess for excellent backward compatibility.
|
||||||
|
- Kemeny-Young paradox is now run more cleanly thanks to the new result object.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- Using PHP new syntax and optimization. PHP 7.0 >= is now required for 1.1 branch.
|
||||||
|
- Improve multi-elections contexts. Now works in a manner consistent with what you want to do (and what yet allowed to imply the documentation).
|
||||||
|
- Efforts on documentation (wiki), and wide rewriting examples.
|
||||||
|
- Many internals refactoring and bugfix.
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.0.0] - 2016-06-05
|
||||||
|
### Added
|
||||||
|
- **Experimental support for very large election**, it comes with critical internal changes. A functional driver for PDO is provided to be used with relational SQL databases, you will probably need to extend it or configure it (database structure...). <br>
|
||||||
|
The modular structure allows you to develop your own implementation to get outsourced datastore, for example, we can imagine a NoSQL database driver. <br>
|
||||||
|
Benchmark shows that on PHP 7 + SQLite, 200 000 votes can be registered and computed in less than 60 seconds on a little server, with ~60mb RAM use. However, the speed of the driver does not change much the performance. From a certain point: slowdowns are intrinsically linked to the internal processing side Condorcet engine. Major optimizations for speed can easily be done for further releases, but this would require a trade-off between speed and code complexity. <br>
|
||||||
|
_If you are interested by this feature, please have a look to the documentation. Consider that the functionality come in BETA stage._
|
||||||
|
- New method Vote::getSimpleRanking -> Provide vote ranking as a string in one line. (Ex: 'A>B=D>C')
|
||||||
|
- New CondorcetPHP\Algo\Tools\VirtualVote:: removeCandidates(Condorcet/Vote $vote, array $candidateToRemove) static method clone your vote and return this clone without specified candidates.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Requirement: PHP 5.6 is the new minimal PHP version. Full official support for PHP7 is now provided (and include some bug fixes).
|
||||||
|
- Internal Change: Many Cleans & Improvements
|
||||||
|
|
||||||
|
## [v0.97.0] - 2015-09-05
|
||||||
|
### Changed
|
||||||
|
- Internal change, for future management ability of billions of votes.
|
||||||
|
- Timer manager knows give an historic with CondorcetPHP\Timer\Manager->getHistory();
|
||||||
|
|
||||||
|
## [v0.96.0] - 2015-08-22
|
||||||
|
### Changed
|
||||||
|
- Condorcet autoloader move on Condorcet/__CondorcetAutoload.php folder, outside lib folder. If you don't have your owns PSR-4 autoloader, you must now explicitly include this file,
|
||||||
|
- Because of dramatically random performance beyond 7 Candidates, our flawed implementation of RankedPair method is now by default limited to 7 Candiates.
|
||||||
|
More than ever, the implementation of RankedPair should be considered experimental; it's really the only method giving me serious problems.
|
||||||
|
- Some minor internal changes.
|
||||||
|
|
||||||
|
## [v0.95.1] - 2015-08-15
|
||||||
|
### Fixed
|
||||||
|
- Bugfix version
|
||||||
|
|
||||||
|
## [v0.95.0] - 2015-08-15
|
||||||
|
### Changed
|
||||||
|
The new class Election replaces Condorcet class and retains most of its methods, static or not.
|
||||||
|
The class Condorcet survives. And now takes care of core configuration, such as recording modules.
|
||||||
|
|
||||||
|
So you must now create an object Election instead of Condorcet. What is more explicit. The remaining methods related to class Condorcet are in the documentation and examples.
|
||||||
|
As the class keeps the Condorcet high static method (although specialized), code modification on your part will be very minor and generally involve changing the "new Condorcet" instruction to "new Election".
|
||||||
|
|
||||||
|
- Condorcet::getClassVersion is renamed Condorcet::getVersion
|
||||||
|
|
||||||
|
## [v0.94.0] - 2015-08-14
|
||||||
|
### Added
|
||||||
|
- Method name now have alias.
|
||||||
|
So _Condorcet::getResult('Schulze')_ is now strictly equivalent to _Condorcet::getResult('Schulze Winning')_ or _Condorcet::getResult('Schulze_Winning')_ or the class namespace CondorcetPHP::getResult('CondorcetPHP\Algo\Methods\SchulzeWinning').
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Condorcet:addAlgos is renamed to Condorcet::addMethod, it's more logic. Argument is now a fully-qualified class name. This class can now be outside of \Condocet namespace. Adding your own algorithm is now much cleaner.
|
||||||
|
- Condorcet::getPairwise(false) now return the new pairwise object instead of an abstract array. Condorcet::getPairwise(true) is unchanged and equivalent to Pairwise::getExplicitPairwise.
|
||||||
|
The new pairwise object implement \Iterastor and \ArrayAccess interfaces, so change may be transparent for you.
|
||||||
|
- PSR-0 autoloader support is removed. Instead, Condorcet is compliant with any PSR-4 autoloader, and it is now the only way to use it with Composer.
|
||||||
|
If you don't have PSR-4 autoloader or you don't want to use Composer, you can continue to just include lib\Condorcet.php, its use now his own fallback PSR-4 implementation instead of his old PSR-0 implementation.
|
||||||
|
Be careful, path to Condorcet.php change cause of PSR-4. It's now lib/Condorcet.php and not the old lib/Condorcet/Condorcet.php old path.
|
||||||
|
|
||||||
|
# Internal changes
|
||||||
|
- Reorganization about namespacing.
|
||||||
|
- Methods are now loaded by the normal and common autoloader.
|
||||||
|
- Pairwise is now an independent object, distinct from Condorcet object.
|
||||||
|
- Timer functionality now works outside of Condorcet class. With Timer\Manager and Timer\Chrono class. More improvement coming later (full log for benchmarking). You can get the timer manager by Condorcet::getTimerManager, but then know what you do!
|
||||||
|
- And other little things and optimization (deleting code deduplication, new constants instead of hardcoding...).
|
||||||
|
|
||||||
|
## [v0.93.0] - 2015-08-02
|
||||||
|
### Changed
|
||||||
|
- Minor internals optimizations.
|
||||||
|
- Some coding conventions change (can affect many lines).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- If you try to get Kemeny-Young 9 candidates on a Stable branch, Kemeny-Young will not try to store generic cache data on disk. This usage (although not recommended in all cases) is slower than before. but does not attempt to do something that should not be possible.
|
||||||
|
|
||||||
|
## [v0.92.0] - 2015-07-26
|
||||||
|
### Changed
|
||||||
|
- Deleting concept of Condorcet object default algorithm, and Class force algorithm. Now, there is only a Class Default method.
|
||||||
|
_Now the default method is managed as static. It is no longer possible to force a method. Any management of the default object-level method is deleted
|
||||||
|
This results in a simple boost, and therefore easier to understand documentation without gadgets methods.
|
||||||
|
A slight speed increase can also be observed, the code being rid of a complex management resulting in many internal calls._
|
||||||
|
- Support PSR-4 autoloading with composer.
|
||||||
|
- New implementation of PSR-0 autloader. _(Automatically used if you do not go through one provided by Composer or framework or other valid autoloaders. It acts only fallback of last resort)_.
|
||||||
|
- Some internal code cleanup (organizational change with sub-namespace, moving or rename some methods or class, better Schulze Family strategy).
|
||||||
|
|
||||||
|
## [v0.91.0] - 2015-03-28
|
||||||
|
### Changed
|
||||||
|
- Condorcet now use more usual PSR-0 class loading philosophy. And each Class and Interface has now her owns PHP file according to PSR-0 specifications.
|
||||||
|
- As result, the new architecture from Condorcet 0.90 is now fully compatible with framework (composer autoloader), is case of you would to play with Candidate Class (for example) before creating first an election by Condorcet Class. It's was a serious issue from Condorcet 0.90.
|
||||||
|
- You can too continue to include /lib/Condorcet/Condorcet.php file as loader, if there is no others compatible autoloader, Condorcet will now use a new and special PSR-0 like autoloader for himself.
|
||||||
|
- Documentation files now use filename compatible with Windows filesystem (thanks Bill ^^)
|
||||||
|
- Minor and unnecessary coding style change.
|
||||||
|
|
||||||
|
## [v0.90.0] - 2015-02-14
|
||||||
|
### Description
|
||||||
|
New internal architecture. very important code refactoring, often completely rewritten. Relatively new API.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Algorithms are now more isolated than Condorcet activities, they use them by their own API.
|
||||||
|
|
||||||
|
#### Vote & Candidate are now objects!
|
||||||
|
- Candidate and Vote are now objects. You can continue to provide string, but all will be converted into object and the return values of most methods will favor this new philosophy.
|
||||||
|
- Vote and candidate are independent objects. They can participate in various elections simultaneously. They have their own lives and historical (name change, change of vote, elections to which they are taking or no longer taking part ...).
|
||||||
|
They can be cloned, serialized, analyzed...
|
||||||
|
- Like Candidate object, a Vote object can take part into multiple elections. He can change its ranking and it will automatically affect all its elections. You can also provide top ranking, and its election can have other candidates. Condorcet will intelligently reconstruct a context for each election even if they do not have the same list of candidates!
|
||||||
|
- Off course, you can extend them !
|
||||||
|
|
||||||
|
#### Kemeny-Young improvements
|
||||||
|
- Code review.
|
||||||
|
- New Permutation class. 9 maximum candidates instead of 6! So, for performance reasons, I suggest to stay at 8.
|
||||||
|
Thanks to Jorge Gomes (@cyberkurumin) for his helpful commit!
|
||||||
|
|
||||||
|
#### Documentation
|
||||||
|
|
||||||
|
Documentation more consistent with the new size of the library has been established. It is not perfect yet, but the documentation work continues day after day to make up for the delay.
|
||||||
|
|
||||||
|
However, foundations and most contents are available now.
|
||||||
|
- New examples of codes meeting the latest revolutions.
|
||||||
|
- A new manual, in the form of a Wiki Github.
|
||||||
|
- Complete specifications for each of the public methods. Into the _doc_ directory.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **Condorcet::format** static method is a substitute to var_dump to print easily better human readable Condorcet data (Vote, Résult). It can also be used to return (and not print) more simple dataset.
|
||||||
|
- Many new methods or API change. But structure stay similar, and old simple scripts can continue to work without modifications or really minor changes.
|
||||||
|
|
||||||
|
## [v0.14.0] - 2014-08-10
|
||||||
|
### Description
|
||||||
|
The code will be very severely rewritten and restructured for the next major release.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added UNIX timestamp of the record of each vote time as a special tag.
|
||||||
|
- Ability to perform cryptographic checksum (SHA-2 256) the status of an election (candidates, votes, cache, library version).
|
||||||
|
- New static method setMaxVoteNumber, allow you to limit the number of votes in a election. And public method to ignore it (or not) for each object.
|
||||||
|
- Improvements and bugfixes around object serialization.
|
||||||
|
- New Options for getClassVersion method
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Compatibility is now guaranteed from PHP 5.5.12 to PHP 5.6.x. But the vital methods seem functional with PHP (>=) 5.4.3
|
||||||
|
- Algorithm Kemeny-Young V2: more than 1000 times faster with a cache of pre-computed data. 6 candidates on an election is now very fast, and it is the new provisional limit.
|
||||||
|
Next Condorcet version will allow more candidates for Kemeny-Young (7 or 8), with more pre-computed sets.
|
||||||
|
- Customized limitation of maximum candidate for Kemeny-Young is removed.
|
||||||
|
- Works around the presentation of the single primary tag of each vote
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Improvements and bugfixes around object serialization.
|
||||||
|
- Many bugfixes and minor internal adjustments. Mostly to satisfy the development of condorcet-vote.org, which uses the library as a real framework of election management.
|
||||||
|
|
||||||
|
## [v0.13.2] - 2014-07-29
|
||||||
|
### Fixed
|
||||||
|
- Bugfix on getVotesList() and all tag filter methods
|
||||||
|
|
||||||
|
## [v0.13.0] - 2014-07-06
|
||||||
|
### Added
|
||||||
|
- New logo by @Christelle-Radena
|
||||||
|
- Add getLastTimer() and getGlobalTimer() methods
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- isJson is now a static method, useful for Condorcet API project
|
||||||
|
- Add an exception handler into the examples
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Some minors bugfix about CondorcetException class
|
||||||
|
|
||||||
|
## [v0.12.0] - 2014-07-02
|
||||||
|
### Added
|
||||||
|
- Votes and candidates can now be defined by a json input. _( jsonVotes(), jsonCandidates() )_
|
||||||
|
- Candidates can now be defined by a text input _( string or file with parseCandidates() )_
|
||||||
|
- The input text or json can now take a parameter of anti-flood safety generating an exception, providing you foresee yourself.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (Git) The static method ::getClassVersion() returns 'DEV' entitle on developments branches.
|
||||||
|
- Candidate name are now trim()
|
||||||
|
- The old system of errors reporting is deleted.
|
||||||
|
- The class now throws exceptions of class 'CondorcetException'
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Various bugfix
|
||||||
|
|
||||||
|
## [v0.11.1] - 2014-07-01
|
||||||
|
### Fixed
|
||||||
|
- Minor bugfix for getMethod() & setMethod() methods.
|
||||||
|
|
||||||
|
## [v0.11.0] - 2014-06-14
|
||||||
|
### Added
|
||||||
|
- Added the ability to include a multitude of votes votes simultaneously from a text or a single wide string file.
|
||||||
|
- Adding an adjustable anti-flood on the previous method.
|
||||||
|
|
||||||
|
- More flexibility to register or claim tags. Use an array or a string separated by commas.
|
||||||
|
- The countVote() method can now act on specific tags.
|
||||||
|
- The getVoteList() method can now be used more accurate and extensive.
|
||||||
|
- The removeVotes() method can now be used more accurate and extensive.
|
||||||
|
- The getResult() method can now be used to gain a profit on a partial selection of the votes (using tags) without requiring the prior removal of votes.
|
||||||
|
- Added more specific error message on addVote()
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Improved documentation
|
||||||
|
- Various optimizations
|
||||||
|
|
||||||
|
## [v0.10.1] - 2014-05-17
|
||||||
|
### Fixed
|
||||||
|
- Bugfix for Schulze_Ratio (division by 0)
|
||||||
|
|
||||||
|
## [v0.10.0] - 2014-05-13
|
||||||
|
### Added
|
||||||
|
- New variants for the method of Schulze
|
||||||
|
- Experimental Implementation of the Ranked Pairs method
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Audited successfully Schulze with the example of Martin Schulze itself
|
||||||
|
- Various optimizations
|
||||||
|
|
||||||
|
## [v0.9.0] - 2014-05-01
|
||||||
|
### Added
|
||||||
|
- Ability to add options to the algorithm with getResult ()
|
||||||
|
- KemenyYoung is now able to detect its conflicts and inform through the use of an option on getResult () (see the documentation)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Multiple bug fixes, some important (but never affecting the results).
|
||||||
|
- Code harmonization
|
||||||
|
- On the benefit of public methods provide a return value with the meaning and utility.
|
||||||
|
- Isolation of static methods having intended to be used by algorithms to avoid duplication of one another.
|
||||||
|
- Very complete (but not 100% exhaustive) examples of uses are kindly provided.
|
||||||
|
- Global code review by the author.
|
||||||
|
|
||||||
|
## [v0.8.0] - 2014-04-24
|
||||||
|
### Added
|
||||||
|
- New algorithm: Kemeny-Young (http://en.wikipedia.org/wiki/Kemeny-Young_method)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Many internal improvements, code cleanup and improve modularity rules
|
||||||
|
- Candidates can now have long names (30 characters)
|
||||||
|
|
||||||
|
## [v0.7.0] - 2014-04-18
|
||||||
|
### Added
|
||||||
|
- Support for serialize and unserialize object.
|
||||||
|
- Optimization of data to keep back.
|
||||||
|
- Checking the version of the data to import.
|
||||||
|
- WARNING : Resultat will be recalculated from voting data.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Complete harmonization of attribute names and methods. Compatibility with old API is completely broken on the form, but the operation remains exactly the same.
|
||||||
|
- Many code cleanup and optimizations
|
||||||
|
|
||||||
|
## [v0.6.0] - 2014-04-14
|
||||||
|
### Added
|
||||||
|
- Add new Condorcet algorithm: Minimax in its three variants (Winning, Margin, Opposition | The last one is not Condorcet criterion compliant)
|
||||||
|
http://en.wikipedia.org/wiki/Minimax_Condorcet
|
||||||
|
- Add the ability to record a new vote by using a format string like "A>B=C>D" rather than the use of an array, read the doc!
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Some bugfix & optimizations
|
||||||
|
|
||||||
|
## [v0.5.1] - 2014-04-13
|
||||||
|
### Fixed
|
||||||
|
- Bugfix about registering new algorihms by an array
|
||||||
|
|
||||||
|
## [v0.5.0] - 2014-04-13
|
||||||
|
### Added
|
||||||
|
- Support Composer
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Important structural changes to meet the standard PSR-0, PSR-1 and PSR-2 (partial).
|
||||||
|
|
||||||
|
## [v0.4.0] - 2014-04-06
|
||||||
|
### Description
|
||||||
|
First version ready for production, with many API improvements and news features. And the new Condorcet Copeland method.
|
||||||
|
|
||||||
|
## [v0.3.0] - 2014-03-16
|
||||||
|
### Description
|
||||||
|
Considerable structural changes and redesign many parts of API.
|
||||||
|
The class can now support the easy addition of new algorithms.
|
||||||
|
|
||||||
|
The next release will be devoted to validate the apparent stability of this version 0.3 and enrich the API for more flexibility. And perhaps the arrival of a new algorithm.
|
||||||
|
|
||||||
|
## [v0.2.0] - 2014-03-12
|
||||||
|
### Description
|
||||||
|
Second release! Not really ready for production, please test it!
|
||||||
|
|
||||||
|
## [v0.1.0] - 2014-03-09
|
||||||
|
### Description
|
||||||
|
First release! Not really ready for production, please test it !
|
1
include/Condorcet/CONTRIBUTING.md
Normal file
1
include/Condorcet/CONTRIBUTING.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Please help.
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD)]
|
||||||
|
class Description
|
||||||
|
{
|
||||||
|
public readonly string $text;
|
||||||
|
|
||||||
|
public function __construct(string $text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||||
|
class Example
|
||||||
|
{
|
||||||
|
public readonly string $name;
|
||||||
|
public readonly string $link;
|
||||||
|
|
||||||
|
public function __construct(string $name, string $link)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->link = $link;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||||
|
class FunctionParameter
|
||||||
|
{
|
||||||
|
public readonly string $text;
|
||||||
|
|
||||||
|
public function __construct(string $text)
|
||||||
|
{
|
||||||
|
$this->text = (mb_substr($text, -1) === '.') ? $text : $text.'.';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD)]
|
||||||
|
class FunctionReturn
|
||||||
|
{
|
||||||
|
public readonly string $text;
|
||||||
|
|
||||||
|
public function __construct(string $text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
|
||||||
|
class InternalModulesAPI
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
|
||||||
|
class PublicAPI extends InternalModulesAPI
|
||||||
|
{
|
||||||
|
public function __construct(string ...$class)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD)]
|
||||||
|
class Related
|
||||||
|
{
|
||||||
|
public readonly array $relatedList;
|
||||||
|
|
||||||
|
public function __construct(string ...$relatedList)
|
||||||
|
{
|
||||||
|
$this->relatedList = $relatedList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Condorcet PHP - Election manager and results calculator.
|
||||||
|
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||||
|
|
||||||
|
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||||
|
https://github.com/julien-boudry/Condorcet
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_METHOD)]
|
||||||
|
class Throws
|
||||||
|
{
|
||||||
|
public array $exceptionList;
|
||||||
|
|
||||||
|
public function __construct(string ...$exceptionList)
|
||||||
|
{
|
||||||
|
$this->exceptionList = $exceptionList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,580 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator;
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes\{Description, Example, FunctionParameter, FunctionReturn, PublicAPI, Related, Throws};
|
||||||
|
use HaydenPierce\ClassFinder\ClassFinder;
|
||||||
|
|
||||||
|
class Generate
|
||||||
|
{
|
||||||
|
// Static - Translators
|
||||||
|
|
||||||
|
public static function makeFilename(\ReflectionMethod $method): string
|
||||||
|
{
|
||||||
|
return self::getModifiersName($method).
|
||||||
|
' '.
|
||||||
|
str_replace('\\', '_', self::simpleClass($method->class)).'--'.$method->name.
|
||||||
|
'.md';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function simpleClass(string $fullClassName): string
|
||||||
|
{
|
||||||
|
return str_replace('CondorcetPHP\\Condorcet\\', '', $fullClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function speakBool($c): string
|
||||||
|
{
|
||||||
|
if ($c === true || $c === 'true') {
|
||||||
|
return 'true';
|
||||||
|
}
|
||||||
|
if ($c === false || $c === 'false') {
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
if ($c === null || $c === 'null') {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
if (\is_array($c)) {
|
||||||
|
return '['.implode(',', $c).']';
|
||||||
|
}
|
||||||
|
if (\is_object($c)) {
|
||||||
|
return 'new '.$c::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTypeAsString(?\ReflectionType $rf_rt, bool $codeBlock = false): ?string
|
||||||
|
{
|
||||||
|
if ($rf_rt !== null) {
|
||||||
|
if ($codeBlock) {
|
||||||
|
return '```'.((string) $rf_rt).'```';
|
||||||
|
} else {
|
||||||
|
return (string) $rf_rt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rf_rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getModifiersName(\ReflectionMethod $method): string
|
||||||
|
{
|
||||||
|
return implode(' ', \Reflection::getModifierNames($method->getModifiers()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static - Builder
|
||||||
|
|
||||||
|
public static function cleverRelated(string $name): string
|
||||||
|
{
|
||||||
|
$infos = explode('::', $name);
|
||||||
|
$infos[0] = str_replace('static ', '', $infos[0]);
|
||||||
|
|
||||||
|
$url = '../'.$infos[0].' Class/public '.str_replace('::', '--', $name) . '.md';
|
||||||
|
$url = str_replace(' ', '%20', $url);
|
||||||
|
|
||||||
|
return '['.$name.']('.$url.')';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function computeRepresentationAsForIndex(\ReflectionMethod $method): string
|
||||||
|
{
|
||||||
|
return self::getModifiersName($method).
|
||||||
|
' '.
|
||||||
|
self::simpleClass($method->class).
|
||||||
|
(($method->isStatic()) ? '::' : '->').
|
||||||
|
$method->name.
|
||||||
|
' ('.(($method->getNumberOfParameters() > 0) ? '...' : '').')';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function computeRepresentationAsPHP(\ReflectionMethod $method): string
|
||||||
|
{
|
||||||
|
$option = false;
|
||||||
|
$str = '(';
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if ($method->getNumberOfParameters() > 0) {
|
||||||
|
foreach ($method->getParameters() as $value) {
|
||||||
|
$str .= ' ';
|
||||||
|
$str .= ($value->isOptional() && !$option) ? '[' : '';
|
||||||
|
$str .= ($i > 0) ? ', ' : '';
|
||||||
|
$str .= self::getTypeAsString($value->getType());
|
||||||
|
$str .= ' ';
|
||||||
|
$str .= $value->isPassedByReference() ? '&' : '';
|
||||||
|
$str .= '$'.$value->getName();
|
||||||
|
$str .= $value->isDefaultValueAvailable() ? ' = '.self::speakBool($value->getDefaultValue()) : '';
|
||||||
|
|
||||||
|
($value->isOptional() && !$option) ? $option = true : null;
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($option) {
|
||||||
|
$str .= ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
$str .= ' )';
|
||||||
|
|
||||||
|
return "```php\n".
|
||||||
|
self::getModifiersName($method).' '.self::simpleClass($method->class).(($method->isStatic()) ? '::' : '->').$method->name.' '.$str. ((self::getTypeAsString($method->getReturnType()) !== null) ? ': '.self::getTypeAsString($method->getReturnType()) : '').
|
||||||
|
"\n```";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Script
|
||||||
|
public function __construct(string $path)
|
||||||
|
{
|
||||||
|
$start_time = microtime(true);
|
||||||
|
|
||||||
|
$pathDirectory = $path.\DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
|
//
|
||||||
|
$FullClassList = ClassFinder::getClassesInNamespace('CondorcetPHP\Condorcet\\', ClassFinder::RECURSIVE_MODE);
|
||||||
|
$FullClassList = array_filter($FullClassList, static function (string $value) {
|
||||||
|
return (mb_strpos($value, 'Condorcet\Test') === false) && (mb_strpos($value, 'Condorcet\Dev') === false);
|
||||||
|
});
|
||||||
|
|
||||||
|
$inDoc = 0;
|
||||||
|
$non_inDoc = 0;
|
||||||
|
$total_methods = 0;
|
||||||
|
$total_nonInternal_methods = 0;
|
||||||
|
|
||||||
|
// Warnings
|
||||||
|
foreach ($FullClassList as $FullClass) {
|
||||||
|
$methods = (new \ReflectionClass($FullClass))->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||||
|
|
||||||
|
foreach ($methods as $oneMethod) {
|
||||||
|
if ($oneMethod->isInternal()) {
|
||||||
|
} elseif (!empty($oneMethod->getAttributes(PublicAPI::class))) {
|
||||||
|
$inDoc++;
|
||||||
|
|
||||||
|
if ($oneMethod->getNumberOfParameters() > 0) {
|
||||||
|
foreach ($oneMethod->getParameters() as $oneParameter) {
|
||||||
|
if (empty($oneParameter->getAttributes(FunctionParameter::class))) {
|
||||||
|
var_dump('Method Has Public API attribute but parameter $'.$oneParameter->getName().' is undocumented '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($oneMethod->getAttributes(Description::class)) && $oneMethod->getDeclaringClass()->getNamespaceName() !== '') {
|
||||||
|
var_dump('Description Attribute is empty: '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$non_inDoc++;
|
||||||
|
|
||||||
|
if (empty($oneMethod->getAttributes(PublicAPI::class)) && $oneMethod->getDeclaringClass()->getNamespaceName() !== '') {
|
||||||
|
// var_dump('Method not has API attribute: '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$full_methods_list = [];
|
||||||
|
|
||||||
|
// generate .md
|
||||||
|
foreach ($FullClassList as $FullClass) {
|
||||||
|
$reflectionClass = new \ReflectionClass($FullClass);
|
||||||
|
$methods = ($reflectionClass)->getMethods();
|
||||||
|
$shortClass = str_replace('CondorcetPHP\Condorcet\\', '', $FullClass);
|
||||||
|
|
||||||
|
$full_methods_list[$shortClass] = [
|
||||||
|
'FullClass' => $FullClass,
|
||||||
|
'shortClass' => $shortClass,
|
||||||
|
'ReflectionClass' => $reflectionClass,
|
||||||
|
'methods' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($methods as $oneMethod) {
|
||||||
|
$method_array = $full_methods_list[$shortClass]['methods'][$oneMethod->name] = [
|
||||||
|
'FullClass' => $FullClass,
|
||||||
|
'shortClass' => $shortClass,
|
||||||
|
'name' => $oneMethod->name,
|
||||||
|
'static' => $oneMethod->isStatic(),
|
||||||
|
'visibility_public' => $oneMethod->isPublic(),
|
||||||
|
'visibility_protected' => $oneMethod->isProtected(),
|
||||||
|
'visibility_private' => $oneMethod->isPrivate(),
|
||||||
|
'ReflectionMethod' => $oneMethod,
|
||||||
|
'ReflectionClass' => $oneMethod->getDeclaringClass(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$total_methods++;
|
||||||
|
|
||||||
|
if (!$oneMethod->isInternal()) {
|
||||||
|
$total_nonInternal_methods++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write Markdown
|
||||||
|
if (!empty($apiAttribute = $oneMethod->getAttributes(PublicAPI::class)) && (empty($apiAttribute[0]->getArguments()) || \in_array(self::simpleClass($oneMethod->class), $apiAttribute[0]->getArguments(), true))) {
|
||||||
|
$path = $pathDirectory . str_replace('\\', '_', self::simpleClass($oneMethod->class)) . ' Class/';
|
||||||
|
|
||||||
|
if (!is_dir($path)) {
|
||||||
|
mkdir($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($path.self::makeFilename($oneMethod), $this->createMarkdownContent($oneMethod, $method_array));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print 'Public methods in doc: '.$inDoc.' / '.($inDoc + $non_inDoc).' | Total non-internal methods count: '.$total_nonInternal_methods.' | Number of Class: '.\count($FullClassList).' | Number of Methods including internals: '.$total_methods."\n";
|
||||||
|
|
||||||
|
// Add Index
|
||||||
|
$file_content = "> **[Presentation](../README.md) | [Manual](https://github.com/julien-boudry/Condorcet/wiki) | Methods References | [Tests](../Tests)**\n\n".
|
||||||
|
|
||||||
|
"# Public API Index*_\n".
|
||||||
|
|
||||||
|
"_*: I try to update and complete the documentation. See also [the manual](https://github.com/julien-boudry/Condorcet/wiki), [the tests](../Tests) also produce many examples. And create issues for questions or fixing documentation!_\n\n";
|
||||||
|
|
||||||
|
|
||||||
|
$file_content .= $this->makeIndex($full_methods_list);
|
||||||
|
|
||||||
|
$file_content .= "\n\n\n";
|
||||||
|
|
||||||
|
uksort($full_methods_list, 'strnatcmp');
|
||||||
|
$file_content .= "# Full Class & Methods References\n".
|
||||||
|
"_Including above methods from public API_\n\n";
|
||||||
|
|
||||||
|
$file_content .= $this->makeProfundis($full_methods_list);
|
||||||
|
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
file_put_contents($pathDirectory.'README.md', $file_content);
|
||||||
|
|
||||||
|
|
||||||
|
echo 'YAH ! <br>' . (microtime(true) - $start_time) .'s';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build Methods
|
||||||
|
|
||||||
|
protected function createMarkdownContent(\ReflectionMethod $method, array $entry): string
|
||||||
|
{
|
||||||
|
// Header
|
||||||
|
$md = '## '.self::getModifiersName($method).' '. self::simpleClass($method->class).'::'.$method->name."\n\n".
|
||||||
|
"### Description \n\n".
|
||||||
|
self::computeRepresentationAsPHP($method)."\n\n".
|
||||||
|
$method->getAttributes(Description::class)[0]->getArguments()[0]."\n ";
|
||||||
|
|
||||||
|
// Input
|
||||||
|
if ($method->getNumberOfParameters() > 0) {
|
||||||
|
foreach ($method->getParameters() as $key => $value) {
|
||||||
|
if (!empty($attributes = $value->getAttributes(FunctionParameter::class))) {
|
||||||
|
$pt = $attributes[0]->newInstance()->text;
|
||||||
|
} elseif (isset($entry['input'][$value->getName()]['text'])) {
|
||||||
|
$pt = $entry['input'][$value->getName()]['text'];
|
||||||
|
} else {
|
||||||
|
$pt = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$md .= "\n\n".
|
||||||
|
'##### **'.$value->getName().':** *'.self::getTypeAsString($value->getType(), true)."* \n".
|
||||||
|
$pt." \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return Value
|
||||||
|
|
||||||
|
if (!empty($method->getAttributes(FunctionReturn::class))) {
|
||||||
|
$md .= "\n\n".
|
||||||
|
"### Return value: \n\n".
|
||||||
|
'*('.self::getTypeAsString($method->getReturnType(), true).')* '.$method->getAttributes(FunctionReturn::class)[0]->getArguments()[0]."\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw
|
||||||
|
if (!empty($method->getAttributes(Throws::class))) {
|
||||||
|
$md .= "\n\n".
|
||||||
|
"### Throws: \n\n";
|
||||||
|
|
||||||
|
foreach ($method->getAttributes(Throws::class)[0]->getArguments() as $arg) {
|
||||||
|
$md .= '* ```'.$arg."```\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Related methods
|
||||||
|
|
||||||
|
if (!empty($method->getAttributes(Related::class))) {
|
||||||
|
$md .= "\n".
|
||||||
|
"---------------------------------------\n\n".
|
||||||
|
"### Related method(s) \n\n";
|
||||||
|
|
||||||
|
foreach ($method->getAttributes(Related::class) as $RelatedAttribute) {
|
||||||
|
foreach ($RelatedAttribute->newInstance()->relatedList as $value) {
|
||||||
|
if ($value === self::simpleClass($method->class).'::'.$method->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$md .= '* '.self::cleverRelated($value)." \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($method->getAttributes(Example::class))) {
|
||||||
|
$md .= "\n".
|
||||||
|
"---------------------------------------\n\n".
|
||||||
|
"### Examples and explanation\n\n";
|
||||||
|
|
||||||
|
foreach ($method->getAttributes(Example::class) as $ExampleAttribute) {
|
||||||
|
$ExampleAttribute = $ExampleAttribute->newInstance();
|
||||||
|
|
||||||
|
$md .= '* **['.$ExampleAttribute->name.']('.$ExampleAttribute->link.")** \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $md;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeIndex(array $index): string
|
||||||
|
{
|
||||||
|
$file_content = '';
|
||||||
|
|
||||||
|
$testPublicAttribute = static function (\ReflectionMethod $reflectionMethod): bool {
|
||||||
|
return !(empty($apiAttribute = $reflectionMethod->getAttributes(PublicAPI::class)) || (!empty($apiAttribute[0]->getArguments()) && !\in_array(self::simpleClass($reflectionMethod->class), $apiAttribute[0]->getArguments(), true)));
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach ($index as $class => &$classMeta) {
|
||||||
|
usort($classMeta['methods'], static function (array $a, array $b): int {
|
||||||
|
if ($a['ReflectionMethod']->isStatic() === $b['ReflectionMethod']->isStatic()) {
|
||||||
|
return strnatcmp($a['ReflectionMethod']->name, $b['ReflectionMethod']->name);
|
||||||
|
} elseif ($a['ReflectionMethod']->isStatic() && !$b['ReflectionMethod']->isStatic()) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$classWillBePublic = false;
|
||||||
|
|
||||||
|
if ($classMeta['ReflectionClass']->getAttributes(PublicAPI::class)) {
|
||||||
|
$classWillBePublic = true;
|
||||||
|
} else {
|
||||||
|
foreach ($classMeta['methods'] as $oneMethod) {
|
||||||
|
if ($testPublicAttribute($oneMethod['ReflectionMethod'])) {
|
||||||
|
$classWillBePublic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($classMeta['ReflectionClass']->getReflectionConstants() as $oneConstant) {
|
||||||
|
if (!empty($oneConstant->getAttributes(PublicAPI::class))) {
|
||||||
|
$classWillBePublic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($classMeta['ReflectionClass']->getProperties() as $onePropertie) {
|
||||||
|
if (!empty($onePropertie->getAttributes(PublicAPI::class))) {
|
||||||
|
$classWillBePublic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($classWillBePublic) {
|
||||||
|
$isEnum = enum_exists(($enumCases = $classMeta['ReflectionClass'])->name);
|
||||||
|
|
||||||
|
$file_content .= "\n";
|
||||||
|
$file_content .= '### CondorcetPHP\Condorcet\\'.$class.' '.((!$isEnum) ? 'Class' : 'Enum')." \n\n";
|
||||||
|
|
||||||
|
if ($isEnum) {
|
||||||
|
$file_content .= $this->makeEnumeCases(new \ReflectionEnum($enumCases->name), false);
|
||||||
|
$file_content .= "\n";
|
||||||
|
} else {
|
||||||
|
$file_content .= $this->makeConstants($classMeta['ReflectionClass'], \ReflectionClassConstant::IS_PUBLIC, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content .= $this->makeProperties($classMeta['ReflectionClass'], null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($classMeta['methods'] as $oneMethod) {
|
||||||
|
if (!$testPublicAttribute($oneMethod['ReflectionMethod']) || !$oneMethod['ReflectionMethod']->isUserDefined()) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$url = str_replace('\\', '_', self::simpleClass($oneMethod['ReflectionMethod']->class)).' Class/'.self::getModifiersName($oneMethod['ReflectionMethod']).' '. str_replace('\\', '_', self::simpleClass($oneMethod['ReflectionMethod']->class).'--'. $oneMethod['ReflectionMethod']->name) . '.md';
|
||||||
|
$url = str_replace(' ', '%20', $url);
|
||||||
|
|
||||||
|
$file_content .= '* ['.self::computeRepresentationAsForIndex($oneMethod['ReflectionMethod']).']('.$url.')';
|
||||||
|
|
||||||
|
if (isset($oneMethod['ReflectionMethod']) && $oneMethod['ReflectionMethod']->hasReturnType()) {
|
||||||
|
$file_content .= ': '.self::getTypeAsString($oneMethod['ReflectionMethod']->getReturnType(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content .= " \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeEnumeCases(\ReflectionEnum $enumReflection, bool $shortName = false): string
|
||||||
|
{
|
||||||
|
$cases = $enumReflection->getCases();
|
||||||
|
|
||||||
|
$r = '';
|
||||||
|
|
||||||
|
foreach ($cases as $oneCase) {
|
||||||
|
$name = ($shortName) ? $enumReflection->getShortName() : self::simpleClass($enumReflection->getName());
|
||||||
|
$r .= '* ```case '.$name.'::'.$oneCase->getName()."``` \n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeConstants(\ReflectionClass $class, ?int $type = null, bool $mustHaveApiAttribute = false, bool $addMdCodeTag = true): string
|
||||||
|
{
|
||||||
|
$file_content = '';
|
||||||
|
|
||||||
|
$hasConstants = false;
|
||||||
|
|
||||||
|
foreach ($class->getReflectionConstants($type) as $constant) {
|
||||||
|
if (!$mustHaveApiAttribute || !empty($constant->getAttributes(PublicAPI::class))) {
|
||||||
|
$file_content .= '* ';
|
||||||
|
$file_content .= $addMdCodeTag ? '```' : '';
|
||||||
|
|
||||||
|
$file_content .= $constant->isFinal() ? 'final ' : '';
|
||||||
|
|
||||||
|
$file_content .= $constant->isPublic() ? 'public' : '';
|
||||||
|
$file_content .= $constant->isProtected() ? 'protected' : '';
|
||||||
|
$file_content .= $constant->isPrivate() ? 'private' : '';
|
||||||
|
|
||||||
|
$file_content .= ' const '.$constant->getName().': ('.\gettype($constant->getValue()).')';
|
||||||
|
$file_content .= $addMdCodeTag ? '``` ' : '';
|
||||||
|
$file_content .= "\n";
|
||||||
|
$hasConstants = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasConstants) {
|
||||||
|
$file_content .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeProperties(\ReflectionClass $class, ?int $type = null, bool $mustHaveApiAttribute = false, bool $addMdCodeTag = true): string
|
||||||
|
{
|
||||||
|
$file_content = '';
|
||||||
|
|
||||||
|
$hasConstants = false;
|
||||||
|
|
||||||
|
foreach ($class->getProperties($type) as $propertie) {
|
||||||
|
if (!$mustHaveApiAttribute || !empty($propertie->getAttributes(PublicAPI::class))) {
|
||||||
|
$file_content .= '* ';
|
||||||
|
$file_content .= $addMdCodeTag ? '```' : '';
|
||||||
|
|
||||||
|
$file_content .= $propertie->isReadOnly() ? 'readonly ' : '';
|
||||||
|
|
||||||
|
$file_content .= $propertie->isPublic() ? 'public ' : '';
|
||||||
|
$file_content .= $propertie->isProtected() ? 'protected ' : '';
|
||||||
|
$file_content .= $propertie->isPrivate() ? 'private ' : '';
|
||||||
|
|
||||||
|
$file_content .= $propertie->isStatic() ? 'static ' : '';
|
||||||
|
|
||||||
|
$file_content .= ((string) $propertie->getType()).' $'.$propertie->getName();
|
||||||
|
$file_content .= $addMdCodeTag ? '``` ' : '';
|
||||||
|
$file_content .= "\n";
|
||||||
|
$hasConstants = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasConstants) {
|
||||||
|
$file_content .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeProfundis(array $index): string
|
||||||
|
{
|
||||||
|
$file_content = '';
|
||||||
|
|
||||||
|
foreach ($index as $class => &$classMeta) {
|
||||||
|
usort($classMeta['methods'], static function (array $a, array $b): int {
|
||||||
|
if ($a['static'] === $b['static']) {
|
||||||
|
if ($a['visibility_public'] && !$b['visibility_public']) {
|
||||||
|
return -1;
|
||||||
|
} elseif (!$a['visibility_public'] && $b['visibility_public']) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
if ($a['visibility_protected'] && !$b['visibility_protected']) {
|
||||||
|
return -1;
|
||||||
|
} elseif (!$a['visibility_protected'] && $b['visibility_protected']) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return strnatcmp($a['name'], $b['name']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($a['static'] && !$b['static']) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$file_content .= "\n";
|
||||||
|
$file_content .= '#### ';
|
||||||
|
$file_content .= ($classMeta['ReflectionClass']->isAbstract()) ? 'Abstract ' : '';
|
||||||
|
$file_content .= 'CondorcetPHP\Condorcet\\'.$class.' ';
|
||||||
|
|
||||||
|
$file_content .= ($p = $classMeta['ReflectionClass']->getParentClass()) ? 'extends '.$p->name.' ' : '';
|
||||||
|
|
||||||
|
$interfaces = implode(', ', $classMeta['ReflectionClass']->getInterfaceNames());
|
||||||
|
$file_content .= (!empty($interfaces)) ? 'implements '.$interfaces : '';
|
||||||
|
|
||||||
|
$file_content .= " \n";
|
||||||
|
$file_content .= "```php\n";
|
||||||
|
|
||||||
|
$isEnum = enum_exists(($enumCases = $classMeta['ReflectionClass'])->name);
|
||||||
|
|
||||||
|
if ($isEnum) {
|
||||||
|
$file_content .= $this->makeEnumeCases(new \ReflectionEnum($enumCases->name), true);
|
||||||
|
$file_content .= "\n";
|
||||||
|
} else {
|
||||||
|
$file_content .= $this->makeConstants(class: $classMeta['ReflectionClass'], addMdCodeTag: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content .= $this->makeProperties(class: $classMeta['ReflectionClass'], addMdCodeTag: false);
|
||||||
|
|
||||||
|
foreach ($classMeta['methods'] as $oneMethod) {
|
||||||
|
if ($oneMethod['ReflectionMethod']->isUserDefined()) {
|
||||||
|
$parameters = $oneMethod['ReflectionMethod']->getParameters();
|
||||||
|
$parameters_string = '';
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
foreach ($parameters as $oneP) {
|
||||||
|
$parameters_string .= (++$i > 1) ? ', ' : '';
|
||||||
|
|
||||||
|
if ($oneP->getType() !== null) {
|
||||||
|
$parameters_string .= self::getTypeAsString($oneP->getType()) . ' ';
|
||||||
|
}
|
||||||
|
$parameters_string .= '$'.$oneP->name;
|
||||||
|
|
||||||
|
if ($oneP->isDefaultValueAvailable()) {
|
||||||
|
$parameters_string .= ' = '.self::speakBool($oneP->getDefaultValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$representation = ($oneMethod['visibility_public']) ? 'public ' : '';
|
||||||
|
$representation .= ($oneMethod['visibility_protected']) ? 'protected ' : '';
|
||||||
|
$representation .= ($oneMethod['visibility_private']) ? 'private ' : '';
|
||||||
|
|
||||||
|
$representation .= ($oneMethod['static']) ? 'static ' : '';
|
||||||
|
$representation .= $oneMethod['name'] . ' ('.$parameters_string.')';
|
||||||
|
|
||||||
|
if ($oneMethod['ReflectionMethod']->hasReturnType()) {
|
||||||
|
$representation .= ': '.self::getTypeAsString($oneMethod['ReflectionMethod']->getReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content .= '* '.$representation." \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content .= "```\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file_content;
|
||||||
|
}
|
||||||
|
}
|
14
include/Condorcet/Dev/Dockerfile.infection
Normal file
14
include/Condorcet/Dev/Dockerfile.infection
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM condorcet
|
||||||
|
|
||||||
|
RUN pecl install pcov \
|
||||||
|
&& docker-php-ext-enable pcov
|
||||||
|
|
||||||
|
RUN php composer.phar install --optimize-autoloader --no-progress \
|
||||||
|
&& rm -rf /root/.composer/cache
|
||||||
|
|
||||||
|
ENTRYPOINT [ "vendor/bin/infection" ]
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# 1. docker build -f Dockerfile.infection -t infection .
|
||||||
|
# 2. docker run --hostname="infection" --mount type=bind,src=$(pwd),dst=/usr/src/condorcetapp --rm -it infection:latest
|
||||||
|
# The infection test takes a long time. You can use --filter to only test a portion of the code.
|
6
include/Condorcet/Dev/Get_Some_Codes_Stats.md
Normal file
6
include/Condorcet/Dev/Get_Some_Codes_Stats.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Get some codes stats:
|
||||||
|
|
||||||
|
```
|
||||||
|
vendor/bin/phploc src Benchmarks Dev Tests Examples # With Test and Examples
|
||||||
|
vendor/bin/phploc src Benchmarks Dev # Without Tests and Examples
|
||||||
|
```
|
8
include/Condorcet/Dev/Infection.md
Normal file
8
include/Condorcet/Dev/Infection.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
To generate Infection report:
|
||||||
|
|
||||||
|
_Customize with the right number of threads for your system._
|
||||||
|
```
|
||||||
|
php vendor/bin/infection --threads=24
|
||||||
|
```
|
||||||
|
|
||||||
|
_Logs at the racine, infection.log_
|
@ -0,0 +1,83 @@
|
|||||||
|
2021-01-03 - > 7590291d
|
||||||
|
|
||||||
|
2479 mutations were generated:
|
||||||
|
1872 mutants were killed
|
||||||
|
14 mutants were not covered by tests
|
||||||
|
427 covered mutants were not detected
|
||||||
|
110 errors were encountered
|
||||||
|
0 syntax errors were encountered
|
||||||
|
56 time outs were encountered
|
||||||
|
0 mutants required more time than configured
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Mutation Score Indicator (MSI): 82%
|
||||||
|
Mutation Code Coverage: 99%
|
||||||
|
Covered Code MSI: 82%
|
||||||
|
|
||||||
|
2021-09-28 - 9882d9c
|
||||||
|
|
||||||
|
2538 mutations were generated:
|
||||||
|
1879 mutants were killed
|
||||||
|
14 mutants were not covered by tests
|
||||||
|
479 covered mutants were not detected
|
||||||
|
110 errors were encountered
|
||||||
|
0 syntax errors were encountered
|
||||||
|
56 time outs were encountered
|
||||||
|
0 mutants required more time than configured
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Mutation Score Indicator (MSI): 80%
|
||||||
|
Mutation Code Coverage: 99%
|
||||||
|
Covered Code MSI: 81%
|
||||||
|
|
||||||
|
|
||||||
|
2021-09-20 - 24d4ba4
|
||||||
|
|
||||||
|
2586 mutations were generated:
|
||||||
|
1892 mutants were killed
|
||||||
|
42 mutants were not covered by tests
|
||||||
|
479 covered mutants were not detected
|
||||||
|
117 errors were encountered
|
||||||
|
0 syntax errors were encountered
|
||||||
|
56 time outs were encountered
|
||||||
|
0 mutants required more time than configured
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Mutation Score Indicator (MSI): 79%
|
||||||
|
Mutation Code Coverage: 98%
|
||||||
|
Covered Code MSI: 81%
|
||||||
|
|
||||||
|
|
||||||
|
2021-08-05 - 40bfb78
|
||||||
|
|
||||||
|
2685 mutations were generated:
|
||||||
|
1962 mutants were killed
|
||||||
|
53 mutants were not covered by tests
|
||||||
|
492 covered mutants were not detected
|
||||||
|
122 errors were encountered
|
||||||
|
0 syntax errors were encountered
|
||||||
|
56 time outs were encountered
|
||||||
|
0 mutants required more time than configured
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Mutation Score Indicator (MSI): 79%
|
||||||
|
Mutation Code Coverage: 98%
|
||||||
|
Covered Code MSI: 81%
|
||||||
|
|
||||||
|
|
||||||
|
2022-07-01 - 39b9c31
|
||||||
|
|
||||||
|
3207 mutations were generated:
|
||||||
|
1229 mutants were killed
|
||||||
|
0 mutants were configured to be ignored
|
||||||
|
42 mutants were not covered by tests
|
||||||
|
191 covered mutants were not detected
|
||||||
|
1 errors were encountered
|
||||||
|
0 syntax errors were encountered
|
||||||
|
11 time outs were encountered
|
||||||
|
1733 mutants required more time than configured
|
||||||
|
|
||||||
|
Metrics:
|
||||||
|
Mutation Score Indicator (MSI): 84%
|
||||||
|
Mutation Code Coverage: 97%
|
||||||
|
Covered Code MSI: 86%
|
94
include/Condorcet/Dev/bugs/JitBug.php
Normal file
94
include/Condorcet/Dev/bugs/JitBug.php
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
// Linux: php -dzend_extension=opcache -dopcache.enable_cli=1 -dopcache.jit_buffer_size=100M -dopcache.jit=tracing Dev/bugs/JitBug.php
|
||||||
|
// Windows: php -d zend_extension=opcache -d opcache.enable_cli=1 -d opcache.jit_buffer_size=100M -d opcache.jit=tracing Dev/bugs/JitBug.php
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
// Not happening on 8.1
|
||||||
|
// Bug only with jit tracing mode (working with jit function) (test on PHP 8.0.10 NTS on x64)
|
||||||
|
// Working with or without opcache
|
||||||
|
|
||||||
|
# Bugs
|
||||||
|
// PHP Fatal error: Uncaught TypeError: CondorcetPHP\Condorcet\Result::__construct(): Argument #6 ($seats) must be of type ?int, CondorcetPHP\Condorcet\Election given, called in C:\dev_scripts\Condorcet\lib\Algo\Method.php on line 84 and defined in C:\dev_scripts\Condorcet\lib\Result.php:89
|
||||||
|
// Stack trace:
|
||||||
|
// #0 C:\dev_scripts\Condorcet\lib\Algo\Method.php(84): CondorcetPHP\Condorcet\Result->__construct()
|
||||||
|
// #1 C:\dev_scripts\Condorcet\lib\Algo\Methods\STV\SingleTransferableVote.php(91): CondorcetPHP\Condorcet\Algo\Method->createResult()
|
||||||
|
// #2 C:\dev_scripts\Condorcet\lib\Algo\Method.php(63): CondorcetPHP\Condorcet\Algo\Methods\STV\SingleTransferableVote->compute()
|
||||||
|
// #3 C:\dev_scripts\Condorcet\lib\ElectionProcess\ResultsProcess.php(80): CondorcetPHP\Condorcet\Algo\Method->getResult()
|
||||||
|
// #4 C:\dev_scripts\Condorcet\Dev\bugs\JitBug.php(24): CondorcetPHP\Condorcet\Election->getResult()
|
||||||
|
// #5 {main}
|
||||||
|
// thrown in C:\dev_scripts\Condorcet\lib\Result.php on line 89
|
||||||
|
|
||||||
|
# Test code
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../../__CondorcetAutoload.php';
|
||||||
|
|
||||||
|
for ($i=1; $i <= 4000; $i++) {
|
||||||
|
|
||||||
|
# With Condorcet
|
||||||
|
$election = new Election;
|
||||||
|
|
||||||
|
$election->parseCandidates('A;B;C');
|
||||||
|
|
||||||
|
$election->addVote('A>B>C');
|
||||||
|
|
||||||
|
$election->getResult('Schulze');
|
||||||
|
$election->getResult('STV');
|
||||||
|
|
||||||
|
# Tentative to reproduce (impossible...)
|
||||||
|
// $a = new A (new Bar);
|
||||||
|
// $b = new B (new Bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Tentative to reproduce (impossible...)
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
{
|
||||||
|
public function __construct(public string $fromMethod, public string $byClass, public Bar $election, public array $result, public $stats, public ?int $seats = null, public array $methodOptions = [])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Base
|
||||||
|
{
|
||||||
|
public const IS_PROPORTIONAL = false;
|
||||||
|
|
||||||
|
public Foo $foo;
|
||||||
|
|
||||||
|
public function __construct(public Bar $barInstance)
|
||||||
|
{
|
||||||
|
$this->foo = new Foo(
|
||||||
|
fromMethod: 'test',
|
||||||
|
byClass: $this::class,
|
||||||
|
election: $this->barInstance,
|
||||||
|
result: [],
|
||||||
|
stats: [],
|
||||||
|
seats: (static::IS_PROPORTIONAL) ? $this->getSeats() : null,
|
||||||
|
methodOptions: []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSeats(): int
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A extends Base
|
||||||
|
{
|
||||||
|
public const IS_PROPORTIONAL = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends Base
|
||||||
|
{
|
||||||
|
public const IS_PROPORTIONAL = true;
|
||||||
|
}
|
34
include/Condorcet/Dev/generate-large-vote-input_file.php
Normal file
34
include/Condorcet/Dev/generate-large-vote-input_file.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__.'/../__CondorcetAutoload.php';
|
||||||
|
|
||||||
|
///
|
||||||
|
$number_of_votes = 100_000_000;
|
||||||
|
$number_of_candidates = 8;
|
||||||
|
///
|
||||||
|
|
||||||
|
$candidateName = 'A';
|
||||||
|
|
||||||
|
$candidates = [];
|
||||||
|
|
||||||
|
for ($i=0; $i < $number_of_candidates; $i++) {
|
||||||
|
$candidates[] = $candidateName++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = new \SplFileObject(__DIR__.'/large.votes', 'w+');
|
||||||
|
$cache = '';
|
||||||
|
|
||||||
|
for ($i=0; $i < $number_of_votes; $i++) {
|
||||||
|
shuffle($candidates);
|
||||||
|
|
||||||
|
$cache .= implode('>', $candidates)."\n";
|
||||||
|
|
||||||
|
if (mb_strlen($cache) > 5_000_000) {
|
||||||
|
$file->fwrite($cache);
|
||||||
|
$cache = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file->fwrite($cache);
|
@ -0,0 +1,5 @@
|
|||||||
|
To generate documentation:
|
||||||
|
|
||||||
|
```
|
||||||
|
php Dev/update-documentation.php
|
||||||
|
```
|
7
include/Condorcet/Dev/interactiveShell.php
Normal file
7
include/Condorcet/Dev/interactiveShell.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace CondorcetPHP\Condorcet;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
130
include/Condorcet/Dev/migrate_yamlDoc_to_attributes.php
Normal file
130
include/Condorcet/Dev/migrate_yamlDoc_to_attributes.php
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes\{PublicAPI};
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
require_once __DIR__.str_replace('/', \DIRECTORY_SEPARATOR, '/../vendor/../vendor/autoload.php');
|
||||||
|
|
||||||
|
|
||||||
|
$doc = Yaml::parseFile(__DIR__.'/../Documentation/doc.yaml');
|
||||||
|
|
||||||
|
// Header & Prefix
|
||||||
|
$header = $doc[0]['header'];
|
||||||
|
unset($doc[0]);
|
||||||
|
|
||||||
|
$undocumented_prefix = $doc[1]['undocumented_prefix'] . "\n";
|
||||||
|
unset($doc[1]);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
$index = [];
|
||||||
|
|
||||||
|
foreach ($doc as &$entry) {
|
||||||
|
if (!\is_array($entry['class'])) {
|
||||||
|
$entry['class'] = [$entry['class']];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($entry['class'] as $class) {
|
||||||
|
$method = $entry;
|
||||||
|
$method['class'] = $class;
|
||||||
|
|
||||||
|
$index[$method['class']][$method['name']] = $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$patternReplaceLastNewLine = '/(.*)\n$/';
|
||||||
|
|
||||||
|
foreach ($index as $ClassName => $ClassData) {
|
||||||
|
$path_to_file = [
|
||||||
|
__DIR__.'/../lib/'.str_replace('\\', '/', $ClassName).'.php',
|
||||||
|
__DIR__.'/../lib/CondorcetVersion.php',
|
||||||
|
__DIR__.'/../lib/Linkable.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($ClassName === 'Election') {
|
||||||
|
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/CandidatesProcess.php';
|
||||||
|
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/VotesProcess.php';
|
||||||
|
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/ResultsProcess.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var_dump($path_to_file);
|
||||||
|
|
||||||
|
foreach ($path_to_file as $oneFile) {
|
||||||
|
$file_contents = file_get_contents($oneFile);
|
||||||
|
|
||||||
|
foreach ($ClassData as $MethodName => $MethodData) {
|
||||||
|
var_dump($ClassName.'->'.$MethodName);
|
||||||
|
|
||||||
|
$description = $MethodData['description'];
|
||||||
|
$description = str_replace('$', '\\\$', $description);
|
||||||
|
$description = preg_replace($patternReplaceLastNewLine, '$1', $description);
|
||||||
|
$description = str_replace(["\n ", "\n"], '\\n', $description);
|
||||||
|
$description = str_replace('"', '\"', $description);
|
||||||
|
|
||||||
|
$attributes = '$3#[Description("'.$description.'")]$2';
|
||||||
|
|
||||||
|
if (isset($MethodData['return'])) {
|
||||||
|
$returnV = $MethodData['return'];
|
||||||
|
$returnV = preg_replace($patternReplaceLastNewLine, '$1', $returnV);
|
||||||
|
$returnV = str_replace(["\n ", "\n"], '\\n', $returnV);
|
||||||
|
$returnV = str_replace('"', '\"', $returnV);
|
||||||
|
|
||||||
|
$attributes .= '$3#[FunctionReturn("'.$returnV.'")]$2';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isset($MethodData['examples'])) {
|
||||||
|
$examples = $MethodData['examples'];
|
||||||
|
$examples = preg_replace($patternReplaceLastNewLine, '$1', $examples);
|
||||||
|
$examples = str_replace(["\n ", "\n"], '\\n', $examples);
|
||||||
|
$examples = str_replace('"', '\"', $examples);
|
||||||
|
|
||||||
|
$arg = '';
|
||||||
|
$i = 1;
|
||||||
|
foreach ($examples as $oneExampleKey => $oneExample) {
|
||||||
|
if ($i++ > 1) {
|
||||||
|
$arg .= ', ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$arg .= '"'.$oneExampleKey.'||'.$oneExample.'"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes .= '$3#[Examples('.$arg.')]$2';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($MethodData['related'])) {
|
||||||
|
$related = $MethodData['related'];
|
||||||
|
$related = str_replace('"', '\"', $related);
|
||||||
|
|
||||||
|
$arg = '';
|
||||||
|
$i = 1;
|
||||||
|
foreach ($related as $oneRelated) {
|
||||||
|
if ($i++ > 1) {
|
||||||
|
$arg .= ', ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$arg .= '"'.$oneRelated.'"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes .= '$3#[Related('.$arg.')]$2';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$pattern = '/(#\[PublicAPI\])(\n)(.*)(public.*function '.$MethodName.' *\()/';
|
||||||
|
$replacement = '$1$2'.$attributes.'$3$4';
|
||||||
|
|
||||||
|
$file_contents = preg_replace(
|
||||||
|
$pattern,
|
||||||
|
$replacement,
|
||||||
|
$file_contents
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($oneFile, $file_contents);
|
||||||
|
}
|
||||||
|
}
|
40
include/Condorcet/Dev/update-documentation.php
Normal file
40
include/Condorcet/Dev/update-documentation.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\Generate;
|
||||||
|
|
||||||
|
require_once __DIR__.str_replace('/', \DIRECTORY_SEPARATOR, '/../vendor/../vendor/autoload.php');
|
||||||
|
|
||||||
|
// Build command
|
||||||
|
|
||||||
|
$path = mb_substr(__DIR__, 0, mb_strlen(__DIR__) - 4);
|
||||||
|
$path .= \DIRECTORY_SEPARATOR.'Documentation';
|
||||||
|
|
||||||
|
// Clear folder
|
||||||
|
|
||||||
|
function rrmdir(string $dir, string $path): void
|
||||||
|
{
|
||||||
|
if (is_dir($dir)) {
|
||||||
|
$objects = scandir($dir);
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
if ($object !== '.' && $object !== '..') {
|
||||||
|
if (filetype($dir.\DIRECTORY_SEPARATOR.$object) === 'dir') {
|
||||||
|
rrmdir($dir.\DIRECTORY_SEPARATOR.$object, $path);
|
||||||
|
} else {
|
||||||
|
unlink($dir.\DIRECTORY_SEPARATOR.$object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reset($objects);
|
||||||
|
if ($dir !== $path) {
|
||||||
|
rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rrmdir($path, $path);
|
||||||
|
|
||||||
|
// Execute command
|
||||||
|
|
||||||
|
new Generate($path);
|
34
include/Condorcet/Dockerfile
Normal file
34
include/Condorcet/Dockerfile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
FROM php:8.1-cli-bullseye
|
||||||
|
|
||||||
|
COPY . /usr/src/condorcetapp
|
||||||
|
WORKDIR /usr/src/condorcetapp
|
||||||
|
ENV PATH="${PATH}:/usr/src/condorcetapp/bin"
|
||||||
|
|
||||||
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
|
||||||
|
&& sed -i "s/128M/4096M/g" "$PHP_INI_DIR/php.ini" \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends --fix-missing -yqq git unzip curl \
|
||||||
|
&& curl --silent --show-error https://getcomposer.org/installer | php \
|
||||||
|
&& chmod +x /usr/src/condorcetapp/bin/* \
|
||||||
|
&& rm -fR composer.lock vendor \
|
||||||
|
&& php composer.phar install --no-dev --optimize-autoloader --no-progress \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& apt-get autoremove -y \
|
||||||
|
&& rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/root/.composer/cache \
|
||||||
|
/tmp/* \
|
||||||
|
/var/tmp/* \
|
||||||
|
/usr/share/man \
|
||||||
|
/usr/share/doc \
|
||||||
|
/usr/share/doc-base
|
||||||
|
|
||||||
|
# Sf Command completion
|
||||||
|
RUN php bin/condorcet completion bash | tee /etc/bash_completion.d/console-events-terminate
|
||||||
|
|
||||||
|
ENTRYPOINT [ "condorcet" ]
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# 1. docker build -t condorcet .
|
||||||
|
# 2. docker run --hostname="condorcet" --rm -it condorcet:latest
|
||||||
|
# 3. docker run --hostname="condorcet" --rm -it condorcet:latest election -c "A;B;C" -w "A>B;C>A;B>A" -lr "Schulze"
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Algo\Pairwise::getExplicitPairwise
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Algo\Pairwise->getExplicitPairwise ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the Pairwise.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* Pairwise as an explicit array .
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getPairwise](../Election%20Class/public%20Election--getPairwise.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Algo\Pairwise::getObjectVersion
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Algo\Pairwise->getObjectVersion ( [bool $major = false] ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Condorcet PHP version who built this Election object. Usefull pour serializing Election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **major:** *```bool```*
|
||||||
|
true will return : '2.0' and false will return : '2.0.0'.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Condorcet PHP version.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getVersion](../Condorcet%20Class/public%20static%20Condorcet--getVersion.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public static Algo\Tools\StvQuotas::make
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Algo\Tools\StvQuotas::make ( string $quota ): self
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the Enum Quotas option for STV methods
|
||||||
|
|
||||||
|
|
||||||
|
##### **quota:** *```string```*
|
||||||
|
Quota name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```self```)* The Quota option
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - STV method](https://github.com/julien-boudry/Condorcet/blob/master/VOTING_METHODS.md#single-transferable-vote)**
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Candidate::__construct
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->__construct ( string $name )
|
||||||
|
```
|
||||||
|
|
||||||
|
Build a candidate.
|
||||||
|
|
||||||
|
|
||||||
|
##### **name:** *```string```*
|
||||||
|
Candidate Name.
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Candidate::setName](../Candidate%20Class/public%20Candidate--setName.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Create Candidates](https://github.com/julien-boudry/Condorcet/wiki/II-%23-A.-Create-an-Election-%23-2.-Create-Candidates)**
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Candidate::countLinks
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->countLinks ( ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Count number of linked election to this object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of linked elections.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Vote::countLinks](../Vote%20Class/public%20Vote--countLinks.md)
|
||||||
|
* [Vote::getLinks](../Vote%20Class/public%20Vote--getLinks.md)
|
||||||
|
* [Candidate::getLinks](../Candidate%20Class/public%20Candidate--getLinks.md)
|
||||||
|
* [Vote::haveLink](../Vote%20Class/public%20Vote--haveLink.md)
|
||||||
|
* [Candidate::haveLink](../Candidate%20Class/public%20Candidate--haveLink.md)
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Candidate::getCreateTimestamp
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getCreateTimestamp ( ): float
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the timestamp corresponding of the creation of this candidate.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```float```)* Timestamp
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Candidate::getTimestamp](../Candidate%20Class/public%20Candidate--getTimestamp.md)
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Candidate::getHistory
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getHistory ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Return an history of each namming change, with timestamp.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* An explicit multi-dimenssional array.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Candidate::getCreateTimestamp](../Candidate%20Class/public%20Candidate--getCreateTimestamp.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Candidate::getLinks
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getLinks ( ): WeakMap
|
||||||
|
```
|
||||||
|
|
||||||
|
Get elections object linked to this Vote or Candidate object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```WeakMap```)* Populated by each elections Condorcet object.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Vote::countLinks](../Vote%20Class/public%20Vote--countLinks.md)
|
||||||
|
* [Candidate::countLinks](../Candidate%20Class/public%20Candidate--countLinks.md)
|
||||||
|
* [Vote::getLinks](../Vote%20Class/public%20Vote--getLinks.md)
|
||||||
|
* [Vote::haveLink](../Vote%20Class/public%20Vote--haveLink.md)
|
||||||
|
* [Candidate::haveLink](../Candidate%20Class/public%20Candidate--haveLink.md)
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Candidate::getName
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getName ( ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the candidate name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Candidate name.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Candidate::getHistory](../Candidate%20Class/public%20Candidate--getHistory.md)
|
||||||
|
* [Candidate::setName](../Candidate%20Class/public%20Candidate--setName.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Candidate::getObjectVersion
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getObjectVersion ( [bool $major = false] ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Condorcet PHP version who built this Election object. Usefull pour serializing Election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **major:** *```bool```*
|
||||||
|
true will return : '2.0' and false will return : '2.0.0'.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Condorcet PHP version.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getVersion](../Condorcet%20Class/public%20static%20Condorcet--getVersion.md)
|
@ -0,0 +1,19 @@
|
|||||||
|
## public Candidate::getProvisionalState
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getProvisionalState ( ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
When you create yourself the vote object, without use the Election::addVote or other native election method. And if you use string input (or array of string).
|
||||||
|
Then, these string input will be converted to into temporary candidate objects, named "provisional". because you don't create the candidate yourself. They have a provisonal statut true.
|
||||||
|
When the vote will be added for the first time to an election, provisional candidate object with a name that matches an election candidate, will be converted into the election candidate. And first ranking will be save into Vote history (Vote::getHistory).
|
||||||
|
|
||||||
|
See VoteTest::testVoteHistory() test for a demonstration. In principle this is transparent from a usage point of view. If you want to avoid any non-strict comparisons, however, you should prefer to create your votes with the Election object, or with Candidate Objects in input. But, you must never getback a candidate marked as provisional in an another election in the same time, it's will not working.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True if candidate object is in a provisional state, false else.
|
||||||
|
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Candidate::getTimestamp
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->getTimestamp ( ): float
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the timestamp corresponding of the last namming change.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```float```)* Timestamp
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Candidate::getCreateTimestamp](../Candidate%20Class/public%20Candidate--getCreateTimestamp.md)
|
@ -0,0 +1,29 @@
|
|||||||
|
## public Candidate::haveLink
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->haveLink ( CondorcetPHP\Condorcet\Election $election ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if this election is linked with this Candidate/Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
##### **election:** *```CondorcetPHP\Condorcet\Election```*
|
||||||
|
Condorcet election to check.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True or False.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Vote::countLinks](../Vote%20Class/public%20Vote--countLinks.md)
|
||||||
|
* [Candidate::countLinks](../Candidate%20Class/public%20Candidate--countLinks.md)
|
||||||
|
* [Vote::getLinks](../Vote%20Class/public%20Vote--getLinks.md)
|
||||||
|
* [Candidate::getLinks](../Candidate%20Class/public%20Candidate--getLinks.md)
|
||||||
|
* [Vote::haveLink](../Vote%20Class/public%20Vote--haveLink.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Candidate::setName
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Candidate->setName ( string $name ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Change the candidate name.
|
||||||
|
*If this will not cause conflicts if the candidate is already participating in elections and would namesake. This situation will throw an exception.*
|
||||||
|
|
||||||
|
|
||||||
|
##### **name:** *```string```*
|
||||||
|
Candidate Name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* In case of success, return TRUE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\CandidateInvalidNameException```
|
@ -0,0 +1,26 @@
|
|||||||
|
## public static Condorcet::addMethod
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::addMethod ( string $methodClass ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
If you create your own Condorcet Algo. You will need it !
|
||||||
|
|
||||||
|
|
||||||
|
##### **methodClass:** *```string```*
|
||||||
|
The class name implementing your method. The class name includes the namespace it was declared in (e.g. Foo\Bar).
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True on Success. False on failure.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::isAuthMethod](../Condorcet%20Class/public%20static%20Condorcet--isAuthMethod.md)
|
||||||
|
* [static Condorcet::getMethodClass](../Condorcet%20Class/public%20static%20Condorcet--getMethodClass.md)
|
@ -0,0 +1,26 @@
|
|||||||
|
## public static Condorcet::getAuthMethods
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::getAuthMethods ( [bool $basic = false] ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Get a list of supported algorithm.
|
||||||
|
|
||||||
|
|
||||||
|
##### **basic:** *```bool```*
|
||||||
|
Include or not the natural Condorcet base algorithm.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* Populated by method string name. You can use it on getResult ... and others methods.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::isAuthMethod](../Condorcet%20Class/public%20static%20Condorcet--isAuthMethod.md)
|
||||||
|
* [static Condorcet::getMethodClass](../Condorcet%20Class/public%20static%20Condorcet--getMethodClass.md)
|
@ -0,0 +1,22 @@
|
|||||||
|
## public static Condorcet::getDefaultMethod
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::getDefaultMethod ( ): ?string
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the Condorcet static default method.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```?string```)* Method name.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getAuthMethods](../Condorcet%20Class/public%20static%20Condorcet--getAuthMethods.md)
|
||||||
|
* [static Condorcet::setDefaultMethod](../Condorcet%20Class/public%20static%20Condorcet--setDefaultMethod.md)
|
@ -0,0 +1,30 @@
|
|||||||
|
## public static Condorcet::getMethodClass
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::getMethodClass ( string $method ): ?string
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the full class path for a method.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```string```*
|
||||||
|
A valid method name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```?string```)* Return null is method not exist.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\AlgorithmException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getAuthMethods](../Condorcet%20Class/public%20static%20Condorcet--getAuthMethods.md)
|
@ -0,0 +1,26 @@
|
|||||||
|
## public static Condorcet::getVersion
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::getVersion ( [bool $major = false] ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the library version.
|
||||||
|
|
||||||
|
|
||||||
|
##### **major:** *```bool```*
|
||||||
|
* true will return : '2.0'
|
||||||
|
* false will return : '2.0.0'.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Condorcet PHP version.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getObjectVersion](../Election%20Class/public%20Election--getObjectVersion.md)
|
@ -0,0 +1,26 @@
|
|||||||
|
## public static Condorcet::isAuthMethod
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::isAuthMethod ( string $method ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Test if a method is in the result set of Condorcet::getAuthMethods.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```string```*
|
||||||
|
A valid method name or class.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True / False
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getMethodClass](../Condorcet%20Class/public%20static%20Condorcet--getMethodClass.md)
|
||||||
|
* [static Condorcet::getAuthMethods](../Condorcet%20Class/public%20static%20Condorcet--getAuthMethods.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public static Condorcet::setDefaultMethod
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public static Condorcet::setDefaultMethod ( string $method ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Put a new static method by default for the news Condorcet objects.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```string```*
|
||||||
|
A valid method name or class.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* In case of success, return TRUE
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getDefaultMethod](../Condorcet%20Class/public%20static%20Condorcet--getDefaultMethod.md)
|
@ -0,0 +1,10 @@
|
|||||||
|
## public Election::__construct
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->__construct ( )
|
||||||
|
```
|
||||||
|
|
||||||
|
Build a new Election.
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
## public Election::addCandidate
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->addCandidate ( [CondorcetPHP\Condorcet\Candidate|string|null $candidate = null] ): CondorcetPHP\Condorcet\Candidate
|
||||||
|
```
|
||||||
|
|
||||||
|
Add one candidate to an election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **candidate:** *```CondorcetPHP\Condorcet\Candidate|string|null```*
|
||||||
|
Alphanumeric string or CondorcetPHP\Condorcet\Candidate object. The whitespace of your candidate name will be trimmed. If null, this function will create a new candidate with an automatic name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Candidate```)* The new candidate object (your or automatic one). Throws an exception on error (existing candidate...).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\CandidateExistsException```
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\VotingHasStartedException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::parseCandidates](../Election%20Class/public%20Election--parseCandidates.md)
|
||||||
|
* [Election::addCandidatesFromJson](../Election%20Class/public%20Election--addCandidatesFromJson.md)
|
||||||
|
* [Election::removeCandidate](../Election%20Class/public%20Election--removeCandidate.md)
|
||||||
|
* [Election::getCandidatesList](../Election%20Class/public%20Election--getCandidatesList.md)
|
||||||
|
* [Election::canAddCandidate](../Election%20Class/public%20Election--canAddCandidate.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Manage Candidate](https://github.com/julien-boudry/Condorcet/wiki/II-%23-A.-Create-an-Election-%23-2.-Create-Candidates)**
|
@ -0,0 +1,38 @@
|
|||||||
|
## public Election::addCandidatesFromJson
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->addCandidatesFromJson ( string $input ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Import candidate from a JSON source.
|
||||||
|
|
||||||
|
|
||||||
|
##### **input:** *```string```*
|
||||||
|
JSON string input.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* List of newly registered candidate object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\CandidateExistsException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addCandidate](../Election%20Class/public%20Election--addCandidate.md)
|
||||||
|
* [Election::parseCandidates](../Election%20Class/public%20Election--parseCandidates.md)
|
||||||
|
* [Election::addVotesFromJson](../Election%20Class/public%20Election--addVotesFromJson.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Manage Candidates](https://github.com/julien-boudry/Condorcet/wiki/II-%23-A.-Create-an-Election-%23-2.-Create-Candidates)**
|
@ -0,0 +1,38 @@
|
|||||||
|
## public Election::addConstraint
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->addConstraint ( string $constraintClass ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Add a constraint rules as a valid class path.
|
||||||
|
|
||||||
|
|
||||||
|
##### **constraintClass:** *```string```*
|
||||||
|
A valid class path. Class must extend VoteConstraint class.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True on success.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\VoteConstraintException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getConstraints](../Election%20Class/public%20Election--getConstraints.md)
|
||||||
|
* [Election::clearConstraints](../Election%20Class/public%20Election--clearConstraints.md)
|
||||||
|
* [Election::testIfVoteIsValidUnderElectionConstraints](../Election%20Class/public%20Election--testIfVoteIsValidUnderElectionConstraints.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Vote Constraints](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-5.-Vote-Constraints)**
|
@ -0,0 +1,43 @@
|
|||||||
|
## public Election::addVote
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->addVote ( CondorcetPHP\Condorcet\Vote|array|string $vote [, array|string|null $tags = null] ): CondorcetPHP\Condorcet\Vote
|
||||||
|
```
|
||||||
|
|
||||||
|
Add a vote to an election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **vote:** *```CondorcetPHP\Condorcet\Vote|array|string```*
|
||||||
|
String or array representation. Or CondorcetPHP\Condorcet\Vote object. If you not provide yourself Vote object, a new one will be generate for you.
|
||||||
|
|
||||||
|
|
||||||
|
##### **tags:** *```array|string|null```*
|
||||||
|
String separated by commas or an array. Will add tags to the vote object for you. But you can too add it yourself to Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Vote```)* The vote object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\VoteMaxNumberReachedException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::parseVotes](../Election%20Class/public%20Election--parseVotes.md)
|
||||||
|
* [Election::addVotesFromJson](../Election%20Class/public%20Election--addVotesFromJson.md)
|
||||||
|
* [Election::removeVote](../Election%20Class/public%20Election--removeVote.md)
|
||||||
|
* [Election::getVotesList](../Election%20Class/public%20Election--getVotesList.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Vote Management](https://github.com/julien-boudry/Condorcet/wiki/II-%23-B.-Vote-management-%23-1.-Add-Vote)**
|
@ -0,0 +1,33 @@
|
|||||||
|
## public Election::addVotesFromJson
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->addVotesFromJson ( string $input ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Import votes from a Json source.
|
||||||
|
|
||||||
|
|
||||||
|
##### **input:** *```string```*
|
||||||
|
Json string input.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Count of new registered vote.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addVote](../Election%20Class/public%20Election--addVote.md)
|
||||||
|
* [Election::parseVotes](../Election%20Class/public%20Election--parseVotes.md)
|
||||||
|
* [Election::addCandidatesFromJson](../Election%20Class/public%20Election--addCandidatesFromJson.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Add Vote](https://github.com/julien-boudry/Condorcet/wiki/II-%23-B.-Vote-management-%23-1.-Add-Vote)**
|
@ -0,0 +1,27 @@
|
|||||||
|
## public Election::allowsVoteWeight
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->allowsVoteWeight ( [bool $rule = true] ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the setting and reset all result data.
|
||||||
|
Then the weight of votes (if specified) will be taken into account when calculating the results. Otherwise all votes will be considered equal.
|
||||||
|
By default, the voting weight is not activated and all votes are considered equal.
|
||||||
|
|
||||||
|
|
||||||
|
##### **rule:** *```bool```*
|
||||||
|
New rule.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* Return True
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::isVoteWeightAllowed](../Election%20Class/public%20Election--isVoteWeightAllowed.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Election::canAddCandidate
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->canAddCandidate ( CondorcetPHP\Condorcet\Candidate|string $candidate ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if a candidate is already registered. Uses strict Vote object comparison, but also string naming comparison in the election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **candidate:** *```CondorcetPHP\Condorcet\Candidate|string```*
|
||||||
|
String or Condorcet/Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True if your candidate is available, false otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addCandidate](../Election%20Class/public%20Election--addCandidate.md)
|
@ -0,0 +1,29 @@
|
|||||||
|
## public Election::clearConstraints
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->clearConstraints ( ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Clear all constraints rules and clear previous results.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* Return True.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getConstraints](../Election%20Class/public%20Election--getConstraints.md)
|
||||||
|
* [Election::addConstraints](../Election%20Class/public%20Election--addConstraints.md)
|
||||||
|
* [Election::testIfVoteIsValidUnderElectionConstraints](../Election%20Class/public%20Election--testIfVoteIsValidUnderElectionConstraints.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Vote Constraints](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-5.-Vote-Constraints)**
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Election::computeResult
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->computeResult ( [?string $method = null] ): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Really similar to Election::getResult() but not return anything. Just calculates silently and fill the cache.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```?string```*
|
||||||
|
Not requiered for use object default method. Set the string name of the algorithm for use an specific one.
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getWinner](../Election%20Class/public%20Election--getWinner.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
* [Condorcet::getDefaultMethod](../Condorcet%20Class/public%20Condorcet--getDefaultMethod.md)
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Election::countCandidates
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->countCandidates ( ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Count the number of registered candidates
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of registered candidates for this election.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getCandidatesList](../Election%20Class/public%20Election--getCandidatesList.md)
|
@ -0,0 +1,23 @@
|
|||||||
|
## public Election::countInvalidVoteWithConstraints
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->countInvalidVoteWithConstraints ( ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Count the number of actual invalid (if constraints functionality is enabled) but registered vote for this election.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of valid and registered vote into this election.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::countValidVoteWithConstraints](../Election%20Class/public%20Election--countValidVoteWithConstraints.md)
|
||||||
|
* [Election::countVotes](../Election%20Class/public%20Election--countVotes.md)
|
||||||
|
* [Election::sumValidVotesWeightWithConstraints](../Election%20Class/public%20Election--sumValidVotesWeightWithConstraints.md)
|
@ -0,0 +1,23 @@
|
|||||||
|
## public Election::countValidVoteWithConstraints
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->countValidVoteWithConstraints ( ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Count the number of actual registered and valid vote for this election. This method don't ignore votes constraints, only valid vote will be counted.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of valid and registered vote into this election.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::countInvalidVoteWithConstraints](../Election%20Class/public%20Election--countInvalidVoteWithConstraints.md)
|
||||||
|
* [Election::countVotes](../Election%20Class/public%20Election--countVotes.md)
|
||||||
|
* [Election::sumValidVotesWeightWithConstraints](../Election%20Class/public%20Election--sumValidVotesWeightWithConstraints.md)
|
@ -0,0 +1,30 @@
|
|||||||
|
## public Election::countVotes
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->countVotes ( [array|string|null $tags = null , bool $with = true] ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Count the number of actual registered and valid vote for this election. This method ignore votes constraints, only valid vote will be counted.
|
||||||
|
|
||||||
|
|
||||||
|
##### **tags:** *```array|string|null```*
|
||||||
|
Tag into string separated by commas, or an Array.
|
||||||
|
|
||||||
|
|
||||||
|
##### **with:** *```bool```*
|
||||||
|
Count Votes with this tag ou without this tag-.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of valid and registered vote into this election.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getVotesList](../Election%20Class/public%20Election--getVotesList.md)
|
||||||
|
* [Election::countValidVoteWithConstraints](../Election%20Class/public%20Election--countValidVoteWithConstraints.md)
|
@ -0,0 +1,19 @@
|
|||||||
|
## public Election::getCandidateObjectFromName
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getCandidateObjectFromName ( string $candidateName ): ?CondorcetPHP\Condorcet\Candidate
|
||||||
|
```
|
||||||
|
|
||||||
|
Find candidate object by string and return the candidate object.
|
||||||
|
|
||||||
|
|
||||||
|
##### **candidateName:** *```string```*
|
||||||
|
Candidate name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```?CondorcetPHP\Condorcet\Candidate```)* Candidate object
|
||||||
|
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Election::getCandidatesList
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getCandidatesList ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Return a list of registered candidates for this election.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* List of candidates in an array.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::countCandidates](../Election%20Class/public%20Election--countCandidates.md)
|
@ -0,0 +1,21 @@
|
|||||||
|
## public Election::getCandidatesListAsString
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getCandidatesListAsString ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Return a list of registered candidates for this election.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* List of candidates in an array populated with strings instead of CandidateObjects.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::countCandidates](../Election%20Class/public%20Election--countCandidates.md)
|
@ -0,0 +1,27 @@
|
|||||||
|
## public Election::getChecksum
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getChecksum ( ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
SHA-2 256 checksum of following internal data:
|
||||||
|
* Candidates
|
||||||
|
* Votes list & tags
|
||||||
|
* Computed data (pairwise, algorithm cache, stats)
|
||||||
|
* Class version (major version like 0.14)
|
||||||
|
|
||||||
|
Can be powerfull to check integrity and security of an election. Or working with serialized object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* SHA-2 256 bits Hexadecimal
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Cryptographic Checksum](https://github.com/julien-boudry/Condorcet/wiki/III-%23-A.-Avanced-features---Configuration-%23-2.-Cryptographic-Checksum)**
|
@ -0,0 +1,29 @@
|
|||||||
|
## public Election::getCondorcetLoser
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getCondorcetLoser ( ): ?CondorcetPHP\Condorcet\Candidate
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the natural Condorcet loser if there is one.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```?CondorcetPHP\Condorcet\Candidate```)* Candidate object given. Null if there are no available loser.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getCondorcetWinner](../Election%20Class/public%20Election--getCondorcetWinner.md)
|
||||||
|
* [Election::getLoser](../Election%20Class/public%20Election--getLoser.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Natural Condorcet](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-1.-Natural-Condorcet)**
|
@ -0,0 +1,29 @@
|
|||||||
|
## public Election::getCondorcetWinner
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getCondorcetWinner ( ): ?CondorcetPHP\Condorcet\Candidate
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the natural Condorcet winner if there is one.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```?CondorcetPHP\Condorcet\Candidate```)* Candidate object given. Null if there are no available winner.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getCondorcetLoser](../Election%20Class/public%20Election--getCondorcetLoser.md)
|
||||||
|
* [Election::getWiner](../Election%20Class/public%20Election--getWiner.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Natural Condorcet](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-1.-Natural-Condorcet)**
|
@ -0,0 +1,29 @@
|
|||||||
|
## public Election::getConstraints
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getConstraints ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Get active constraints list.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* Array with class name of each active constraint. Empty array if there is not.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::clearConstraints](../Election%20Class/public%20Election--clearConstraints.md)
|
||||||
|
* [Election::addConstraints](../Election%20Class/public%20Election--addConstraints.md)
|
||||||
|
* [Election::testIfVoteIsValidUnderElectionConstraints](../Election%20Class/public%20Election--testIfVoteIsValidUnderElectionConstraints.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Vote Constraints](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-5.-Vote-Constraints)**
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Election::getExplicitPairwise
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getExplicitPairwise ( ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the Pairwise.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* Pairwise as an explicit array .
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getPairwise](../Election%20Class/public%20Election--getPairwise.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
@ -0,0 +1,27 @@
|
|||||||
|
## public Election::getGlobalTimer
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getGlobalTimer ( ): float
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the cumulated computation runtime of this object. Include only computation related methods.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```float```)* (Float) Timer
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getLastTimer](../Election%20Class/public%20Election--getLastTimer.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Timber benchmarking](https://github.com/julien-boudry/Condorcet/wiki/III-%23-A.-Avanced-features---Configuration-%23-1.-Timer-Benchmarking)**
|
@ -0,0 +1,23 @@
|
|||||||
|
## public Election::getImplicitRankingRule
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getImplicitRankingRule ( ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the corresponding setting as currently set (True by default).
|
||||||
|
If it is True then all votes expressing a partial ranking are understood as implicitly placing all the non-mentioned candidates exequos on a last rank.
|
||||||
|
If it is false, then the candidates not ranked, are not taken into account at all.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True / False
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::setImplicitRanking](../Election%20Class/public%20Election--setImplicitRanking.md)
|
@ -0,0 +1,27 @@
|
|||||||
|
## public Election::getLastTimer
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getLastTimer ( ): float
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the last computation runtime (typically after a getResult() call.). Include only computation related methods.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```float```)* (Float) Timer
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getGlobalTimer](../Election%20Class/public%20Election--getGlobalTimer.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Timber benchmarking](https://github.com/julien-boudry/Condorcet/wiki/III-%23-A.-Avanced-features---Configuration-%23-1.-Timer-Benchmarking)**
|
@ -0,0 +1,40 @@
|
|||||||
|
## public Election::getLoser
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getLoser ( [?string $method = null] ): CondorcetPHP\Condorcet\Candidate|array|null
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the natural Condorcet loser if there is one. Alternatively you can get the loser(s) from an advanced Condorcet algorithm.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```?string```*
|
||||||
|
*Only if not nulle:*
|
||||||
|
|
||||||
|
The loser will be provided by an advanced algorithm of an available advanced Condorcet method. For most of them, it will be the same as the Condorcet Marquis there. But if it does not exist, it may be different; and in some cases they may be multiple.
|
||||||
|
|
||||||
|
If null, Natural Condorcet algorithm will be use.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Candidate|array|null```)* Candidate object given. Null if there are no available winner or loser.
|
||||||
|
|
||||||
|
If you use an advanced method instead of Natural, you can get an array with multiples losers.
|
||||||
|
|
||||||
|
Throw an exception on error.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getWinner](../Election%20Class/public%20Election--getWinner.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Natural Condorcet](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-1.-Natural-Condorcet)**
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Election::getNumberOfSeats
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getNumberOfSeats ( ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Get number of Seats for STV methods.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Number of seats.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::setNumberOfSeats](../Election%20Class/public%20Election--setNumberOfSeats.md)
|
||||||
|
* [Result::getNumberOfSeats](../Result%20Class/public%20Result--getNumberOfSeats.md)
|
@ -0,0 +1,25 @@
|
|||||||
|
## public Election::getObjectVersion
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getObjectVersion ( [bool $major = false] ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Condorcet PHP version who built this Election object. Usefull pour serializing Election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **major:** *```bool```*
|
||||||
|
true will return : '2.0' and false will return : '2.0.0'.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Condorcet PHP version.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [static Condorcet::getVersion](../Condorcet%20Class/public%20static%20Condorcet--getVersion.md)
|
@ -0,0 +1,28 @@
|
|||||||
|
## public Election::getPairwise
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getPairwise ( ): CondorcetPHP\Condorcet\Algo\Pairwise
|
||||||
|
```
|
||||||
|
|
||||||
|
Return the Pairwise.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Algo\Pairwise```)* Pairwise object.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getExplicitPairwise](../Election%20Class/public%20Election--getExplicitPairwise.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Advanced Results](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-4.-Advanced-Results-Management)**
|
@ -0,0 +1,42 @@
|
|||||||
|
## public Election::getResult
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getResult ( [?string $method = null , array $methodOptions = []] ): CondorcetPHP\Condorcet\Result
|
||||||
|
```
|
||||||
|
|
||||||
|
Get a full ranking from an advanced Condorcet method.
|
||||||
|
*Have a look on the [supported method](https://github.com/julien-boudry/Condorcet/wiki/I-%23-Installation-%26-Basic-Configuration-%23-2.-Condorcet-Methods), or create [your own algorithm](https://github.com/julien-boudry/Condorcet/wiki/III-%23-C.-Extending-Condorcet-%23-1.-Add-your-own-ranking-algorithm).*
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```?string```*
|
||||||
|
Not required for use election default method. Set the string name of the algorithm for use of a specific one.
|
||||||
|
|
||||||
|
|
||||||
|
##### **methodOptions:** *```array```*
|
||||||
|
Array of option for some methods. Look at each method documentation.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Result```)* An Condorcet/Result Object (implementing ArrayAccess and Iterator, can be use like an array ordered by rank)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\AlgorithmException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getWinner](../Election%20Class/public%20Election--getWinner.md)
|
||||||
|
* [Condorcet::getDefaultMethod](../Condorcet%20Class/public%20Condorcet--getDefaultMethod.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Ranking from Condorcet Method](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-2.-Get-Ranking-from-Condorcet-advanced-Methods)**
|
@ -0,0 +1,23 @@
|
|||||||
|
## public Election::getState
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getState ( ): CondorcetPHP\Condorcet\ElectionProcess\ElectionState
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the election process level.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\ElectionProcess\ElectionState```)* ElectionState::CANDIDATES_REGISTRATION: Candidate registered state. No votes, no result, no cache.
|
||||||
|
ElectionState::VOTES_REGISTRATION: Voting registration phase. Pairwise cache can exist thanks to dynamic computation if voting phase continue after the first get result. But method result never exist.
|
||||||
|
3: Result phase: Some method result may exist, pairwise exist. An election will return to Phase 2 if votes are added or modified dynamically.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::setStateToVote](../Election%20Class/public%20Election--setStateToVote.md)
|
@ -0,0 +1,15 @@
|
|||||||
|
## public Election::getStatsVerbosity
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getStatsVerbosity ( ): CondorcetPHP\Condorcet\Algo\StatsVerbosity
|
||||||
|
```
|
||||||
|
|
||||||
|
The current level of stats verbosity for this election object. Look at Election->setStatsVerbosity method for more informations.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Algo\StatsVerbosity```)* The current verbosity level for this election object.
|
||||||
|
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Election::getTimerManager
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getTimerManager ( ): CondorcetPHP\Condorcet\Timer\Manager
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Timer manager object.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Timer\Manager```)* An CondorcetPHP\Condorcet\Timer\Manager object using by this election.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getGlobalTimer](../Election%20Class/public%20Election--getGlobalTimer.md)
|
||||||
|
* [Election::getLastTimer](../Election%20Class/public%20Election--getLastTimer.md)
|
@ -0,0 +1,30 @@
|
|||||||
|
## public Election::getVotesList
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getVotesList ( [array|string|null $tags = null , bool $with = true] ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Get registered vote list.
|
||||||
|
|
||||||
|
|
||||||
|
##### **tags:** *```array|string|null```*
|
||||||
|
Tags list as a string separated by commas or array.
|
||||||
|
|
||||||
|
|
||||||
|
##### **with:** *```bool```*
|
||||||
|
Get votes with these tags or without.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* Populated by each Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::countVotes](../Election%20Class/public%20Election--countVotes.md)
|
||||||
|
* [Election::getVotesListAsString](../Election%20Class/public%20Election--getVotesListAsString.md)
|
@ -0,0 +1,27 @@
|
|||||||
|
## public Election::getVotesListAsString
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getVotesListAsString ( [bool $withContext = true] ): string
|
||||||
|
```
|
||||||
|
|
||||||
|
Get registered vote list.
|
||||||
|
|
||||||
|
|
||||||
|
##### **withContext:** *```bool```*
|
||||||
|
Depending of the implicit ranking rule of the election, will complete or not the ranking. If $withContext is false, ranking are never adapted to the context.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```string```)* Return a string like :<br>
|
||||||
|
A > B > C * 3<br>
|
||||||
|
A = B > C * 6
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::parseVotes](../Election%20Class/public%20Election--parseVotes.md)
|
@ -0,0 +1,30 @@
|
|||||||
|
## public Election::getVotesListGenerator
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getVotesListGenerator ( [array|string|null $tags = null , bool $with = true] ): Generator
|
||||||
|
```
|
||||||
|
|
||||||
|
Same as Election::getVotesList. But Return a PHP generator object.
|
||||||
|
Usefull if your work on very large election with an external DataHandler, because it's will not using large memory amount.
|
||||||
|
|
||||||
|
|
||||||
|
##### **tags:** *```array|string|null```*
|
||||||
|
Tags list as a string separated by commas or array.
|
||||||
|
|
||||||
|
|
||||||
|
##### **with:** *```bool```*
|
||||||
|
Get votes with these tags or without.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```Generator```)* Populated by each Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getVotesList](../Election%20Class/public%20Election--getVotesList.md)
|
@ -0,0 +1,31 @@
|
|||||||
|
## public Election::getVotesValidUnderConstraintGenerator
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getVotesValidUnderConstraintGenerator ( [array|string|null $tags = null , bool $with = true] ): Generator
|
||||||
|
```
|
||||||
|
|
||||||
|
Same as Election::getVotesList. But Return a PHP generator object.
|
||||||
|
Usefull if your work on very large election with an external DataHandler, because it's will not using large memory amount.
|
||||||
|
|
||||||
|
|
||||||
|
##### **tags:** *```array|string|null```*
|
||||||
|
Tags list as a string separated by commas or array.
|
||||||
|
|
||||||
|
|
||||||
|
##### **with:** *```bool```*
|
||||||
|
Get votes with these tags or without.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```Generator```)* Populated by each Vote object.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getVotesListGenerator](../Election%20Class/public%20Election--getVotesListGenerator.md)
|
||||||
|
* [Election::getVotesList](../Election%20Class/public%20Election--getVotesList.md)
|
@ -0,0 +1,41 @@
|
|||||||
|
## public Election::getWinner
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->getWinner ( [?string $method = null] ): CondorcetPHP\Condorcet\Candidate|array|null
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the natural Condorcet winner if there is one. Alternatively you can get the winner(s) from an advanced Condorcet algorithm.
|
||||||
|
|
||||||
|
|
||||||
|
##### **method:** *```?string```*
|
||||||
|
*Only if not null: *
|
||||||
|
|
||||||
|
The winner will be provided by an advanced algorithm of an available advanced Condorcet method. For most of them, it will be the same as the Condorcet Marquis there. But if it does not exist, it may be different; and in some cases they may be multiple.
|
||||||
|
|
||||||
|
If null, Natural Condorcet algorithm will be use.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```CondorcetPHP\Condorcet\Candidate|array|null```)* Candidate object given. Null if there are no available winner or loser.
|
||||||
|
|
||||||
|
If you use an advanced method instead of Natural, you can get an array with multiples winners.
|
||||||
|
|
||||||
|
Throw an exception on error.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::getCondorcetWinner](../Election%20Class/public%20Election--getCondorcetWinner.md)
|
||||||
|
* [Election::getLoser](../Election%20Class/public%20Election--getLoser.md)
|
||||||
|
* [Election::getResult](../Election%20Class/public%20Election--getResult.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Natural Condorcet](https://github.com/julien-boudry/Condorcet/wiki/II-%23-C.-Result-%23-1.-Natural-Condorcet)**
|
@ -0,0 +1,30 @@
|
|||||||
|
## public Election::isRegisteredCandidate
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->isRegisteredCandidate ( CondorcetPHP\Condorcet\Candidate|string $candidate [, bool $strictMode = true] ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if a candidate is already taking part in the election.
|
||||||
|
|
||||||
|
|
||||||
|
##### **candidate:** *```CondorcetPHP\Condorcet\Candidate|string```*
|
||||||
|
Candidate object or candidate string name. String name works only if the strict mode is active.
|
||||||
|
|
||||||
|
|
||||||
|
##### **strictMode:** *```bool```*
|
||||||
|
Search comparison mode. In strict mode, candidate objects are compared strictly and a string input can't match anything.
|
||||||
|
If strict mode is false, the comparison will be based on name.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True / False
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addCandidate](../Election%20Class/public%20Election--addCandidate.md)
|
@ -0,0 +1,22 @@
|
|||||||
|
## public Election::isVoteWeightAllowed
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->isVoteWeightAllowed ( ): bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the corresponding setting as currently set (False by default).
|
||||||
|
If it is True then votes vote optionally can use weight otherwise (if false) all votes will be evaluated as equal for this election.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```bool```)* True / False
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::allowsVoteWeight](../Election%20Class/public%20Election--allowsVoteWeight.md)
|
@ -0,0 +1,43 @@
|
|||||||
|
## public Election::parseCandidates
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->parseCandidates ( string $input [, bool $isFile = false] ): array
|
||||||
|
```
|
||||||
|
|
||||||
|
Import candidate from a text source.
|
||||||
|
|
||||||
|
|
||||||
|
##### **input:** *```string```*
|
||||||
|
String or valid path to a text file.
|
||||||
|
|
||||||
|
|
||||||
|
##### **isFile:** *```bool```*
|
||||||
|
If true, the input is evaluated as path to a text file.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```array```)* List of newly registered candidate object. Count it for checking if all candidates have been correctly registered.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Throws:
|
||||||
|
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\CandidateExistsException```
|
||||||
|
* ```CondorcetPHP\Condorcet\Throwable\VoteMaxNumberReachedException```
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addCandidate](../Election%20Class/public%20Election--addCandidate.md)
|
||||||
|
* [Election::addCandidatesFromJson](../Election%20Class/public%20Election--addCandidatesFromJson.md)
|
||||||
|
* [Election::parseVotes](../Election%20Class/public%20Election--parseVotes.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Manage Candidates](https://github.com/julien-boudry/Condorcet/wiki/II-%23-A.-Create-an-Election-%23-2.-Create-Candidates)**
|
@ -0,0 +1,38 @@
|
|||||||
|
## public Election::parseVotes
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
```php
|
||||||
|
public Election->parseVotes ( string $input [, bool $isFile = false] ): int
|
||||||
|
```
|
||||||
|
|
||||||
|
Import votes from a text source. If any invalid vote is found inside, nothing are registered.
|
||||||
|
|
||||||
|
|
||||||
|
##### **input:** *```string```*
|
||||||
|
String or valid path to a text file.
|
||||||
|
|
||||||
|
|
||||||
|
##### **isFile:** *```bool```*
|
||||||
|
If true, the input is evalatued as path to text file.
|
||||||
|
|
||||||
|
|
||||||
|
### Return value:
|
||||||
|
|
||||||
|
*(```int```)* Count of the new registered vote.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Related method(s)
|
||||||
|
|
||||||
|
* [Election::addVote](../Election%20Class/public%20Election--addVote.md)
|
||||||
|
* [Election::parseCandidates](../Election%20Class/public%20Election--parseCandidates.md)
|
||||||
|
* [Election::parseVotesWithoutFail](../Election%20Class/public%20Election--parseVotesWithoutFail.md)
|
||||||
|
* [Election::addVotesFromJson](../Election%20Class/public%20Election--addVotesFromJson.md)
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
### Examples and explanation
|
||||||
|
|
||||||
|
* **[Manual - Add Vote](https://github.com/julien-boudry/Condorcet/wiki/II-%23-B.-Vote-management-%23-1.-Add-Vote)**
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user