Skip to content

Commit

Permalink
explicit maximum number of iterations for alternate scaling algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
polettif committed Apr 2, 2024
1 parent e6d1d24 commit 16eb907
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 6 deletions.
11 changes: 8 additions & 3 deletions R/biproportional.R
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,12 @@ find_matrix_divisors = function(M, seats_cols, seats_rows, round_func) {
which.max(x)
}

while(!all(c(mc(M,dC,dR) == seats_cols, mr(M,dC,dR) == seats_rows))) {
# usually less than 20 iterations are needed
max_iter = getOption("proporz_max_iterations", 1000)
for(i in seq_len(max_iter)) {
if(all(c(mc(M,dC,dR) == seats_cols, mr(M,dC,dR) == seats_rows))) {
return(list(cols = dC, rows = dR))
}
# change party divisors
row_decr = which.min0(mr(M,dC,dR) - seats_rows)
if(length(row_decr) == 1) {
Expand Down Expand Up @@ -506,8 +511,8 @@ find_matrix_divisors = function(M, seats_cols, seats_rows, round_func) {
seats_cols[col_incr], round_func)
}
}

return(list(cols = dC, rows = dR))
stop("Result is undefined, exceeded maximum number of iterations (", max_iter, ")",
call. = FALSE)
}

#' Find divisor to assign seats
Expand Down
6 changes: 3 additions & 3 deletions R/utils.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
bisect = function(f, x1, x2, tol = 1e-9) {
bisect = function(f, x1, x2, tol = 1e-9, max_iterations = 1000) {
stopifnot(length(x1) == 1, length(x2) == 1, length(tol) == 1, x1 < x2)
stopifnot((f(x1) <= 0 && f(x2) >= 0) || (f(x1) >= 0 && f(x2) <= 0))
stopifnot(!is.infinite(x1), !is.infinite(x2))
stopifnot(!is.nan(x1), !is.nan(x2))
stopifnot(x1 >= 0, x2 >= 0)

for(i in 1:1e6) {
for(i in seq_len(max_iterations)) {
x <- (x1 + x2)/2
if(f(x) == 0 || (x2-x1) < tol) {
return(x)
Expand All @@ -16,7 +16,7 @@ bisect = function(f, x1, x2, tol = 1e-9) {
x2 <- x
}
}
stop("Exceeded maximum number of iterations (1e6)") # nocov
stop("Exceeded maximum number of iterations (", max_iterations, ")") # nocov
}

#' Pivot long data.frame to wide matrix and vice versa
Expand Down
4 changes: 4 additions & 0 deletions tests/testthat/test-biproportional.R
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ test_that("undefined result biproportional", {
expect_error_fixed(biproporz(uri2020$votes_matrix, uri2020$seats_vector, quorum_any(any_district = 0.7)),
"Result is undefined, equal quotient for parties: 'CVP', 'SPGB', 'FDP', 'SVP'")

vm5 = matrix(c(10, 10, 10, 10), 2, 2)
expect_error_fixed(biproporz(vm5, c(3,1)),
"Result is undefined, exceeded maximum number of iterations")

# manual fix (actual implementation depends on rules)
vm4 <- vm6 <- vm
vm4[4,1] <- vm4[4,1]+1
Expand Down

0 comments on commit 16eb907

Please sign in to comment.