Skip to content

new PCS handling functions: DO NOT MERGE #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Roxygen: list(wrap = FALSE)
Imports:
BBmisc (>= 1.10),
checkmate (>= 1.8.2),
stringi,
methods
Suggests:
akima,
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export(makeParamSet)
export(makeUntypedLearnerParam)
export(makeUntypedParam)
export(paramValueToString)
export(parsePCSFile)
export(plotEAF)
export(plotOptPath)
export(plotYTraces)
Expand All @@ -180,6 +181,7 @@ import(BBmisc)
import(checkmate)
import(methods)
import(stats)
import(stringi)
useDynLib(ParamHelpers,c_dfRowsToList)
useDynLib(ParamHelpers,c_generateDesign)
useDynLib(ParamHelpers,c_trafo_and_set_dep_to_na)
86 changes: 86 additions & 0 deletions R/parsePCSFile.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
consume = function(s, regexp) {
loc = stri_locate_first_regex(s, regexp)[1L, ]
e = stri_sub(s, loc[1L], loc[2L])
r = stri_join(stri_sub(s, 1L, loc[1L] - 1L), stri_sub(s, loc[2L] + 1L, stri_length(s)))
list(match = stri_trim_both(e), rest = stri_trim_both(r))
}

parseDefault = function(s) {
s = consume(s, "\\[.*\\]")
stri_trim_both(stri_replace_all_regex(s$match, "[\\[\\]]", ""))
}

stri_split_trim = function(x, sep = ",") {
stri_trim_both(stri_split_fixed(x, sep)[[1L]])
}

#' @title Read and parse PCS files
#'
#' @param file [\code{character(1)}].\cr
#' Path to the PCS file.
#' @return \code{\link{ParamSet}}.
#' @export
parsePCSFile = function(file) {
assertFileExists(file, access = "r", extension = "pcs")

lines = stri_read_lines(file)
lines = stri_replace_all_regex(lines, "#.*", "")
lines = stri_trim_both(lines)
lines = lines[nzchar(lines)]
result = list()

lines = lines[!stri_startswith_fixed(lines, "Conditionals:")]
j = stri_detect_fixed(lines, "|")
lines.cond = lines[j]
lines = lines[!j]

lines = lines[!stri_startswith_fixed(lines, "Forbidden:")]
j = stri_startswith_fixed(lines, "{") & stri_endswith_fixed(lines, "}")
lines.forbidden = lines[j]
lines = lines[!j]

### parse param lines
for (line in lines) {
z = consume(line, "[a-zA-Z0-9_\\-]+\\s*")
id = z$match

if (stri_startswith_fixed(z$rest, "[")) { # num or int param
z = consume(z$rest, "^\\[.*?\\]")
bounds = stri_replace_all_regex(z$match, "[\\[\\]]", "")
bounds = as.numeric(stri_split_trim(bounds))
if (stri_detect_fixed(z$rest, "i")) {
def = as.numeric(parseDefault(z$rest))
par = makeIntegerParam(id = id, lower = bounds[1L], upper = bounds[2L], default = def)
} else {
def = as.integer(parseDefault(z$rest))
par = makeNumericParam(id = id, lower = bounds[1L], upper = bounds[2L], default = def)
}
} else if (stri_startswith_fixed(z$rest, "{")) { # discrete
z = consume(z$rest, "^\\{.*\\}")
values = stri_replace_all_regex(z$match, "[{}]", "")
values = stri_split_trim(values)
def = parseDefault(z$rest)
par = makeDiscreteParam(id = id, values = values, default = def)
} else {
stop("Illegal format")
}
result[[id]] = par
}

for (line in lines.cond) {
s = stri_split_trim(line, "|")
id1 = s[1L]
stopifnot(id %in% names(result))

s = stri_split_trim(s[2L], " in ")
id2 = s[1L]
stopifnot(id2 %in% names(result))

vals = stri_split_trim(stri_replace_all_regex(s[2L], "[{}]", ""))
req = sprintf("%s %%in%% c('%s')", id2, stri_flatten(vals, "','"))
req = quote(req)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably be asQuoted

result[[id1]]$requires = req
}

result
}
4 changes: 4 additions & 0 deletions R/pcs_helpers.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
filterEmptyStrings = function(xs) {
xs = vcapply(xs, stri_trim)
xs[nzchar(xs)]
}
35 changes: 35 additions & 0 deletions R/writePCSFile.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#' @title Writes a param set to a PCS files.
#'
#' @description
#'
#' @template arg_parset
#' @param path [\code{character(1)}]\cr
#' File path for output PCS file.
#' @param overwrite [\code{logical(1)}]\cr
#' Can \code{path} be overwritten?
#' Default is \code{FALSE}.
#' @return Nothing.
#' @family ParamSet, pcs
writePCSFile = function(par.set, path, overwrite = FALSE) {
assertClass(par.set, "ParamSet")
assertPathForOutput(path, overwrite = overwrite)
assertFlag(overwrite)
lines = character(0L) # result container

# write line for a scalar (nonvec) param, returns string
writePCSScalarLine = function(p) {
s = sprintf("%s [%g,%g] [%g]", p$id, p$lower, p$upper, p$default)
# print(s)
return(s)
}

# loop over params, loop over length of vectors, add line to "lines"
for (p in par.set$pars) {
len = p$len
for (j in 1:p$len) {
lines[length(lines) + 1L] = writePCSScalarLine(p)
}
}
stri_write_lines(fname = path, str = lines)
invisible(NULL)
}
1 change: 1 addition & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
#' @import checkmate
#' @import methods
#' @import stats
#' @import stringi
NULL
5 changes: 5 additions & 0 deletions inst/pcs_files/branin-params.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ps = makeParamSet(
makeNumericParam("x0", lower = -5, upper = 10, default = 10),
makeNumericParam("x1", lower = 0, upper = 15, default = 15)
)

