In this post, I asked a question regarding how to create a matrix of integers where elements in each row satisfy a particular property.
The notation in the original post is a bit cumbersome so I will try to explain the question in a nutshell. I have a vector of integers cvec
, which has length l-1
, and I enumerate all the possibilities in a matrix such that every integer in each of the l
columns is less than or equal to cvec[1]
(first three lines of code). Then I iteratively reduce that large set possibilities into a smaller matrix, such that for a given row:
- Consecutive elements taken 2,3,...l-1 at a time must be no larger than
cvec[2]
,cvec[3]
, ...,cvec[l-1]
, respectively - The total sum of the
l
elements is equal tox
.
By first subsetting mat
to only those rows with sum x
, and then running the nested for loops, I've been able to reduce the runtime by over 1/10th. For the above example, it now runs 7.8 seconds
. However, I still think this could be faster if I somehow eliminate the nested loops. Any suggestions?
valid.counts2 <- function(x,l,cvec){
#l>1
vec = seq(from=0,to=cvec[1])
lst = lapply(numeric(l), function(i) vec)
mat = as.matrix(expand.grid(lst))
mat = mat[which(rowSums(mat)==x),]
if(l>2){
#k=1 is redundant since all must be less than or equal to cvec[1]
for (k in seq(from=2, to=l-1)){
row.indx = NULL
for (r in seq(l-k+1)){
#pick out the index of the row(s) that satisfy constraint
row.indx = which(rowSums(mat[,r:(r+k-1),drop=FALSE])<=cvec[k])
#filter rows of mat
mat = mat[unique(row.indx),]
}
}
}
return(mat)
}
==
by%in%
so you can now use a whole vector likex=seq(from=148,to=155)
as input. For the output, you couldreturn(table(rowSums(mat))
if all you care about is the number of solutions. Also, your use ofunique()
is useless and you do not need to initalizerow.indx = NULL
. \$\endgroup\$