1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 SRI International.
4 *
5 * Yices is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Yices is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Yices. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #if defined(CYGWIN) || defined(MINGW)
20 #ifndef __YICES_DLLSPEC__
21 #define __YICES_DLLSPEC__ __declspec(dllexport)
22 #endif
23 #endif
24
25 #include <assert.h>
26
27 #include "frontend/common/parameters.h"
28 #include "utils/string_utils.h"
29
30 /*
31 * Parameter names: using the Yices conventions
32 * - for the smt2 front end, you prefix these names with ':yices:'
33 */
34 static const char * const param_names[NUM_PARAMETERS] = {
35 "arith-elim",
36 "aux-eq-quota",
37 "aux-eq-ratio",
38 "bland-threshold",
39 "branching",
40 "bvarith-elim",
41 "c-factor",
42 "c-threshold",
43 "cache-tclauses",
44 "clause-decay",
45 "d-factor",
46 "d-threshold",
47 "dyn-ack",
48 "dyn-ack-threshold",
49 "dyn-bool-ack",
50 "dyn-bool-ack-threshold",
51 "eager-lemmas",
52 "ef-flatten-iff",
53 "ef-flatten-ite",
54 "ef-gen-mode",
55 "ef-max-iters",
56 "ef-max-samples",
57 "fast-restarts",
58 "flatten",
59 "icheck",
60 "icheck-period",
61 "keep-ite",
62 "learn-eq",
63 "max-ack",
64 "max-bool-ack",
65 "max-extensionality",
66 "max-interface-eqs",
67 "max-update-conflicts",
68 "mcsat-bv-var-size",
69 "mcsat-nra-bound",
70 "mcsat-nra-bound-max",
71 "mcsat-nra-bound-min",
72 "mcsat-nra-mgcd",
73 "mcsat-nra-nlsat",
74 "mcsat-var-order",
75 "optimistic-fcheck",
76 "prop-threshold",
77 "r-factor",
78 "r-fraction",
79 "r-threshold",
80 "random-seed",
81 "randomness",
82 "simplex-adjust",
83 "simplex-prop",
84 "tclause-size",
85 "var-decay",
86 "var-elim",
87 };
88
89 // corresponding parameter codes in order
90 static const yices_param_t param_code[NUM_PARAMETERS] = {
91 PARAM_ARITH_ELIM,
92 PARAM_AUX_EQ_QUOTA,
93 PARAM_AUX_EQ_RATIO,
94 PARAM_BLAND_THRESHOLD,
95 PARAM_BRANCHING,
96 PARAM_BVARITH_ELIM,
97 PARAM_C_FACTOR,
98 PARAM_C_THRESHOLD,
99 PARAM_CACHE_TCLAUSES,
100 PARAM_CLAUSE_DECAY,
101 PARAM_D_FACTOR,
102 PARAM_D_THRESHOLD,
103 PARAM_DYN_ACK,
104 PARAM_DYN_ACK_THRESHOLD,
105 PARAM_DYN_BOOL_ACK,
106 PARAM_DYN_BOOL_ACK_THRESHOLD,
107 PARAM_EAGER_LEMMAS,
108 PARAM_EF_FLATTEN_IFF,
109 PARAM_EF_FLATTEN_ITE,
110 PARAM_EF_GEN_MODE,
111 PARAM_EF_MAX_ITERS,
112 PARAM_EF_MAX_SAMPLES,
113 PARAM_FAST_RESTARTS,
114 PARAM_FLATTEN,
115 PARAM_ICHECK,
116 PARAM_ICHECK_PERIOD,
117 PARAM_KEEP_ITE,
118 PARAM_LEARN_EQ,
119 PARAM_MAX_ACK,
120 PARAM_MAX_BOOL_ACK,
121 PARAM_MAX_EXTENSIONALITY,
122 PARAM_MAX_INTERFACE_EQS,
123 PARAM_MAX_UPDATE_CONFLICTS,
124 PARAM_MCSAT_BV_VAR_SIZE,
125 PARAM_MCSAT_NRA_BOUND,
126 PARAM_MCSAT_NRA_BOUND_MAX,
127 PARAM_MCSAT_NRA_BOUND_MIN,
128 PARAM_MCSAT_NRA_MGCD,
129 PARAM_MCSAT_NRA_NLSAT,
130 PARAM_MCSAT_VAR_ORDER,
131 PARAM_OPTIMISTIC_FCHECK,
132 PARAM_PROP_THRESHOLD,
133 PARAM_R_FACTOR,
134 PARAM_R_FRACTION,
135 PARAM_R_THRESHOLD,
136 PARAM_RANDOM_SEED,
137 PARAM_RANDOMNESS,
138 PARAM_SIMPLEX_ADJUST,
139 PARAM_SIMPLEX_PROP,
140 PARAM_TCLAUSE_SIZE,
141 PARAM_VAR_DECAY,
142 PARAM_VAR_ELIM,
143 };
144
145
146
147 /*
148 * Names of each branching mode (in lexicographic order)
149 */
150 #define NUM_BRANCHING_MODES 6
151
152 static const char * const branching_modes[NUM_BRANCHING_MODES] = {
153 "default",
154 "negative",
155 "positive",
156 "th-neg",
157 "th-pos",
158 "theory",
159 };
160
161 static const branch_t branching_code[NUM_BRANCHING_MODES] = {
162 BRANCHING_DEFAULT,
163 BRANCHING_NEGATIVE,
164 BRANCHING_POSITIVE,
165 BRANCHING_TH_NEG,
166 BRANCHING_TH_POS,
167 BRANCHING_THEORY,
168 };
169
170
171
172 /*
173 * Names of the generalization modes for the EF solver
174 */
175 #define NUM_EF_GEN_MODES 4
176
177 static const char * const ef_gen_modes[NUM_EF_GEN_MODES] = {
178 "auto",
179 "none",
180 "projection",
181 "substitution",
182 };
183
184 static const ef_gen_option_t ef_gen_code[NUM_EF_GEN_MODES] = {
185 EF_GEN_AUTO_OPTION,
186 EF_NOGEN_OPTION,
187 EF_GEN_BY_PROJ_OPTION,
188 EF_GEN_BY_SUBST_OPTION,
189 };
190
191
192 /*
193 * Tables for converting parameter id to parameter name
194 * and branching code to branching name. One more table
195 * for converting from EF generalization codes to strings.
196 */
197 const char *param2string[NUM_PARAMETERS];
198 const char *branching2string[NUM_BRANCHING_MODES];
199 const char *efgen2string[NUM_EF_GEN_MODES];
200
201
202 /*
203 * Initialize the table [parameter id --> string]
204 * and [branching mode --> string]
205 * and [ef gen code --> string]
206 */
init_parameter_name_table(void)207 void init_parameter_name_table(void) {
208 uint32_t i, j;
209 const char *name;
210
211 for (i=0; i<NUM_PARAMETERS; i++) {
212 name = param_names[i];
213 j = param_code[i];
214 param2string[j] = name;
215 }
216
217 for (i=0; i<NUM_BRANCHING_MODES; i++) {
218 name = branching_modes[i];
219 j = branching_code[i];
220 branching2string[j] = name;
221 }
222
223 for (i=0; i<NUM_EF_GEN_MODES; i++) {
224 name = ef_gen_modes[i];
225 j = ef_gen_code[i];
226 efgen2string[j] = name;
227 }
228 }
229
230
231 /*
232 * Search for a parameter of the given name
233 * - use binary search in the param_names table
234 * - return PARAM_UNKNOWN if there's no parameter with that name
235 */
find_param(const char * name)236 yices_param_t find_param(const char *name) {
237 int32_t i;
238 i = binary_search_string(name, param_names, NUM_PARAMETERS);
239 if (i >= 0) {
240 assert(i < NUM_PARAMETERS);
241 return param_code[i];
242 } else {
243 return PARAM_UNKNOWN;
244 }
245 }
246
247
248 /*
249 * Convert a parameter value to boolean, int32, float, etc.
250 * - name = parameter name, used for error reporting.
251 * - return true if the conversion works
252 * - return false otherwise and returns an error message/string in *reason
253 */
param_val_to_bool(const char * name,const param_val_t * v,bool * value,char ** reason)254 bool param_val_to_bool(const char *name, const param_val_t *v, bool *value, char **reason) {
255 bool code;
256
257 code = true;
258 if (v->tag == PARAM_VAL_FALSE) {
259 *value = false;
260 } else if (v->tag == PARAM_VAL_TRUE) {
261 *value = true;
262 } else {
263 *reason = "boolean required";
264 code = false;
265 }
266 return code;
267 }
268
param_val_to_int32(const char * name,const param_val_t * v,int32_t * value,char ** reason)269 bool param_val_to_int32(const char *name, const param_val_t *v, int32_t *value, char **reason) {
270 rational_t *q;
271
272 if (v->tag == PARAM_VAL_RATIONAL) {
273 q = v->val.rational;
274 if (q_is_smallint(q)) {
275 *value = q_get_smallint(q);
276 return true;
277 } else if (q_is_integer(q)) {
278 *reason = "integer overflow";
279 return false;
280 }
281 // if q is a rational: same error as not a number
282 }
283
284 *reason = "integer required";
285
286 return false;
287 }
288
param_val_to_pos32(const char * name,const param_val_t * v,int32_t * value,char ** reason)289 bool param_val_to_pos32(const char *name, const param_val_t *v, int32_t *value, char **reason) {
290 if (param_val_to_int32(name, v, value, reason)) {
291 if (*value > 0) return true;
292 *reason = "must be positive";
293 }
294 return false;
295 }
296
param_val_to_pos16(const char * name,const param_val_t * v,int32_t * value,char ** reason)297 bool param_val_to_pos16(const char *name, const param_val_t *v, int32_t *value, char **reason) {
298 if (param_val_to_int32(name, v, value, reason)) {
299 if (1 <= *value && *value <= UINT16_MAX) {
300 return true;
301 }
302 *reason = "must be between 1 and 2^16";
303 }
304 return false;
305 }
306
param_val_to_nonneg32(const char * name,const param_val_t * v,int32_t * value,char ** reason)307 bool param_val_to_nonneg32(const char *name, const param_val_t *v, int32_t *value, char **reason) {
308 if (param_val_to_int32(name, v, value, reason)) {
309 if (*value >= 0) return true;
310 *reason = "cannot be negative";
311 }
312 return false;
313 }
314
param_val_to_float(const char * name,const param_val_t * v,double * value,char ** reason)315 bool param_val_to_float(const char *name, const param_val_t *v, double *value, char **reason) {
316 mpq_t aux;
317
318 if (v->tag == PARAM_VAL_RATIONAL) {
319 mpq_init(aux);
320 q_get_mpq(v->val.rational, aux);
321 /*
322 * NOTE: the GMP documentation says that conversion to double
323 * may raise a hardware trap (overflow, underflow, etc.) on
324 * some systems. We ignore this here.
325 */
326 *value = mpq_get_d(aux);
327 mpq_clear(aux);
328 return true;
329 } else {
330 *reason = "number required";
331 return false;
332 }
333 }
334
param_val_to_posfloat(const char * name,const param_val_t * v,double * value,char ** reason)335 bool param_val_to_posfloat(const char *name, const param_val_t *v, double *value, char **reason) {
336 if (param_val_to_float(name, v, value, reason)) {
337 if (*value > 0.0) return true;
338 *reason = "must be positive";
339 }
340 return false;
341 }
342
343 // ratio: number between 0 and 1 (inclusive)
param_val_to_ratio(const char * name,const param_val_t * v,double * value,char ** reason)344 bool param_val_to_ratio(const char *name, const param_val_t *v, double *value, char **reason) {
345 if (param_val_to_float(name, v, value, reason)) {
346 if (0 <= *value && *value <= 1.0) return true;
347 *reason = "must be between 0 and 1";
348 }
349 return false;
350 }
351
352 // factor: must be at least 1
param_val_to_factor(const char * name,const param_val_t * v,double * value,char ** reason)353 bool param_val_to_factor(const char *name, const param_val_t *v, double *value, char **reason) {
354 if (param_val_to_float(name, v, value, reason)) {
355 if (1.0 <= *value) return true;
356 *reason = "must be at least 1";
357 }
358 return false;
359 }
360
361 // terms
param_val_to_terms(const char * name,const param_val_t * v,ivector_t ** value,char ** reason)362 bool param_val_to_terms(const char *name, const param_val_t *v, ivector_t **value, char **reason) {
363 if (v->tag == PARAM_VAL_TERMS) {
364 *value = v->val.terms;
365 return true;
366 }
367 *reason = "list of variables required";
368 return false;
369 }
370
371 /*
372 * Special case: branching mode
373 * - allowed modes are 'default' 'positive' 'negative' 'theory' 'th-neg' 'th-pos'
374 */
param_val_to_branching(const char * name,const param_val_t * v,branch_t * value,char ** reason)375 bool param_val_to_branching(const char *name, const param_val_t *v, branch_t *value, char **reason) {
376 int32_t i;
377
378 if (v->tag == PARAM_VAL_SYMBOL) {
379 i = binary_search_string(v->val.symbol, branching_modes, NUM_BRANCHING_MODES);
380 if (i >= 0) {
381 assert(i < NUM_BRANCHING_MODES);
382 *value = branching_code[i];
383 return true;
384 }
385 }
386 *reason = "must be one of 'default' 'positive' 'negative' 'theory' 'th-neg' 'th-pos";
387
388 return false;
389 }
390
391
392
393 /*
394 * EF generalization mode
395 * - allowed modes are "none" or "substitution" or "projection" or "auto"
396 * - we use a general implementation so that we can add more modes later
397 */
param_val_to_genmode(const char * name,const param_val_t * v,ef_gen_option_t * value,char ** reason)398 bool param_val_to_genmode(const char *name, const param_val_t *v, ef_gen_option_t *value, char **reason) {
399 int32_t i;
400
401 if (v->tag == PARAM_VAL_SYMBOL) {
402 i = binary_search_string(v->val.symbol, ef_gen_modes, NUM_EF_GEN_MODES);
403 if (i >= 0) {
404 assert(i < NUM_EF_GEN_MODES);
405 *value = ef_gen_code[i];
406 return true;
407 }
408 }
409 *reason = "must be one of 'none' 'substitution' 'projection' 'auto'";
410
411 return false;
412 }
413
414