#!/usr/bin/perl -w

# results in this script are not normalized yet.

use strict;

my @partyfullname= qw(PvdA VVD CDA D66 GroenLinks ChristenUnie SP SGP Leefbaar fortuyn);
my @party= qw(PvdA VVD CDA D66 GL Christ SP SGP Leef LPF);

my @soortissue= ( "Criminaliteit en veiligheid", "Ethische kwesties", "Democratie", "Migranten",
   "Sociaal-economisch beleid", "Sociale zekerheid en zorg", "Wonen", "Verkeer en milieu",
   "Onderwijs, sport en cultuur", "Financi?n en belastingen", "Internationale betrekkingen en Defensie");

my @mening= qw(oneens neutraal eens);

my @program= (
	{
		category=>0, issue=> "Er moet een algemene legitimatieplicht komen.",
		scores=>[-1, 1, 1, -1, -1, 1, -1, 1, 1, 1,],
	},
	{
		category=>0, issue=> "Het inzetten van cameratoezicht in winkel- en uitgaanscentra  moet niet verder worden doorgevoerd.",
		scores=>[-1, -1, -1, 0, 1, -1, -1, -1, 0, -1,],
	},
	{
		category=>0, issue=> "Criminelen die in herhaling vallen (recidivisten), moeten zwaarder worden gestraft.",
		scores=>[1, 1, 1, 0, -1, 1, 1, 1, 1, 1,],
	},
	{
		category=>1, issue=> "Euthanasie moet weer volledig strafbaar worden gesteld.",
		scores=>[-1, -1, 0, -1, -1, 1, -1, 1, -1, -1,],
	},
	{
		category=>1, issue=> "Voor mensen die geen andere uitweg zien, moet een zelfdodingspil (\'pil van Drion\') tot de mogelijkheden behoren.",
		scores=>[-1, -1, -1, 1, -1, -1, -1, -1, 0, -1,],
	},
	{
		category=>1, issue=> "Genetische manipulatie van voedsel moet worden verboden.",
		scores=>[-1, -1, 0, -1, 1, 1, 1, 1, -1, 0,],
	},
	{
		category=>2, issue=> "De minister-president moet rechtstreeks door de burgers worden gekozen.",
		scores=>[-1, -1, -1, 1, -1, -1, -1, -1, 1, 1,],
	},
	{
		category=>2, issue=> "Het moet mogelijk worden een bindend referendum te houden over een voorstel vanuit de bevolking (volksinitiatief).",
		scores=>[1, -1, -1, 1, 1, -1, 1, -1, 1, 1,],
	},
	{
		category=>3, issue=> "Buitenlanders die langer dan drie jaar in Nederland wonen moeten algemeen kiesrecht krijgen, dus ook voor de Tweede-Kamerverkiezingen.",
		scores=>[0, -1, -1, -1, 1, -1, -1, -1, -1, -1,],
	},
	{
		category=>3, issue=> "Asielzoekers die langer dan anderhalf jaar op een beslissing moeten wachten, krijgen automatisch een verblijfsvergunning.",
		scores=>[-1, -1, -1, -1, 1, -1, -1, -1, -1, -1,],
	},
	{
		category=>4, issue=> "Voor oudere werknemers in WW of bijstand gaat weer de sollicitatieplicht gelden.",
		scores=>[-1, 1, -1, 1, -1, 1, -1, -1, 1, 1,],
	},
	{
		category=>4, issue=> "Om grote inkomensverschillen tegen te gaan, moeten niet alleen de salarissen van \'gewone\' werknemers maar ook die van managers in een CAO worden ondergebracht.",
		scores=>[0, -1, -1, 0, 1, 1, 1, -1, -1, -1,],
	},
	{
		category=>4, issue=> "Winkels dienen op zondag gesloten te zijn.",
		scores=>[-1, -1, -1, -1, -1, 1, 0, 1, -1, 0,],
	},
	{
		category=>5, issue=> "Alleen werknemers die voor 50% of meer arbeidsongeschikt zijn, krijgen voortaan een WAO-uitkering.",
		scores=>[-1, 1, -1, -1, -1, -1, -1, -1, -1, 1,],
	},
	{
		category=>5, issue=> "De verzekeringspremie voor ziektekosten moet geheel naar draagkracht worden geheven.",
		scores=>[-1, -1, -1, -1, 1, 1, 1, -1, -1, -1,],
	},
	{
		category=>5, issue=> "Extra financiering van de gezondheidszorg is niet nodig, een efficiëntere besteding van de beschikbare gelden is voldoende om problemen als wachtlijsten op te lossen.",
		scores=>[-1, 0, -1, -1, -1, -1, -1, -1, 1, 1,],
	},
	{
		category=>6, issue=> "De aftrek van hypotheekrente voor het eerste huis moet volledig gehandhaafd blijven.",
		scores=>[1, 1, 1, 1, -1, -1, -1, -1, 1, 1,],
	},
	{
		category=>6, issue=> "De Onroerend Zaak Belasting (OZB), de gemeentelijke belasting op huisvesting, moet worden afgeschaft.",
		scores=>[-1, 1, -1, 0, -1, -1, -1, -1, 0, -1,],
	},
	{
		category=>7, issue=> "Onder de Waddenzee mogen geen proefboringen naar olie of gas meer plaatsvinden.",
		scores=>[1, -1, 1, 1, 1, 1, 1, -1, 1, 0,],
	},
	{
		category=>7, issue=> "Knelpunten in het wegennet moeten met spoed worden aangepakt, onder andere door het verbreden van wegen.",
		scores=>[1, 1, 1, 0, -1, -1, 0, -1, 1, 1,],
	},
	{
		category=>7, issue=> "De aanleg van de Betuwelijn moet worden gestaakt.",
		scores=>[-1, -1, -1, -1, 1, 1, 1, 0, 1, 1,],
	},
	{
		category=>7, issue=> "De toepassing van kernenergie moet mogelijk blijven.",
		scores=>[-1, 1, 1, -1, -1, -1, -1, 1, -1, 0,],
	},
	{
		category=>8, issue=> "Professionele sport moet niet langer worden gesubsidieerd.",
		scores=>[-1, -1, -1, -1, -1, 1, -1, 1, -1, 1,],
	},
	{
		category=>8, issue=> "De publieke omroep moet een beperktere taak krijgen.",
		scores=>[-1, 1, -1, 0, -1, -1, -1, -1, -1, 0,],
	},
	{
		category=>8, issue=> "Scholen moeten worden bestuurd door ouders en leerkrachten, in het voortgezet onderwijs ook door leerlingen.",
		scores=>[0, -1, -1, 1, -1, -1, 1, -1, 1, 1,],
	},
	{
		category=>9, issue=> "Het aflossen van de staatsschuld heeft prioriteit boven meer geld voor gezondheidszorg en onderwijs.",
		scores=>[0, 1, 0, -1, -1, -1, -1, -1, 1, 1,],
	},
	{
		category=>9, issue=> "Het hoogste tarief van de inkomstenbelasting moet worden verlaagd.",
		scores=>[-1, 1, 0, 0, -1, -1, -1, 1, 1, 0,],
	},
	{
		category=>10, issue=> "Nederland moet kiezen voor een federaal Europa, met een Europese grondwet en een Europese regering die verantwoording schuldig is aan het Europees Parlement.",
		scores=>[0, -1, -1, 1, 1, -1, -1, -1, -1, -1,],
	},
	{
		category=>10, issue=> "De Nederlandse krijgsmacht moet zich meer richten op vredesoperaties dan op verdediging van de landsgrenzen. ",
		scores=>[1, 0, 0, 0, 1, 1, 0, -1, 1, -1,],
	},
	{
		category=>10, issue=> "De eis aan ontwikkelingslanden om de ontvangen hulp bij het Nederlandse bedrijfsleven te besteden, moet worden afgeschaft.",
		scores=>[1, -1, 0, 1, 1, 1, 1, 0, 1, -1,],
	},
);


