rsmt2/
conf.rs

1//! Solver configuration, contains backend-solver-specific info.
2//!
3//! Do **NOT** use wildcards when matching over `SmtStyle`. We want the code to fail to compile
4//! whenever we add a solver. Likewise, do not use `if let` with `SmtStyle`.
5//!
6//! Note that the command for each solver can be passed through environment variables, see
7//! - [`Z3_ENV_VAR`],
8//! - [`CVC4_ENV_VAR`],
9//! - [`YICES_2_ENV_VAR`], and
10//! - the [`SmtConf::z3_or_env`], [`SmtConf::cvc4_or_env`], and [`SmtConf::yices_2_or_env`]
11//!   constructors.
12
13use std::fmt;
14
15use crate::{SmtRes, Solver};
16
17use self::SmtStyle::*;
18
19/// A configuration item is either a keyword or unsupported.
20pub type ConfItem = Option<&'static str>;
21
22/// Value of an unsupported configuration item.
23#[inline]
24fn unsupported() -> ConfItem {
25    None
26}
27/// Keyword for a configuration item.
28#[inline]
29fn supported(keyword: &'static str) -> ConfItem {
30    Some(keyword)
31}
32
33/// Environment variable providing the command for z3.
34pub const Z3_ENV_VAR: &str = "RSMT2_Z3_CMD";
35/// Environment variable providing the command for CVC4.
36pub const CVC4_ENV_VAR: &str = "RSMT2_CVC4_CMD";
37/// Environment variable providing the command for Yices 2.
38pub const YICES_2_ENV_VAR: &str = "RSMT2_YICES_2_CMD";
39
40/// Retrieves the value of an environment variable.
41fn get_env_var(env_var: &str) -> SmtRes<Option<String>> {
42    match std::env::var(env_var) {
43        Ok(res) => Ok(Some(res)),
44        Err(std::env::VarError::NotPresent) => Ok(None),
45        Err(std::env::VarError::NotUnicode(cmd)) => bail!(
46            "value of environment variable `{}` is not legal unicode: `{}`",
47            env_var,
48            cmd.to_string_lossy(),
49        ),
50    }
51}
52
53/// Solver styles.
54///
55/// - [z3][z3]: full support
56/// - [cvc4][cvc4]: full support in theory, but only partially tested. Note that `get-value` is
57///   known to crash some versions of CVC4.
58/// - [yices 2][yices 2]: full support in theory, but only partially tested. Command `get-model`
59///   will only work on Yices 2 > `2.6.1`, and needs to be activated in [`SmtConf`] with
60///   [`SmtConf::models`]. To understand why, see <https://github.com/SRI-CSL/yices2/issues/162>.
61///   
62/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
63/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
64/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66#[allow(dead_code)]
67pub enum SmtStyle {
68    /// Z3-style smt solver.
69    Z3,
70    /// CVC4-style smt solver.
71    ///
72    /// **NB**: CVC4 has only been partially tested at this point.
73    CVC4,
74    /// Yices-2-style smt solver.
75    ///
76    /// **NB**: Yices 2 has only been partially tested at this point.
77    Yices2,
78}
79
80impl SmtStyle {
81    /// Configuration constructor.
82    pub fn new(self, cmd: impl Into<String>) -> SmtConf {
83        let cmd = cmd.into();
84        match self {
85            Z3 => SmtConf {
86                style: self,
87                cmd,
88                options: vec!["-in".into(), "-smt2".into()],
89                models: true,
90                incremental: true,
91                check_success: false,
92                unsat_cores: false,
93                interpolants: true,
94                check_sat_assuming: supported("check-sat-assuming"),
95            },
96            CVC4 => SmtConf {
97                style: self,
98                cmd,
99                options: vec![
100                    "-q".into(),
101                    "--no-interactive".into(),
102                    "--lang".into(),
103                    "smt2".into(),
104                ],
105                models: false,
106                incremental: false,
107                check_success: false,
108                unsat_cores: false,
109                interpolants: false,
110                check_sat_assuming: unsupported(),
111            },
112            Yices2 => SmtConf {
113                style: self,
114                cmd,
115                options: vec![],
116                models: false,
117                incremental: false,
118                check_success: false,
119                unsat_cores: false,
120                interpolants: false,
121                check_sat_assuming: supported("check-sat-assuming"),
122            },
123        }
124    }
125
126    /// Default configuration for a solver style.
127    ///
128    /// # Warning
129    ///
130    /// The command used to run a particular solver is up to the end-user. As such, it **does not
131    /// make sense** to use default commands for anything else than local testing. You should
132    /// explicitely pass the command to use with [`Self::new`] instead.
133    pub fn default(self) -> SmtConf {
134        self.new(self.cmd())
135    }
136
137    /// A solver style from a string.
138    #[allow(dead_code)]
139    pub fn of_str(s: &str) -> Option<Self> {
140        match s {
141            "z3" | "Z3" => Some(Z3),
142            "cvc4" | "CVC4" => Some(CVC4),
143            "Yices2" | "yices2" | "YICES2" | "Yices 2" | "yices 2" | "YICES 2" => Some(Yices2),
144            _ => None,
145        }
146    }
147    /// Legal string representations of solver styles.
148    #[allow(dead_code)]
149    pub fn str_keys() -> Vec<&'static str> {
150        vec![
151            "z3", "Z3", "cvc4", "CVC4", "Yices2", "yices2", "YICES2", "Yices 2", "yices 2",
152            "YICES 2",
153        ]
154    }
155
156    /// Solver style command from the corresponding environment variable.
157    ///
158    /// The environement variables scanned are [`Z3_ENV_VAR`], [`CVC4_ENV_VAR`] and
159    /// [`YICES_2_ENV_VAR`].
160    pub fn env_cmd(self) -> SmtRes<Option<String>> {
161        match self {
162            Z3 => get_env_var(Z3_ENV_VAR),
163            CVC4 => get_env_var(CVC4_ENV_VAR),
164            Yices2 => get_env_var(YICES_2_ENV_VAR),
165        }
166    }
167
168    /// Default command for a solver style.
169    #[cfg(not(windows))]
170    pub fn cmd(self) -> &'static str {
171        match self {
172            Z3 => "z3",
173            CVC4 => "cvc4",
174            Yices2 => "yices",
175        }
176    }
177    /// Default command for a solver style.
178    #[cfg(windows)]
179    pub fn cmd(self) -> &'static str {
180        match self {
181            Z3 => "z3.exe",
182            CVC4 => "cvc4.exe",
183            Yices2 => "yices.exe",
184        }
185    }
186
187    /// True if `self` is [`Self::Z3`].
188    pub fn is_z3(self) -> bool {
189        self == Self::Z3
190    }
191}
192
193impl fmt::Display for SmtStyle {
194    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
195        match *self {
196            Z3 => write!(fmt, "z3"),
197            CVC4 => write!(fmt, "cvc4"),
198            Yices2 => write!(fmt, "yices2"),
199        }
200    }
201}
202
203/// Configuration and solver specific info.
204///
205/// - [z3]: full support
206/// - [cvc4]: full support in theory, but only partially tested. Note that `get-value` is
207///   known to crash some versions of CVC4.
208/// - [yices 2]: full support in theory, but only partially tested. Command `get-model`
209///   will only work on Yices 2 > `2.6.1`, and needs to be activated with [`Self::models`]. To
210///   understand why, see <https://github.com/SRI-CSL/yices2/issues/162>.
211///   
212/// [z3]: https://github.com/Z3Prover/z3 (z3 github repository)
213/// [cvc4]: https://cvc4.github.io/ (cvc4 github pages)
214/// [yices 2]: https://yices.csl.sri.com/ (yices 2 official page)
215#[derive(Debug, Clone)]
216pub struct SmtConf {
217    /// Solver style.
218    style: SmtStyle,
219    /// Solver command.
220    cmd: String,
221    /// Options to call the solver with.
222    options: Vec<String>,
223    /// Model production.
224    models: bool,
225    /// Incrementality.
226    incremental: bool,
227    /// Parse success.
228    check_success: bool,
229    /// Triggers unsat-core production.
230    unsat_cores: bool,
231    /// Triggers interpolant production.
232    interpolants: bool,
233    /// Keyword for check-sat with assumptions.
234    check_sat_assuming: ConfItem,
235}
236
237impl SmtConf {
238    /// Solver style accessor.
239    pub fn style(&self) -> SmtStyle {
240        self.style
241    }
242
243    /// Creates a new z3-like solver configuration.
244    ///
245    /// # Examples
246    ///
247    /// ```rust
248    /// # use rsmt2::SmtConf;
249    /// let conf = SmtConf::z3("my_z3_command");
250    /// assert!(conf.get_cmd() == "my_z3_command")
251    /// ```
252    #[inline]
253    pub fn z3(cmd: impl Into<String>) -> Self {
254        Z3.new(cmd)
255    }
256
257    /// Creates a new cvc4-like solver configuration.
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// # use rsmt2::SmtConf;
263    /// let conf = SmtConf::cvc4("my_cvc4_command");
264    /// assert!(conf.get_cmd() == "my_cvc4_command")
265    /// ```
266    #[inline]
267    pub fn cvc4(cmd: impl Into<String>) -> Self {
268        CVC4.new(cmd)
269    }
270
271    /// Creates a new yices-2-like solver configuration.
272    ///
273    /// # Examples
274    ///
275    /// ```rust
276    /// # use rsmt2::SmtConf;
277    /// let conf = SmtConf::yices_2("my_yices_2_command");
278    /// assert!(conf.get_cmd() == "my_yices_2_command")
279    /// ```
280    #[inline]
281    pub fn yices_2(cmd: impl Into<String>) -> Self {
282        Yices2.new(cmd)
283    }
284
285    /// Creates a z3-like solver configuration from an optional, or the value of the [`Z3_ENV_VAR`]
286    /// environment variable.
287    ///
288    /// Fails if `cmd.is_none()` and [`Z3_ENV_VAR`] is not set.
289    ///
290    /// ```rust
291    /// use rsmt2::conf::{SmtConf, Z3_ENV_VAR};
292    /// use std::env::{set_var, var_os};
293    ///
294    /// // Passes the command directly.
295    /// let cmd = "z3_explicit";
296    /// let explicit_cmd = SmtConf::z3_or_env(Some(cmd.into())).expect("explicit");
297    /// assert_eq!(explicit_cmd.get_cmd(), cmd);
298    ///
299    /// // Error if no command + environment variable not set.
300    /// assert_eq!(var_os(Z3_ENV_VAR), None);
301    /// let error = SmtConf::z3_or_env(None);
302    /// match error {
303    ///     Ok(_) => panic!("expected error, got an SMT style"),
304    ///     Err(e) => assert_eq!(
305    ///         &e.to_string(),
306    ///         "no command for z3 provided, \
307    ///         and `RSMT2_Z3_CMD` environment variable not set; \
308    ///         cannot spawn z3 solver"
309    ///     ),
310    /// }
311    ///
312    /// // Retrieves the command from the environment.
313    /// let cmd = "z3_implicit";
314    /// assert_eq!(Z3_ENV_VAR, "RSMT2_Z3_CMD");
315    /// set_var(Z3_ENV_VAR, cmd);
316    /// let implicit_cmd = SmtConf::z3_or_env(None).expect("implicit");
317    /// assert_eq!(implicit_cmd.get_cmd(), cmd);
318    /// ```
319    #[inline]
320    pub fn z3_or_env(cmd: Option<String>) -> SmtRes<Self> {
321        if let Some(cmd) = cmd {
322            Ok(Self::z3(cmd))
323        } else {
324            let cmd = SmtStyle::Z3.env_cmd()?;
325            if let Some(cmd) = cmd {
326                Ok(Self::z3(cmd))
327            } else {
328                bail!(
329                    "no command for z3 provided, \
330                    and `{}` environment variable not set; cannot spawn z3 solver",
331                    Z3_ENV_VAR,
332                )
333            }
334        }
335    }
336
337    /// Creates a CVC4-like solver configuration from an optional, or the value of the
338    /// [`CVC4_ENV_VAR`] environment variable.
339    ///
340    /// Fails if `cmd.is_none()` and [`CVC4_ENV_VAR`] is not set.
341    ///
342    /// ```rust
343    /// use rsmt2::conf::{SmtConf, CVC4_ENV_VAR};
344    /// use std::env::{set_var, var_os};
345    ///
346    /// // Passes the command directly.
347    /// let cmd = "cvc4_explicit";
348    /// let explicit_cmd = SmtConf::cvc4_or_env(Some(cmd.into())).expect("explicit");
349    /// assert_eq!(explicit_cmd.get_cmd(), cmd);
350    ///
351    /// // Error if no command + environment variable not set.
352    /// assert_eq!(var_os(CVC4_ENV_VAR), None);
353    /// let error = SmtConf::cvc4_or_env(None);
354    /// match error {
355    ///     Ok(_) => panic!("expected error, got an SMT style"),
356    ///     Err(e) => assert_eq!(
357    ///         &e.to_string(),
358    ///         "no command for CVC4 provided, \
359    ///         and `RSMT2_CVC4_CMD` environment variable not set; \
360    ///         cannot spawn CVC4 solver"
361    ///     ),
362    /// }
363    ///
364    /// // Retrieves the command from the environment.
365    /// let cmd = "cvc4_implicit";
366    /// assert_eq!(CVC4_ENV_VAR, "RSMT2_CVC4_CMD");
367    /// set_var(CVC4_ENV_VAR, cmd);
368    /// let implicit_cmd = SmtConf::cvc4_or_env(None).expect("implicit");
369    /// assert_eq!(implicit_cmd.get_cmd(), cmd);
370    /// ```
371    #[inline]
372    pub fn cvc4_or_env(cmd: Option<String>) -> SmtRes<Self> {
373        if let Some(cmd) = cmd {
374            Ok(Self::cvc4(cmd))
375        } else {
376            let cmd = SmtStyle::CVC4.env_cmd()?;
377            if let Some(cmd) = cmd {
378                Ok(Self::cvc4(cmd))
379            } else {
380                bail!(
381                    "no command for CVC4 provided, \
382                    and `{}` environment variable not set; cannot spawn CVC4 solver",
383                    CVC4_ENV_VAR,
384                )
385            }
386        }
387    }
388
389    /// Creates a Yices-2-like solver configuration from an optional, or the value of the
390    /// [`YICES_2_ENV_VAR`] environment variable.
391    ///
392    /// Fails if `cmd.is_none()` and [`YICES_2_ENV_VAR`] is not set.
393    ///
394    /// ```rust
395    /// use rsmt2::conf::{SmtConf, YICES_2_ENV_VAR};
396    /// use std::env::{set_var, var_os};
397    ///
398    /// // Passes the command directly.
399    /// let cmd = "yices_2_explicit";
400    /// let explicit_cmd = SmtConf::yices_2_or_env(Some(cmd.into())).expect("explicit");
401    /// assert_eq!(explicit_cmd.get_cmd(), cmd);
402    ///
403    /// // Error if no command + environment variable not set.
404    /// assert_eq!(var_os(YICES_2_ENV_VAR), None);
405    /// let error = SmtConf::yices_2_or_env(None);
406    /// match error {
407    ///     Ok(_) => panic!("expected error, got an SMT style"),
408    ///     Err(e) => assert_eq!(
409    ///         &e.to_string(),
410    ///         "no command for Yices 2 provided, \
411    ///         and `RSMT2_YICES_2_CMD` environment variable not set; \
412    ///         cannot spawn Yices 2 solver"
413    ///     ),
414    /// }
415    ///
416    /// // Retrieves the command from the environment.
417    /// let cmd = "yices_2_implicit";
418    /// assert_eq!(YICES_2_ENV_VAR, "RSMT2_YICES_2_CMD");
419    /// set_var(YICES_2_ENV_VAR, cmd);
420    /// let implicit_cmd = SmtConf::yices_2_or_env(None).expect("implicit");
421    /// assert_eq!(implicit_cmd.get_cmd(), cmd);
422    /// ```
423    #[inline]
424    pub fn yices_2_or_env(cmd: Option<String>) -> SmtRes<Self> {
425        if let Some(cmd) = cmd {
426            Ok(Self::yices_2(cmd))
427        } else {
428            let cmd = SmtStyle::Yices2.env_cmd()?;
429            if let Some(cmd) = cmd {
430                Ok(Self::yices_2(cmd))
431            } else {
432                bail!(
433                    "no command for Yices 2 provided, \
434                    and `{}` environment variable not set; cannot spawn Yices 2 solver",
435                    YICES_2_ENV_VAR,
436                )
437            }
438        }
439    }
440
441    /// Creates a new z3-like solver configuration and command.
442    ///
443    /// # Warning
444    ///
445    /// The command used to run a particular solver is up to the end-user. As such, it **does not
446    /// make sense** to use default commands for anything else than local testing. You should
447    /// explicitely pass the command to use with [`Self::z3`] instead.
448    ///
449    /// # Examples
450    ///
451    /// ```rust
452    /// # use rsmt2::SmtConf;
453    /// let conf = SmtConf::default_z3();
454    /// assert! {
455    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
456    /// }
457    /// ```
458    #[inline]
459    pub fn default_z3() -> Self {
460        Z3.default()
461    }
462
463    /// Creates a new cvc4-like solver configuration and command.
464    ///
465    /// # Warning
466    ///
467    /// The command used to run a particular solver is up to the end-user. As such, it **does not
468    /// make sense** to use default commands for anything else than local testing. You should
469    /// explicitely pass the command to use with [`Self::cvc4`] instead.
470    ///
471    /// # Examples
472    ///
473    /// ```rust
474    /// # use rsmt2::SmtConf;
475    /// let conf = SmtConf::default_cvc4();
476    /// assert! {
477    ///     conf.get_cmd() == "cvc4" || conf.get_cmd() == "cvc4.exe"
478    /// }
479    /// ```
480    #[inline]
481    pub fn default_cvc4() -> Self {
482        CVC4.default()
483    }
484
485    /// Creates a new yices-2-like solver configuration and command.
486    ///
487    /// # Warning
488    ///
489    /// The command used to run a particular solver is up to the end-user. As such, it **does not
490    /// make sense** to use default commands for anything else than local testing. You should
491    /// explicitely pass the command to use with [`Self::yices_2`] instead.
492    ///
493    /// # Examples
494    ///
495    /// ```rust
496    /// # use rsmt2::SmtConf;
497    /// let conf = SmtConf::default_yices_2();
498    /// assert! {
499    ///     conf.get_cmd() == "yices" || conf.get_cmd() == "yices.exe"
500    /// }
501    /// ```
502    #[inline]
503    pub fn default_yices_2() -> Self {
504        Yices2.default()
505    }
506
507    /// Spawns the solver.
508    ///
509    /// # Examples
510    ///
511    /// ```rust
512    /// # use rsmt2::SmtConf;
513    /// let _solver = SmtConf::default_z3().spawn(()).unwrap();
514    /// ```
515    #[inline]
516    pub fn spawn<Parser>(self, parser: Parser) -> SmtRes<Solver<Parser>> {
517        Solver::new(self, parser)
518    }
519
520    /// Concise description of the underlying solver.
521    ///
522    /// # Examples
523    ///
524    /// ```rust
525    /// # use rsmt2::SmtConf;
526    /// assert_eq! { SmtConf::default_z3().desc(), "z3" }
527    /// ```
528    #[inline]
529    pub fn desc(&self) -> &str {
530        match self.style {
531            Z3 => "z3",
532            CVC4 => "cvc4",
533            Yices2 => "yices2",
534        }
535    }
536
537    /// Solver command.
538    ///
539    /// # Examples
540    ///
541    /// ```rust
542    /// # use rsmt2::SmtConf;
543    /// let conf = SmtConf::default_z3();
544    /// assert! {
545    ///     conf.get_cmd() == "z3" || conf.get_cmd() == "z3.exe"
546    /// }
547    /// ```
548    #[inline]
549    pub fn get_cmd(&self) -> &str {
550        &self.cmd
551    }
552
553    /// Options of the configuration.
554    ///
555    /// # Examples
556    ///
557    /// ```rust
558    /// # use rsmt2::SmtConf;
559    /// assert_eq! {
560    ///     SmtConf::default_z3().get_options(), & [ "-in", "-smt2" ]
561    /// }
562    /// ```
563    #[inline]
564    pub fn get_options(&self) -> &[String] {
565        &self.options
566    }
567
568    /// Adds an option to the configuration.
569    ///
570    /// # Examples
571    ///
572    /// ```rust
573    /// # use rsmt2::SmtConf;
574    /// let mut conf = SmtConf::default_z3();
575    /// conf.option("arith.euclidean_solver=true");
576    /// assert_eq! {
577    ///     conf.get_options(),
578    ///     & [ "-in", "-smt2", "arith.euclidean_solver=true" ]
579    /// }
580    /// ```
581    #[inline]
582    pub fn option<S: Into<String>>(&mut self, o: S) -> &mut Self {
583        self.options.push(o.into());
584        self
585    }
586
587    /// Sets the command for the solver.
588    ///
589    /// # Examples
590    ///
591    /// ```rust
592    /// # use rsmt2::SmtConf;
593    /// let mut conf = SmtConf::default_z3();
594    /// conf.cmd("my_custom_z3_command");
595    /// assert_eq! { conf.get_cmd(), "my_custom_z3_command" }
596    /// ```
597    #[inline]
598    pub fn cmd<S: Into<String>>(&mut self, cmd: S) -> &mut Self {
599        let cmd = cmd.into();
600        let mut iter = cmd.split(' ');
601
602        'set_cmd: while let Some(cmd) = iter.next() {
603            if !cmd.is_empty() {
604                self.cmd = cmd.into();
605                break 'set_cmd;
606            }
607        }
608
609        for option in iter {
610            if !option.is_empty() {
611                self.options.push(option.into())
612            }
613        }
614
615        self
616    }
617
618    /// Model production flag.
619    ///
620    /// # Examples
621    ///
622    /// ```rust
623    /// # use rsmt2::SmtConf;
624    /// assert!(SmtConf::default_z3().get_models());
625    /// ```
626    pub fn get_models(&self) -> bool {
627        self.models
628    }
629    /// Activates model production.
630    ///
631    /// # Examples
632    ///
633    /// ```rust
634    /// # use rsmt2::SmtConf;
635    /// let mut conf = SmtConf::default_z3();
636    /// conf.models();
637    /// assert!(conf.get_models());
638    /// ```
639    pub fn models(&mut self) {
640        self.set_models(true)
641    }
642    /// (De)activates model production.
643    ///
644    /// # Examples
645    ///
646    /// ```rust
647    /// # use rsmt2::SmtConf;
648    /// let mut conf = SmtConf::default_z3();
649    /// conf.set_models(false);
650    /// assert!(!conf.get_models());
651    /// ```
652    pub fn set_models(&mut self, val: bool) {
653        self.models = val;
654        if val {
655            match self.style {
656                CVC4 => self.options.push("--produce-models".into()),
657                Yices2 => self.options.push("--smt2-model-format".into()),
658                Z3 => (),
659            }
660        }
661    }
662
663    /// Incrementality.
664    ///
665    /// # Examples
666    ///
667    /// ```rust
668    /// # use rsmt2::SmtConf;
669    /// let mut conf = SmtConf::default_z3();
670    /// assert!(conf.get_incremental());
671    /// ```
672    pub fn get_incremental(&self) -> bool {
673        self.incremental
674    }
675    /// Activates incrementality (push/pop, check-sat-assuming).
676    ///
677    /// # Examples
678    ///
679    /// ```rust
680    /// # use rsmt2::SmtConf;
681    /// let mut conf = SmtConf::default_z3();
682    /// conf.incremental();
683    /// assert!(conf.get_incremental());
684    /// ```
685    pub fn incremental(&mut self) {
686        self.set_incremental(true)
687    }
688    /// Activates incrementality (push/pop, check-sat-assuming).
689    ///
690    /// # Examples
691    ///
692    /// ```rust
693    /// # use rsmt2::SmtConf;
694    /// let mut conf = SmtConf::default_z3();
695    /// conf.incremental();
696    /// assert!(conf.get_incremental());
697    /// ```
698    pub fn set_incremental(&mut self, val: bool) {
699        self.incremental = val;
700        if val {
701            match self.style {
702                CVC4 | Yices2 => self.options.push("--incremental".into()),
703                Z3 => (),
704            }
705        }
706    }
707
708    /// Indicates if unsat core production is active.
709    ///
710    /// # Examples
711    ///
712    /// ```rust
713    /// # use rsmt2::SmtConf;
714    /// assert!(! SmtConf::default_z3().get_unsat_cores());
715    /// ```
716    #[inline]
717    pub fn get_unsat_cores(&self) -> bool {
718        self.unsat_cores
719    }
720    /// Activates unsat core production.
721    ///
722    /// # Examples
723    ///
724    /// ```rust
725    /// # use rsmt2::SmtConf;
726    /// let mut conf = SmtConf::default_z3();
727    /// conf.unsat_cores();
728    /// assert!(conf.get_unsat_cores());
729    /// ```
730    #[inline]
731    pub fn unsat_cores(&mut self) {
732        self.set_unsat_cores(true)
733    }
734    /// (De)activates unsat core production.
735    ///
736    /// # Examples
737    ///
738    /// ```rust
739    /// # use rsmt2::SmtConf;
740    /// let mut conf = SmtConf::default_z3();
741    /// conf.set_unsat_cores(false);
742    /// assert!(!conf.get_unsat_cores());
743    /// ```
744    #[inline]
745    pub fn set_unsat_cores(&mut self, val: bool) {
746        self.unsat_cores = val
747    }
748
749    /// Keyword for check-sat with assumptions.
750    ///
751    /// # Examples
752    ///
753    /// ```rust
754    /// # use rsmt2::SmtConf;
755    /// assert_eq! {
756    ///     SmtConf::default_z3().get_check_sat_assuming(), Some("check-sat-assuming")
757    /// }
758    /// ```
759    #[inline]
760    pub fn get_check_sat_assuming(&self) -> ConfItem {
761        self.check_sat_assuming.as_ref().map(|s| *s)
762    }
763
764    /// Indicates if success-checking is active, see [`Solver`](crate::Solver#check-success).
765    ///
766    /// # Examples
767    ///
768    /// ```rust
769    /// # use rsmt2::SmtConf;
770    /// assert!(! SmtConf::default_z3().get_check_success());
771    /// ```
772    #[inline]
773    pub fn get_check_success(&self) -> bool {
774        self.check_success
775    }
776    /// Activates success-checking, see [`Solver`](crate::Solver#check-success).
777    ///
778    /// # Examples
779    ///
780    /// ```rust
781    /// # use rsmt2::SmtConf;
782    /// let mut conf = SmtConf::default_z3();
783    /// conf.check_success();
784    /// assert!(conf.get_check_success());
785    /// ```
786    #[inline]
787    pub fn check_success(&mut self) {
788        self.set_check_success(true)
789    }
790    /// (De)activates sucess-checking, see [`Solver`](crate::Solver#check-success).
791    ///
792    /// # Examples
793    ///
794    /// ```rust
795    /// # use rsmt2::SmtConf;
796    /// let mut conf = SmtConf::default_z3();
797    /// conf.set_check_success(true);
798    /// assert!(conf.get_check_success());
799    /// ```
800    #[inline]
801    pub fn set_check_success(&mut self, val: bool) {
802        self.check_success = val
803    }
804
805    /// Indicates if interpolant production is active.
806    ///
807    /// # Examples
808    ///
809    /// ```rust
810    /// # use rsmt2::SmtConf;
811    /// assert!(SmtConf::default_z3().get_interpolants());
812    /// ```
813    #[inline]
814    pub fn get_interpolants(&self) -> bool {
815        self.interpolants
816    }
817    /// Activates interpolant production.
818    ///
819    /// # Examples
820    ///
821    /// ```rust
822    /// # use rsmt2::SmtConf;
823    /// let mut conf = SmtConf::default_z3();
824    /// conf.interpolants();
825    /// assert!(conf.get_interpolants());
826    /// ```
827    #[inline]
828    pub fn interpolants(&mut self) -> SmtRes<()> {
829        self.set_interpolants(true)
830    }
831    /// (De)activates interpolant production.
832    ///
833    /// # Examples
834    ///
835    /// ```rust
836    /// # use rsmt2::SmtConf;
837    /// let mut conf = SmtConf::default_z3();
838    /// conf.set_interpolants(false);
839    /// assert!(!conf.get_interpolants());
840    /// ```
841    #[inline]
842    pub fn set_interpolants(&mut self, val: bool) -> SmtRes<()> {
843        if self.style.is_z3() {
844            self.interpolants = val;
845            Ok(())
846        } else {
847            bail!(
848                "interpolant production is only supported by Z3, \
849                cannot activate interpolants for `{}`",
850                self.style,
851            )
852        }
853    }
854}
855
856/// ## Solver-specific error-handling
857impl SmtConf {
858    /// Adds information to a `get-value` error message if needed.
859    pub fn enrich_get_values_error(&self, e: crate::errors::Error) -> crate::errors::Error {
860        match self.style {
861            SmtStyle::CVC4 => e.chain_err(|| {
862                "some versions of CVC4 produce errors on `get-value` commands, \
863                 consider using `get-model` instead"
864            }),
865            SmtStyle::Z3 | SmtStyle::Yices2 => e,
866        }
867    }
868}