3 changes: 3 additions & 0 deletions inst/pcs_files/branin-params.pcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
x0 [-5,10] [10]
x1 [0, 15] [15]

8 changes: 8 additions & 0 deletions inst/pcs_files/camelback-params.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x0 [-3,3] [3]
x1 [-2, 2] [2]

ps = makeParamSet(
makeNumericParam("x0", lower = -3, upper = 3, default = 3),
makeNumericParam("x1", lower = -2, upper = 2, default = 2)
)

2 changes: 2 additions & 0 deletions inst/pcs_files/camelback-params.pcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x0 [-3,3] [3]
x1 [-2, 2] [2]
80 changes: 80 additions & 0 deletions inst/pcs_files/cplex12-params-milp.pcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
barrier_limits_growth {1e+6,1e+8,1e+10,1e+12,1e+14}[1e+12] # barrier growth limit. Allegedly called bargrowth. in R, >= 1.0. Now that I check results numerically this can be optimized
barrier_algorithm {0,1,2,3}[0] # barrier algorithm. Auto, cat
barrier_crossover {-1,0,1,2}[0] # barrier crossover algorithm. Auto, cat
barrier_limits_corrections {-1,0,1,4,16,64}[-1] # barrier maximum correction limit. Auto=-1, in N+, poorly informed
barrier_ordering {0,1,2,3} [0] # barrier ordering algorithm. Auto, cat
barrier_startalg {1,2,3,4}[1] # barrier starting point algorithm. Auto, cat
emphasis_memory {no}[no] #MEMORYEMPHASIS. No auto. Binary. Disallow emphasis_memory yes.
emphasis_mip {0,1,2,3,4}[0] # MIP emphasis switch. Auto, cat
emphasis_numerical {yes,no}[no] # numerical precision emphasis. No auto, cat. Since I penalize (too) poor numerical precision this is an optimization parameter
feasopt_mode {0,1,2,3,4,5}[0] # mode of FeasOpt. Auto, cat
lpmethod {0,1,2,3,4,5,6}[0] # algorithm for continuous problems. Auto, cat
mip_cuts_cliques {-1,0,1,2,3}[0] # MIP cliques switch. Auto, cat
mip_cuts_covers {-1,0,1,2,3}[0] # MIP covers switch. Auto, cat
mip_cuts_disjunctive {-1,0,1,2,3}[0] # MIP disjunctive cuts switch. Auto, cat
mip_cuts_flowcovers {-1,0,1,2}[0] # MIP flow cover cuts switch. Auto, cat
mip_cuts_gomory {-1,0,1,2}[0] # MIP Gomory fractional cuts switch. Auto, cat
mip_cuts_gubcovers {-1,0,1,2}[0] # MIP GUB cuts switch. Auto, cat
mip_cuts_implied {-1,0,1,2}[0] # MIP implied bound cuts switch. Auto, cat
mip_cuts_mcfcut {-1,0,1,2}[0] # MCF cut switch. Auto, cat
mip_cuts_mircut {-1,0,1,2}[0] # MIP MIR (mixed integer rounding) cut switch. Auto, cat
mip_cuts_pathcut {-1,0,1,2}[0] # MIP flow path cut switch. Auto, cat
mip_cuts_zerohalfcut {-1,0,1,2} [0] # MIP zero-half cuts switch. Auto, cat
mip_limits_aggforcut {0,1,2,3,5,10}[3] # constraint aggregation limit for cut generation. No auto, in N+_0
mip_limits_cutsfactor {1,2,4,8,16}[4] # row multiplier factor for cuts. in R+
mip_limits_cutpasses {-1,0,1,4,16,64}[0] # number of cutting plane passes. Auto=0, in N+, poorly informed
mip_limits_gomorycand {50,100,200,400,800}[200] # candidate limit for generating Gomory fractional cuts. No auto, in N+
mip_limits_gomorypass {0,1,4,16,64}[0] # pass limit for generating Gomory fractional cuts. Auto=0, in N+, poorly informed
mip_limits_strongcand {2,5,10,20,40}[10] # MIP strong branching candidate list limit. No auto, in N_0+
mip_limits_strongit {0,1,4,16,64}[0] # MIP strong branching iterations limit. Auto=0, in N+ , poorly informed
mip_limits_submipnodelim {125,250,500,1000,2000}[500] # limit on nodes explored when a subMIP is being solved. No auto, in N_0+
mip_ordertype {0,1,2,3}[0] # MIP priority order generation. No auto, cat
mip_strategy_backtrack {0.9,0.99,0.999,0.9999,0.99999,0.999999} [0.9999] # backtracking tolerance. No auto, any number from 0.0 to 1.0. Despite the name this is not a tolerance parameter
mip_strategy_bbinterval {2,4,7,15,30,1000}[7] # MIP strategy best bound interval. No auto, in N+_0. 0 is equivalent to infinity
mip_strategy_branch {-1,0,1} [0] # MIP branching direction. Auto, cat
mip_strategy_dive {0,1,2,3}[0] # MIP dive strategy. Auto, cat
mip_strategy_file {0,1}[1] #node storage file switch. No auto. Cat. DISALLOW values 2 and 3 => they write files to disk (stuff will break and we run out of space)
mip_strategy_fpheur {-1,0,1,2}[0] # feasibility pump switch. Auto, cat. Does NOT apply for MIQCP
mip_strategy_heuristicfreq {-1,0,5,10,20,40,80}[0] # MIP heuristic frequency. Auto=0, in N+. 20 is an example used in the manual. It may be totally off...
mip_strategy_lbheur {yes,no}[no] # local branching heuristic. No auto, cat
mip_strategy_nodeselect {0,1,2,3}[1] # MIP node selection strategy. No auto, cat
mip_strategy_order {yes,no}[yes] # MIP priority order switch. No auto, cat.
mip_strategy_presolvenode {-1,0,1,2}[0] # node presolve switch. Auto, cat
mip_strategy_probe {-1,0,1,2,3}[0] # MIP probing level. Auto, cat
mip_strategy_rinsheur {-1,0,5,10,20,40,80}[0] # RINS heuristic frequency. Auto=0, 20 is an example from the CPLEX parameter reference; could be totally off
mip_strategy_search {0,1,2} [0] # MIP dynamic search switch. Auto, cat. NOT compatible with callbacks (fine in our case, where we don't use those)
mip_strategy_startalgorithm {0,1,2,3,4,5,6}[0] # MIP starting algorithm. Auto, cat. SPECIAL CASES: MIQCP and MIQP only allow some of these
mip_strategy_subalgorithm {0,1,2,3,4,5}[0] # MIP subproblem algorithm. Auto, cat.
mip_strategy_variableselect {-1,0,1,2,3,4} [0] # MIP variable selection strategy. Auto, cat
network_netfind {1,2,3}[2] # simplex network extraction level. No auto, cat
network_pricing {0,1,2}[0] # network simplex pricing algorithm. Auto, cat. The CPLEX parameter reference says the default (0) is identical to option 3, which I thus disabled.
perturbation_constant {1e-8,1e-7,1e-6,1e-5,1e-4}[1e-6] # part 2 of parameter "simplex_perturbation", conditional on part1=1
preprocessing_aggregator {-1,0,1,4,16,64}[-1] # preprocessing aggregator application limit
preprocessing_boundstrength {-1,0,1}[-1] # bound strengthening switch. Auto, cat
preprocessing_coeffreduce {0,1,2} [2] # coefficient reduction setting. Auto, cat
preprocessing_dependency {-1,0,1,2,3}[-1] # dependency switch. Auto, cat
preprocessing_dual {-1,0,1}[0] # presolve dual setting. Auto, cat
preprocessing_fill {2,5,10,20,40}[10] # preprocessing aggregator fill. No auto, in N+
preprocessing_linear {0,1}[1] # linear reduction switch. No auto, cat
preprocessing_numpass {-1,0,1,4,16,64}[-1] # limit on the number of presolve passes made. Auto=-1, in N+, poorly informed
preprocessing_reduce {0,1,2,3}[3] # primal and dual reduction type. Auto, cat
preprocessing_relax {-1,0,1}[-1] # relaxed LP presolve switch. Auto, cat
preprocessing_repeatpresolve {-1,0,1,2,3}[-1] # MIP repeat presolve switch. Auto, cat
preprocessing_symmetry {-1,0,1,2,3,4,5} [-1] # symmetry breaking. Auto, cat
read_scale {-1,0,1}[0] # scale parameter. Auto, cat
sifting_algorithm {0,1,2,3,4}[0] # sifting subproblem algorithm. Auto, cat.
simplex_crash {-1,0,1}[1] # simplex crash ordering. Auto, cat
simplex_dgradient {0,1,2,3,4,5}[0] # dual simplex pricing algorithm. Auto, cat
simplex_limits_perturbation {0,1,4,16,64}[0] # simplex perturbation limit. Auto=0, in N+, poorly informed
simplex_limits_singularity {2,5,10,20,40}[10] # simplex singularity repair limit. No auto, in N_0+
simplex_perturbation_switch {no,yes}[no] # part 1 of parameter "simplex_perturbation"
simplex_pgradient {-1,0,1,2,3,4}[0] # primal simplex pricing algorithm. Auto, cat
simplex_pricing {0,1,4,16,64}[0] # simplex pricing candidate list size. Auto=0, in N+, poorly informed
simplex_refactor {0,4,16,64,256} [0] #simplex refactoring frequency. 0=Auto. N+. Simplex refactorization interval. Hoyt's LP notes say Chvtal suggests an optimal refactorization interval of 16.
simplex_tolerances_markowitz {0.0001, 0.001, 0.01, 0.1, 0.5} [0.01] # Markowitz tolerance. 0.0001 to 0.99999