print "<HR>euclidian<BR>\n";
writeTable(\&euclidianDistance);

print "<HR>cityblock<BR>\n";
writeTable(\&cityblockDistance);

print "<HR>pmcorrelation<BR>\n";
writeTable(\&pmcorrelation);

exit(0);

#xw' = weight*userchoice
#y' = partychoice

#  correlatie methods:
#0 = pm-correlation
#1 = euclidian
#2 = cityblock

#0: z= ( n*sum(xw*y)-sum(xw)*sum(y) ) / ( ( n*sum(xw^2)-sum(xw)^2 ) * ( n*sum(y^2)-sum(y)^2 ) )
#1: max= sqrt(sum((1+weight)^2))   z=sqrt(sum( (xw-y)^2 ))
#2: max= sum(1+weight)             z=sum(abs(xw-y))

#normalize:  (max-z)/max*2-1

sub getScoreVector {
    my $party= shift;

    return map { $program[$_]->{scores}[$party] } ( 0..$#program );
}

sub pmcorrelation {
    my ($vec1, $vec2) = @_;

    my $n= $#$vec1 + 1;

    my $dist= 0;
    my $sumxy=0;
    my $sumx=0;
    my $sumx2=0;
    my $sumy=0;
    my $sumy2=0;
    my $nsummed= 0;
    for my $i (0..$n-1) {
        my $x= $vec1->[$i];
        my $y= $vec2->[$i];

        if (defined $x && defined $y) {
            $sumxy += $x*$y;
            $sumx += $x; $sumx2 += $x**2;
            $sumy += $y; $sumy2 += $y**2;

            $nsummed++;
        }
    }

    return ( $nsummed*$sumxy-$sumx*$sumy ) / sqrt( ($nsummed*$sumx2-$sumx**2) * ($nsummed*$sumy2-$sumy**2) );
}

#todo: in the original the result is divided by sum(weights)
#    here I divide by n
sub euclidianDistance {
    my ($vec1, $vec2) = @_;

    my $n= $#$vec1 + 1;

    my $dist= 0;
    my $nsummed= 0;
    for my $i (0..$n-1) {
        my $x= $vec1->[$i];
        my $y= $vec2->[$i];

        if (defined $x && defined $y) {
            $dist += sqrt( ($x-$y)**2 );
            $nsummed++;
        }
    }

    return $dist/sqrt($nsummed);
}

#todo: in the original the result is divided by sum(weights)
#    here I divide by n
sub cityblockDistance {
    my ($vec1, $vec2) = @_;

    my $n= $#$vec1 + 1;

    my $dist= 0;
    my $nsummed= 0;
    for my $i (0..$n-1) {
        my $x= $vec1->[$i];
        my $y= $vec2->[$i];

        if (defined $x && defined $y) {
            $dist += abs( $x-$y );
            $nsummed++;
        }
    }

    return $dist/$nsummed;
}


sub writeTable {
    my $distfunc= shift;

    print "<TABLE cellpadding=0 cellspacing=0 border=1>";
    print "<TR><TD></TD>";
    for my $x (0..$#party) {
        print "<TH>$party[$x]</TH>";
    }
    print "</TR>\n";
    for my $y (0..$#party) {

        my @yparty= getScoreVector($y);
        print "<TR><TH>$party[$y]</TH>";
        for my $x (0..$#party) {
            my @xparty= getScoreVector($x);
            my $dist= $distfunc->(\@xparty, \@yparty);

	    
            printf("<TD>%6.2f</TD>", $dist);

        }
        print "</TR>\n";
    }
    print "</TABLE>";
}
