diff --git a/agt/ballotagent/new_ballot.go b/agt/ballotagent/new_ballot.go index e0121b2a7c47f00407789e8298af578fa39b32b5..ecaa4f0d0587e0ad535407236489cbdf9cd94e34 100644 --- a/agt/ballotagent/new_ballot.go +++ b/agt/ballotagent/new_ballot.go @@ -77,6 +77,10 @@ func (rsa *BallotServerAgent) createBallot(w http.ResponseWriter, r *http.Reques go rsa.handleBallot(resp, cs.BordaSWF, cs.BordaSCF, tb, deadline) case "approval": go rsa.handleBallotWithSingleOption(resp, cs.ApprovalSWF, cs.ApprovalSCF, tb, deadline) + case "copeland": + go rsa.handleBallot(resp, cs.CopelandSWF, cs.CopelandSCF, tb, deadline) + case "stv": + go rsa.handleBallot(resp, cs.STV_SWF, cs.STV_SCF, tb, deadline) default: w.WriteHeader(http.StatusNotImplemented) msg := fmt.Sprintf("Unkonwn rule '%s'", req.Rule) diff --git a/comsoc/Copeland.go b/comsoc/Copeland.go index 7076a9b4de20578f2bfe7749ab88012274203de2..b99c415fc71cc8b77a72829f580366024ce58b9d 100644 --- a/comsoc/Copeland.go +++ b/comsoc/Copeland.go @@ -1 +1,41 @@ -package comsoc \ No newline at end of file +package comsoc + +func CopelandSWF(p Profile) (count Count, err error) { + count = make(Count) + alts := make([]Alternative, 0) + for i := 1; i <= len(p[0]); i++ { + alts = append(alts, Alternative(i)) + } + err = checkProfileAlternative(p, alts) + if err != nil { + return nil, err + } + for alt1 := 1; alt1 <= len(alts); alt1++ { + for alt2 := alt1 + 1; alt2 <= len(alts); alt2++ { + score1, score2 := 0, 0 + for _, pref := range p { + if isPref(Alternative(alt1), Alternative(alt2), pref) { + score1++ + } else { + score2++ + } + } + if score1 > score2 { + count[Alternative(alt1)]++ + count[Alternative(alt2)]-- + } else if score2 > score1 { + count[Alternative(alt1)]-- + count[Alternative(alt2)]++ + } + } + } + return +} + +func CopelandSCF(p Profile) (bestAlts []Alternative, err error) { + count, err := CopelandSWF(p) + if err != nil { + return nil, err + } + return maxCount(count), err +} diff --git a/comsoc/STV.go b/comsoc/STV.go index 7076a9b4de20578f2bfe7749ab88012274203de2..0416ec0a962ed6876ee16f554d1fb084379c04c1 100644 --- a/comsoc/STV.go +++ b/comsoc/STV.go @@ -1 +1,77 @@ -package comsoc \ No newline at end of file +package comsoc + +func getRandomKey(count Count) Alternative { + for k := range count { + return k + } + return 0 // should never happen +} + +func countContains(count Count, alt Alternative) bool { + for k := range count { + if alt == k { + return true + } + } + return false +} + +// renvoie une des pires alternatives pour un décompte donné +func minCount(count Count, alts []Alternative) (worstAlt Alternative) { + for _, alt := range alts { + if !countContains(count, alt) { + return alt + } + } + worstAlt = getRandomKey(count) + minPoints := count[worstAlt] + for i, points := range count { + if points < minPoints { + worstAlt = i + minPoints = points + } + } + return worstAlt +} + +func STV_SWF(p Profile) (count Count, err error) { + count = make(Count) + alts := make([]Alternative, 0) + for i := 1; i <= len(p[0]); i++ { + alts = append(alts, Alternative(i)) + } + err = checkProfileAlternative(p, alts) + if err != nil { + return nil, err + } + + nbRounds := len(alts) + for round := 0; round < nbRounds; round++ { + majorityRes := make(Count) + for _, pref := range p { + majorityRes[pref[0]]++ + } + worstAlt := minCount(majorityRes, alts) + count[worstAlt] = round + + // On enlève la pire alt des alts + alts[rank(worstAlt, alts)] = alts[len(alts)-1] + alts = alts[:len(alts)-1] + + // on enlève la pire alt de chacunes des preferences + for i, pref := range p { + pref[rank(worstAlt, pref)] = pref[len(pref)-1] + pref = pref[:len(pref)-1] + p[i] = pref + } + } + return +} + +func STV_SCF(p Profile) (bestAlts []Alternative, err error) { + count, err := STV_SWF(p) + if err != nil { + return nil, err + } + return maxCount(count), err +}