Closed julien-boudry closed 1 year ago
Thank you. I wish I noticed this before I made my most recent commits. I don't know how to integrate these changes in a way that shows your contribution in the history.
Don't worry about that ;)
Well, I just made the commits. I've been having a good experience with PHP, but I find this a very bizarre design choice.
I must have done something wrong. It now ends in a 26-way tie.
Well, I just made the commits. I've been having a good experience with PHP, but I find this a very bizarre design choice.
** is a relatively new operator is PHP. Before, It's was only the pow() function (like other language).
Python uses exactly the same operators than PHP here, for both ^ and **. C++ and Rust use ^ in the same way that PHP does (but doesn't seem to have an exponent operator ?) But the new Julia language use ^ for exponent. PHP is relatively conservative here.
I must have done something wrong. It now ends in a 26-way tie.
Made this test: _(here we doing echo and vardump, but we could use a real interactive debugger)
var_dump($nationalMargins);
var_dump(array_sum($nationalMargins));
return array_sum($nationalMargins);
The array_sum is always equal to float(NAN)
The national margin looks like that:
array(38) {
["ALB"]=>
float(305.31773749766074)
["ARM"]=>
float(0)
["AUS"]=>
float(0)
["AUT"]=>
float(568.4815241989093)
["AZE"]=>
float(NAN)
["BEL"]=>
float(637.6405308542155)
["CHE"]=>
float(NAN)
["CYP"]=>
float(190.57487934296086)
["CZE"]=>
float(876.8844445555251)
["DEU"]=>
float(NAN)
["DNK"]=>
float(NAN)
["ESP"]=>
float(2051.6521502635132)
["EST"]=>
float(NAN)
["FIN"]=>
float(NAN)
["FRA"]=>
float(2405.1677042702613)
["GBR"]=>
float(NAN)
["GEO"]=>
float(492.3124763845493)
["GRC"]=>
float(606.183009567419)
["HRV"]=>
float(0)
["IRL"]=>
float(410.1073504344644)
["ISL"]=>
float(NAN)
["ISR"]=>
float(687.7629335222447)
["ITA"]=>
float(1580.9659444864128)
["LTU"]=>
float(NAN)
["LVA"]=>
float(235.19067669207067)
["MDA"]=>
float(282.8879052617626)
["MLT"]=>
float(0)
["NLD"]=>
float(NAN)
["NOR"]=>
float(NAN)
["POL"]=>
float(NAN)
["PRT"]=>
float(NAN)
["ROU"]=>
float(NAN)
["SMR"]=>
float(NAN)
["SRB"]=>
float(0)
["SVN"]=>
float(NAN)
["SWE"]=>
float(NAN)
["UKR"]=>
float(NAN)
["WLD"]=>
float(10914.278247252607)
}
You must find out why NAN is from your formula. And it looks spicy! If needed (better is to use it only if no choice), Condorcet includes brick/maths as a dependency.
As I understand it, using a fractional exponent is a strange thing. PHP accepts it, but the results can be strange, with a lot of Nan. ( https://www.php.net/manual/fr/function.is-nan.php#62504 )
I try same computation in other languages:
Python:
(-15 * 1897426) ** (1/3)
>>> (152.6588687488304+264.41291689896286j)
Julia
julia> (-15 * 1897426) ^ (1/3)
ERROR: DomainError with -2.846139e7:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
Stacktrace:
[1] throw_exp_domainerror(x::Float64)
@ Base.Math ./math.jl:37
[2] ^(x::Float64, y::Float64)
@ Base.Math ./math.jl:1123
[3] ^(x::Int64, y::Float64)
@ Base ./promotion.jl:444
[4] top-level scope
@ REPL[2]:1
Javascript (hard to say it: but same as PHP)
(-15 * 1897426) ** (1/3)
>>> NaN
Rust
use num::pow;
fn main() {
let x = pow(-15 * 1897426, 1/3);
println!("x = {}", x);
}
>>> x = 1
// Found that from doc: Note that 0⁰ (pow(0, 0)) returns 1. Mathematically this is undefined.
Ruby
(-15 * 1897426) ** (1/3)
=> 1
Perl:
print ( (-15 * 1897426) ** (1/3) );
=> NaN
C:
#include <stdio.h>
#include <math.h>
int main()
{
double r;
r = pow(-15 * 1897426, 1/3);
printf("%.2lf", r);
}
=> 1
Also, brick/math library doesn't accept float as an exponent, only int, so it raises an error if you try to exponent by 1/3.
So should be a math problem more than a code problem.
Here's a test I tried.
<?php
echo("\n5^(1/2)=". 5**(1/2));
echo("\n8^(2/3)=". 8**(2/3));
echo("\n-8^(2/3)=". (-8)**(2/3));
echo("\n-8^(1/3)=". (-8)**(1/3));
Output:
5^(1/2)=2.2360679774998
8^(2/3)=4
-8^(2/3)=NAN
-8^(1/3)=NAN
It seems like it just doesn't like doing exponentiation on negative numbers.
Here's two lines that I might commit in EurovisionSchulze.php. It solves the problem of PHP not liking exponentiation of negative numbers.
$filteredMargin = $this->filteredPairwise[$country][$iCountry]['win'][$jCountry]-$this->filteredPairwise[$country][$jCountry]['win'][$iCountry];
$nationalMargins[$country] = ($filteredMargin<=>0)*(abs($filteredMargin) * $contest->populations[$country] )**(1/3);
But here are the end results of some-votes.cvotes using this line:
"FIN > ISR = SWE > UKR > NOR > ITA > ARM > ALB > HRV > BEL = FRA > ESP = MDA > CZE > POL > CHE = EST > AUS = CYP > AUT = LTU > SVN > PRT > SRB > GBR > DEU"
I find it hard to believe that there would be any ties if the program is working properly. I can see significant margins between the countries that are supposedly tied.
Not a PHP problem, as shown above, all the languages have problems. Rust, Ruby, and C give an absurd result because math is 'undefined', but probably faster for CPU. Python gives incomplete results (that I don't understand). Julia tells us to use complex maths types instead. Perl, Javascript, and PHP give NaN.
Yes, I agree that ties are unlikely. Maybe could you compare this result with the original Schulze method. Then do math step by steps. For that, you can also remove the getStats method for your call. The original will give you the strongest paths $result->getStats();
.
I tried an experiment with all countries populations set to 5000. I also got it to output Schulze Margins at the end. Here are the results from some-votes.cvotes
:
Results from the first method:
string(153) "FIN > SWE > ISR > NOR > ITA > UKR > BEL = HRV > CZE > ARM > FRA > POL > MDA > EST > CHE > CYP > ALB > AUS = LTU > SVN > AUT = ESP > PRT > SRB > GBR > DEU"
Results from the second method:
string(153) "FIN > SWE > ISR > NOR > ITA > UKR > BEL = HRV > CZE > ARM > FRA > POL > MDA > EST > CHE > CYP > ALB > AUS = LTU > SVN > AUT = ESP > PRT > SRB > GBR > DEU"
Results from the regular Schulze Method:
string(153) "FIN > SWE > ISR > NOR > ITA > UKR > HRV > BEL > ARM > MDA > CZE > ALB > CHE = FRA > CYP > EST > POL > LTU > AUS > SVN > ESP > AUT > PRT > SRB > GBR > DEU"
So there was only one tie in Schulze Margin.
Edit: There was a mistake in the code. The 'second method' is just a repeat of 'Eurovision Schulze'.
When I try to run your project, I was curious about this error:
Having a warning is not a good sign (and can also slower things).
But behind this warning, I found that:
^ is a bitwise operator in PHP, NOT an arithmetic operator. https://www.php.net/manual/en/language.operators.bitwise.php
The one you looking for seems to be the ** operator. https://www.php.net/manual/en/language.operators.arithmetic.php
Probably the confusion comes from.