Your EfficientFactorList function does a good job of effectively capturing the set of all factors for each number from 1 to n, so all that remains is a set of all factorizations. As you think, using factorization of smaller values ββto calculate factorization for larger values ββseems to be effective.
Consider the number k with coefficients k_1, k_2, ..., k_n. A naive approach would be to combine the factorizations k / k_1, k / k_2, ..., k / k_n by adding k_i to each factorization k / k_i to obtain the factorization k. As a processed example, we consider the calculation of factorizations 16 (which has non-trivial coefficients 2, 4, and 8). 2 has the factorization {2}, 4 has the factorization {4, 2 * 2}, and 8 has the factorization {8, 4 * 2, 2 * 2 * 2}, so we calculated the complete set of factorization by the first calculation {2 * 8, 4 * 4, 2 * 2 * 4, 8 * 2, 4 * 2 * 2, 2 * 2 * 2 * 2}, and then, taking unique factorizations, {8 * 2, 4 * 4, 4 * 2 * 2, 2 * 2 * 2 * 2}. Appendix 16 gives the final answer.
A more efficient approach is to note that we do not need to add k_i to all factorizations of k / k_i. For example, we did not need to add 2 * 2 * 4 from factorization 4, because it is already included from factorization 8. Similarly, we did not need to add 2 * 8 * from factorization 4, because it is already included from factorization 8. In the general case we need to enable factorization from k / k_i if all the values ββin the factorization are k_i or more.
In code:
library(gmp) all.fact <- function(n) { facts <- EfficientFactorList(n) facts[[1]] <- list(1) for (x in 2:n) { if (length(facts[[x]]) == 2) { facts[[x]] <- list(x) # Prime number } else { x.facts <- facts[[x]][facts[[x]] != 1 & facts[[x]] <= (x^0.5+0.001)] allSmaller <- lapply(x.facts, function(pf) lapply(facts[[x/pf]], function(y) { if (all(y >= pf)) { return(c(pf, y)) } else { return(NULL) } })) allSmaller <- do.call(c, allSmaller) facts[[x]] <- c(x, allSmaller[!sapply(allSmaller, function(y) is.null(y))]) } } return(facts) }
This is much faster than the published code:
system.time(f1 <- FactorRepresentations(10000)) # user system elapsed # 13.470 0.159 13.765 system.time(f2 <- all.fact(10000)) # user system elapsed # 1.602 0.028 1.641
As a health check, it also returns the same number of factorizations for each number:
lf1 <- sapply(f1, length) lf2 <- sapply(f2, length) all.equal(lf1, lf2)