Specify the software and configuration used to solve a project prioritization
problem()
. By default, the best available exact algorithm
solver will be used.
The following solvers can be used to find solutions for a
project prioritization problem()
:
add_default_solver()
This solver uses the best software currently installed on the system.
add_gurobi_solver()
Gurobi is a state-of-the-art commercial optimization software with an R package interface. It is by far the fastest solver that can be used by this package, however, it is also the only solver that is not freely available. That said, licenses are available to academics at no cost. The gurobi package is distributed with the Gurobi software suite. This solver uses the gurobi package to solve problems.
add_rsymphony_solver()
SYMPHONY is an open-source integer programming solver that is part of the Computational Infrastructure for Operations Research (COIN-OR) project, an initiative to promote development of open-source tools for operations research (a field that includes linear programming). The Rsymphony package provides an interface to COIN-OR and is available on CRAN. This solver uses the Rsymphony package to solve problems.
add_lpsymphony_solver()
The lpsymphony package provides a different interface to the COIN-OR software suite. Unlike the Rsymhpony package, the lpsymphony package is distributed through Bioconductor. The lpsymphony package may be easier to install on Windows or Max OSX systems than the Rsymphony package.
add_lpsolveapi_solver()
lp_solve is an open-source integer programming solver. The lpSolveAPI package provides an interface to this solver and is available on CRAN. Although this solver is the slowest currently supported solver, it is also the only exact algorithm solver that can be installed on all operating systems without any manual installation steps.
add_heuristic_solver()
Generate solutions using a backwards heuristic algorithm. Although these types of algorithms have conventionally been used to solve project prioritization problems, they are extremely unlikely to identify optimal solutions and provide no guarantees concerning solution quality.
add_random_solver()
Generate solutions by
randomly funding actions. This can be useful when evaluating the
performance of a funding scheme---though it is strongly recommended
to evaluate the performance of a funding scheme by comparing it
to an optimal solution identified using exact algorithms (e.g.
add_gurobi_solver()
, add_rsymphony_solver()
).
# load data
data(sim_projects, sim_features, sim_actions)
# build problem
p1 <- problem(sim_projects, sim_actions, sim_features,
"name", "success", "name", "cost", "name") %>%
add_max_richness_objective(budget = 200) %>%
add_binary_decisions()
# build another problem, with the default solver
p2 <- p1 %>%
add_default_solver()
# build another problem, with the gurobi solver
# \dontrun{
p3 <- p1 %>%
add_gurobi_solver()
# }
# build another problem, with the Rsympony solver
# \dontrun{
p4 <- p1 %>%
add_rsymphony_solver()
# }
# build another problem, with the lpsymphony solver
# \dontrun{
p5 <- p1 %>%
add_lpsymphony_solver()
# }
# build another problem, with the lpSolveAPI solver
p6 <- p1 %>%
add_lpsolveapi_solver()
# build another problem, with the heuristic solver
p7 <- p1 %>%
add_heuristic_solver()
# build another problem, with the random solver
p8 <- p1 %>%
add_random_solver()
# \dontrun{
# generate solutions using each of the solvers
s <- rbind(solve(p2), solve(p3), solve(p4), solve(p5), solve(p6), solve(p7),
solve(p8))
#> Set parameter Username
#> Set parameter TimeLimit to value 2147483647
#> Set parameter MIPGap to value 0
#> Set parameter NumericFocus to value 3
#> Set parameter Presolve to value 2
#> Set parameter Threads to value 1
#> Set parameter PoolSolutions to value 1
#> Set parameter PoolSearchMode to value 2
#> Academic license - for non-commercial use only - expires 2025-04-21
#> Gurobi Optimizer version 11.0.2 build v11.0.2rc0 (linux64 - "Ubuntu 22.04.4 LTS")
#>
#> CPU model: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz, instruction set [SSE2|AVX|AVX2|AVX512]
#> Thread count: 4 physical cores, 8 logical processors, using up to 1 threads
#>
#> Optimize a model with 47 rows, 47 columns and 102 nonzeros
#> Model fingerprint: 0x193cb636
#> Variable types: 0 continuous, 42 integer (42 binary)
#> Semi-Variable types: 5 continuous, 0 integer
#> Coefficient statistics:
#> Matrix range [9e-02, 1e+02]
#> Objective range [1e+00, 1e+00]
#> Bounds range [1e+00, 1e+00]
#> RHS range [1e+00, 2e+02]
#> Found heuristic solution: objective 1.4456093
#> Presolve removed 16 rows and 12 columns
#> Presolve time: 0.00s
#> Presolved: 31 rows, 35 columns, 65 nonzeros
#> Variable types: 0 continuous, 35 integer (35 binary)
#> Root relaxation presolved: 31 rows, 35 columns, 65 nonzeros
#>
#>
#> Root relaxation: objective 2.190381e+00, 11 iterations, 0.00 seconds (0.00 work units)
#>
#> Nodes | Current Node | Objective Bounds | Work
#> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
#>
#> * 0 0 0 2.1903807 2.19038 0.00% - 0s
#>
#> Explored 1 nodes (11 simplex iterations) in 0.00 seconds (0.00 work units)
#> Thread count was 1 (of 8 available processors)
#>
#> Solution count 1: 2.19038
#> No other solutions better than 2.19038
#>
#> Optimal solution found (tolerance 0.00e+00)
#> Best objective 2.190380737245e+00, best bound 2.190380737245e+00, gap 0.0000%
#> Set parameter Username
#> Set parameter TimeLimit to value 2147483647
#> Set parameter MIPGap to value 0
#> Set parameter NumericFocus to value 3
#> Set parameter Presolve to value 2
#> Set parameter Threads to value 1
#> Set parameter PoolSolutions to value 1
#> Set parameter PoolSearchMode to value 2
#> Academic license - for non-commercial use only - expires 2025-04-21
#> Gurobi Optimizer version 11.0.2 build v11.0.2rc0 (linux64 - "Ubuntu 22.04.4 LTS")
#>
#> CPU model: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz, instruction set [SSE2|AVX|AVX2|AVX512]
#> Thread count: 4 physical cores, 8 logical processors, using up to 1 threads
#>
#> Optimize a model with 47 rows, 47 columns and 102 nonzeros
#> Model fingerprint: 0x193cb636
#> Variable types: 0 continuous, 42 integer (42 binary)
#> Semi-Variable types: 5 continuous, 0 integer
#> Coefficient statistics:
#> Matrix range [9e-02, 1e+02]
#> Objective range [1e+00, 1e+00]
#> Bounds range [1e+00, 1e+00]
#> RHS range [1e+00, 2e+02]
#> Found heuristic solution: objective 1.4456093
#> Presolve removed 16 rows and 12 columns
#> Presolve time: 0.00s
#> Presolved: 31 rows, 35 columns, 65 nonzeros
#> Variable types: 0 continuous, 35 integer (35 binary)
#> Root relaxation presolved: 31 rows, 35 columns, 65 nonzeros
#>
#>
#> Root relaxation: objective 2.190381e+00, 11 iterations, 0.00 seconds (0.00 work units)
#>
#> Nodes | Current Node | Objective Bounds | Work
#> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
#>
#> * 0 0 0 2.1903807 2.19038 0.00% - 0s
#>
#> Explored 1 nodes (11 simplex iterations) in 0.00 seconds (0.00 work units)
#> Thread count was 1 (of 8 available processors)
#>
#> Solution count 1: 2.19038
#> No other solutions better than 2.19038
#>
#> Optimal solution found (tolerance 0.00e+00)
#> Best objective 2.190380737245e+00, best bound 2.190380737245e+00, gap 0.0000%
#>
#> Model name: 'project prioritization problem' - run #1
#> Objective: Maximize(R0)
#>
#> SUBMITTED
#> Model size: 47 constraints, 47 variables, 102 non-zeros.
#> Sets: 0 GUB, 0 SOS.
#>
#> Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
#> The primal and dual simplex pricing strategy set to 'Devex'.
#>
#>
#> Relaxed solution 2.21077983146 after 34 iter is B&B base.
#>
#> Feasible solution 1.91490153549 after 43 iter, 8 nodes (gap 9.2%)
#> Improved solution 2.0146497578 after 47 iter, 11 nodes (gap 6.1%)
#> Improved solution 2.19038073724 after 59 iter, 20 nodes (gap 0.6%)
#>
#> Optimal solution 2.19038073724 after 59 iter, 20 nodes (gap 0.6%).
#>
#> Excellent numeric accuracy ||*|| = 1.11022e-16
#>
#> MEMO: lp_solve version 5.5.2.0 for 64 bit OS, with 64 bit LPSREAL variables.
#> In the total iteration count 59, 16 (27.1%) were bound flips.
#> There were 11 refactorizations, 0 triggered by time and 1 by density.
#> ... on average 3.9 major pivots per refactorization.
#> The largest [LUSOL v2.2.1.0] fact(B) had 104 NZ entries, 1.0x largest basis.
#> The maximum B&B level was 6, 0.1x MIP order, 4 at the optimal solution.
#> The constraint matrix inf-norm is 103.226, with a dynamic range of 1193.9.
#> Time to load data was 0.000 seconds, presolve used 0.000 seconds,
#> ... 0.000 seconds in simplex solver, in total 0.000 seconds.
s$solver <- c("default", "gurobi", "Rsymphony", "lpsymphony", "lpSolveAPI",
"heuristic", "random")
# print solutions
print(as.data.frame(s))
#> solution status obj cost F1_action F2_action
#> 1 1 OPTIMAL 2.190381 195.3907 1 1
#> 2 1 OPTIMAL 2.190381 195.3907 1 1
#> 3 1 TM_OPTIMAL_SOLUTION_FOUND 2.190381 195.3907 1 1
#> 4 1 TM_OPTIMAL_SOLUTION_FOUND 2.190381 195.3907 1 1
#> 5 1 optimal solution found 2.190381 195.3907 1 1
#> 6 1 <NA> 2.190381 195.3907 1 1
#> 7 1 <NA> 2.190381 195.3907 1 1
#> F3_action F4_action F5_action baseline_action F1_project F2_project
#> 1 0 0 0 1 1 1
#> 2 0 0 0 1 1 1
#> 3 0 0 0 1 1 1
#> 4 0 0 0 1 1 1
#> 5 0 0 0 1 1 1
#> 6 0 0 0 1 1 1
#> 7 0 0 0 1 1 1
#> F3_project F4_project F5_project baseline_project F1 F2
#> 1 0 0 0 1 0.8080322 0.8649623
#> 2 0 0 0 1 0.8080322 0.8649623
#> 3 0 0 0 1 0.8080322 0.8649623
#> 4 0 0 0 1 0.8080322 0.8649623
#> 5 0 0 0 1 0.8080322 0.8649623
#> 6 0 0 0 1 0.8080322 0.8649623
#> 7 0 0 0 1 0.8080322 0.8649623
#> F3 F4 F5 solver
#> 1 0.0864612 0.2489246 0.1820005 default
#> 2 0.0864612 0.2489246 0.1820005 gurobi
#> 3 0.0864612 0.2489246 0.1820005 Rsymphony
#> 4 0.0864612 0.2489246 0.1820005 lpsymphony
#> 5 0.0864612 0.2489246 0.1820005 lpSolveAPI
#> 6 0.0864612 0.2489246 0.1820005 heuristic
#> 7 0.0864612 0.2489246 0.1820005 random
# }