Conditionals:
mip_limits_strongcand | mip_strategy_variableselect in {3}
mip_limits_strongit | mip_strategy_variableselect in {3}
mip_strategy_order | mip_ordertype in {1,2,3}
perturbation_constant | simplex_perturbation_switch in {yes}
12 changes: 12 additions & 0 deletions inst/pcs_files/saps-params.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# alpha [1, 1.4] [1.189]l
# rho [0, 1] [0.5]
# ps [0, 0.2] [0.1]
# wp [0, 0.06] [0.03]

ps = makeParamSet(
makeNumericParam("alpha", lower = -5, upper = 10, default = 10),
makeNumericParam("rho", lower = 0, upper = 15, default = 15),
makeNumericParam("ps", lower = 0, upper = 15, default = 15),
makeNumericParam("wp", lower = 0, upper = 15, default = 15)
)

4 changes: 4 additions & 0 deletions inst/pcs_files/saps-params.pcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
alpha [1, 1.4] [1.189]l
rho [0, 1] [0.5]
ps [0, 0.2] [0.1]
wp [0, 0.06] [0.03]
38 changes: 38 additions & 0 deletions inst/pcs_files/spear-params-mixed.pcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
sp-var-dec-heur {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}[0] # Originally, 3,4,9,10 not used following Domagoj's advice. 20 requires modular arithmetic input format
sp-learned-clause-sort-heur {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}[0] # All values make sense here. 20 requires modular arithmetic input format
sp-orig-clause-sort-heur {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}[0] # All values make sense here. 20 requires modular arithmetic input format
sp-res-order-heur {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}[0] # All values make sense here. 20 requires modular arithmetic input format
sp-clause-del-heur {0,1,2}[2] # All values make sense here.
sp-phase-dec-heur {0,1,2,3,4,5,6}[5] # All values make sense here.
sp-resolution {0,1,2}[1] # 0 renders a whole bunch of conditionals irrelevant.
sp-variable-decay [1, 2] [1.4]l # Should be bigger than 1 (o/w increase not decay). Was: in 1.1,1.4,2.0, def 1.4
sp-clause-decay [1, 2] [1.4]l # Same thing.
sp-restart-inc [1.1, 1.9] [1.5] # Uniform because multiplicative. Was: in 1.1,1.3,1.5,1.7,1.9, def 1.5
sp-learned-size-factor [0.1, 1.6] [0.4]l # Uniform on logarithmic scale (starting value). Was: in 0.1,0.2,0.4,0.8,1.6, def 0.4
sp-learned-clauses-inc [1.1, 1.5] [1.3] # 1.2 and 1.4 were introduced later. Uniform because multiplicative Was: in1.1,1.2,1.3,1.4,1.5, def 1.3
sp-clause-activity-inc [0.5, 1.5] [1] # Was: in 0.5,1,1.5, def 1
sp-var-activity-inc [0.5, 1.5] [1] # Was: in 0.5,1,1.5, def 1
sp-rand-phase-dec-freq{0, 0.0001, 0.001, 0.005, 0.01, 0.05}[0.001] # Used discretized version to preserve 0. Never picked 0.05 in previous experiments, always zero.
sp-rand-var-dec-freq {0, 0.0001, 0.001, 0.005, 0.01, 0.05}[0.001] # Used discretized version to preserve 0. Never picked 0.05 in previous experiments, always zero.
sp-rand-var-dec-scaling [0.3, 1.1] [1] # Domagoj said the previous values were too coarse, so finer discretization now.
sp-rand-phase-scaling [0.3, 1.1] [1] # Same thing. Was: in 0.3,0.6,0.9,1,1.1, def 1
sp-max-res-lit-inc [0.25, 4][1]l # 0.5 and 2 were introduced later. Was: in 0.25,0.5,1,2,4, def 1
sp-first-restart [25, 3200] [100]il # Uniform on logarithmic scale (starting value). Was: in 25,50,100,200,400,800,1600,3200, def 100
sp-res-cutoff-cls [2, 20] [8]il # Only up to 20 allowed, would've used 32 otherwise.
sp-res-cutoff-lits [100, 1600] [400]il # Was: in 100,200,400,800,1600, def 400
sp-max-res-runs [1, 32] [4]il # Was: in 1,2,4,8,16,32, def 4
sp-update-dec-queue {0,1}[1] # Enable by default.
sp-use-pure-literal-rule {0,1}[1] # Enable by default.
sp-clause-inversion {0,1}[1] # Enable by default. Enable reversion of learned clauses if fixed order (sp-learned-clause-sort-heur=19)

Conditionals:
sp-rand-phase-dec-freq|sp-phase-dec-heur in {0,1,3,4,5,6} # when heuristic is random, then additional random steps don't change anything
sp-rand-var-dec-scaling|sp-rand-var-dec-freq in {0.0001, 0.001, 0.005, 0.01, 0.05} # not 0
sp-rand-phase-scaling|sp-rand-phase-dec-freq in {0.0001, 0.001, 0.005, 0.01, 0.05} # not 0
sp-clause-inversion|sp-learned-clause-sort-heur in {19}

sp-res-order-heur|sp-resolution in {1,2}
sp-max-res-lit-inc|sp-resolution in {1,2}
sp-res-cutoff-cls|sp-resolution in {1,2}
sp-res-cutoff-lits|sp-resolution in {1,2}
sp-max-res-runs|sp-resolution in {1,2}
15 changes: 15 additions & 0 deletions man/parsePCSFile.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions man/writePCSFile.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions test.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load_all()

ps = makeParamSet(
makeNumericParam("x0", lower = -5, upper = 10, default = 10),
makeNumericParam("x1", lower = 0, upper = 15, default = 15 )
)


writePCSFile(ps, path = "~/cos/ParamHelpers/bla.pcs", overwrite = TRUE)
Loading