Skip to content

Commit

Permalink
Optimize pairwise strengths computation (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
janos committed Jan 17, 2023
1 parent 44f33e0 commit 00daf99
Showing 1 changed file with 40 additions and 30 deletions.
70 changes: 40 additions & 30 deletions schulze.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package schulze
import (
"fmt"
"sort"
"unsafe"
)

// NewPreferences initializes a fixed size slice that stores all pairwise
Expand Down Expand Up @@ -166,45 +167,56 @@ func ballotRanks[C comparable](choices []C, b Ballot[C]) (ranks [][]choiceIndex,
return ranks, choicesLen, nil
}

func calculatePairwiseStrengths[C comparable](choices []C, preferences []int) []strength {
choicesCount := len(choices)
const intSize = unsafe.Sizeof(int(0))

strengths := make([]strength, choicesCount*choicesCount)
func calculatePairwiseStrengths[C comparable](choices []C, preferences []int) []int {
choicesCount := uintptr(len(choices))

for i := 0; i < choicesCount; i++ {
for j := 0; j < choicesCount; j++ {
if i != j {
c := preferences[i*choicesCount+j]
if c > preferences[j*choicesCount+i] {
strengths[i*choicesCount+j] = strength(c)
}
if choicesCount == 0 {
return nil
}

strengths := make([]int, choicesCount*choicesCount)

strengthsPtr := unsafe.Pointer(&strengths[0])

for i := uintptr(0); i < choicesCount; i++ {
for j := uintptr(0); j < choicesCount; j++ {
// removed unnecessary check for optimization: if i == j { continue }
ij := i*choicesCount + j
ji := j*choicesCount + i
c := preferences[ij]
if c > preferences[ji] {
*(*int)(unsafe.Add(strengthsPtr, ij*intSize)) = c
}
}
}

for i := 0; i < choicesCount; i++ {
for j := 0; j < choicesCount; j++ {
if i != j {
for k := 0; k < choicesCount; k++ {
if (i != k) && (j != k) {
jk := j*choicesCount + k
strengths[jk] = max(
strengths[jk],
min(
strengths[j*choicesCount+i],
strengths[i*choicesCount+k],
),
)
}
}
for i := uintptr(0); i < choicesCount; i++ {
for j := uintptr(0); j < choicesCount; j++ {
// removed unnecessary check for optimization: if i == j { continue }
for k := uintptr(0); k < choicesCount; k++ {
// removed unnecessary check for optimization: if i == k || j == k { continue }
jk := j*choicesCount + k
ji := j*choicesCount + i
ik := i*choicesCount + k
jkp := (*int)(unsafe.Add(strengthsPtr, jk*intSize))
m := max(
*jkp,
min(
*(*int)(unsafe.Add(strengthsPtr, ji*intSize)),
*(*int)(unsafe.Add(strengthsPtr, ik*intSize)),
),
)
*(jkp) = m
}
}
}

return strengths
}

func calculateResults[C comparable](choices []C, strengths []strength) (results []Result[C], tie bool) {
func calculateResults[C comparable](choices []C, strengths []int) (results []Result[C], tie bool) {
choicesCount := len(choices)
results = make([]Result[C], 0, choicesCount)

Expand Down Expand Up @@ -236,16 +248,14 @@ func calculateResults[C comparable](choices []C, strengths []strength) (results
return results, tie
}

type strength int

func min(a, b strength) strength {
func min(a, b int) int {
if a < b {
return a
}
return b
}

func max(a, b strength) strength {
func max(a, b int) int {
if a > b {
return a
}
Expand Down

0 comments on commit 00daf99

Please sign in to comment.