Home > Software engineering >  Combinations with constraints
Combinations with constraints

Time:02-03

I would like to generate all possible combinations with some constraints but I can't find a smart solution.

Suppose I have 5 element order by riskiness and I want combine these elements in three aggregate groups with these constraints:

  1. All 3 groups must be represented (e.g. 1,2,2,2,2 is not accepted since 3 is missing)
  2. Order matters (e.g. 1,2,1,2,3 is not accepted because 1 is between the two)

At the moment I create these groups with these line of codes, but I would like to extend to multi cases (e.g. 15 element aggregated in 5 groups etc.). Is there a R function already available?

risk_disaggregated<-c("1. Very low risk","2. Low risk","3. Medium risk","4. High risk","5. Very high risk")

aggregation<-c(rep(1,3),rep(2,1),rep(3,1))
aggregation1<-c(rep(1,1),rep(2,3),rep(3,1))
aggregation2<-c(rep(1,1),rep(2,1),rep(3,3))
aggregation3<-c(rep(1,1),rep(2,2),rep(3,2))
aggregation4<-c(rep(1,2),rep(2,2),rep(3,1))
aggregation5<-c(rep(1,2),rep(2,1),rep(3,2))
                
db_final<-cbind(risk_disaggregated,aggregation,aggregation1,aggregation2,aggregation3,aggregation4,aggregation5)

CodePudding user response:

I came up with this:

library(dplyr) # bind_cols 

risk_disaggregated<-c("1. Very low risk",
                      "2. Low risk",
                      "3. Medium risk",
                      "4. High risk",
                      "5. Very high risk")

unique_vals <- 1:3
fill <- 5
most <- fill-length(unique_vals)
(variations <- combn(x = rep(unique_vals,most),
                     m = most,
                     simplify = FALSE) |> 
    lapply(sort) |> 
    unique())

(variations <- setNames(variations,
                        paste0("set_",seq_along(variations))))

bind_cols(risk=risk_disaggregated,
          lapply(variations,\(x)sort(c(unique_vals,x))))

CodePudding user response:

Since each row of n elements must have at least one entry of each of k groups, simply cbind a matrix where every row is 1:k with a matrix of combinations of 1:(n - k) with repetition. Then sort each row to meet your order constraint.

An implementation using RcppAlgos and Rfast. It will be quite fast.

library(RcppAlgos) # for comboGeneral
library(Rfast) # for rowSort

k <- 3L
n <- 5L
rowSort(cbind(m <- comboGeneral(k, n - k, TRUE), col(diag(0L, nrow(m), k))))

#>      [,1] [,2] [,3] [,4] [,5]
#> [1,]    1    1    1    2    3
#> [2,]    1    1    2    2    3
#> [3,]    1    1    2    3    3
#> [4,]    1    2    2    2    3
#> [5,]    1    2    2    3    3
#> [6,]    1    2    3    3    3

The 15 element, 5 group case:

k <- 5L
n <- 15L
m <- rowSort(cbind(m <- comboGeneral(k, n - k, TRUE), col(diag(0L, nrow(m), k))))
dim(m)
#> [1] 1001   15
  • Related