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