Skip to content

Commit fde32b3

Browse files
committed
Add documentation to src/chc.rs
1 parent d3ec658 commit fde32b3

1 file changed

Lines changed: 75 additions & 2 deletions

File tree

src/chc.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
/// Multi-sorted CHC system with tuples.
1+
//! A multi-sorted CHC system with tuples.
2+
23
use pretty::{termcolor, Pretty};
34
use rustc_index::IndexVec;
45

@@ -17,6 +18,7 @@ pub use debug::DebugInfo;
1718
pub use solver::{CheckSatError, Config};
1819
pub use unbox::unbox;
1920

21+
/// A name of a datatype.
2022
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2123
pub struct DatatypeSymbol {
2224
inner: String,
@@ -43,6 +45,10 @@ impl DatatypeSymbol {
4345
}
4446
}
4547

48+
/// A datatype sort.
49+
///
50+
/// A datatype sort is a sort that is defined by a datatype. It has a symbol and a list of
51+
/// argument sorts.
4652
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4753
pub struct DatatypeSort {
4854
symbol: DatatypeSymbol,
@@ -74,6 +80,7 @@ impl DatatypeSort {
7480
}
7581
}
7682

83+
/// A sort is the type of a logical term.
7784
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
7885
pub enum Sort {
7986
Null,
@@ -271,6 +278,10 @@ impl Sort {
271278
}
272279

273280
rustc_index::newtype_index! {
281+
/// An index representing term-level variable.
282+
///
283+
/// We manage term-level variables using indices that are unique in each clause.
284+
/// [`Clause`] contains `IndexVec<TermVarIdx, Sort>` that manages the indices and the sorts of the variables.
274285
#[orderable]
275286
#[debug_format = "v{}"]
276287
pub struct TermVarIdx { }
@@ -297,6 +308,7 @@ impl TermVarIdx {
297308
}
298309
}
299310

311+
/// A known function symbol.
300312
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
301313
pub struct Function {
302314
name: &'static str,
@@ -376,6 +388,7 @@ impl Function {
376388
pub const NEG: Function = Function::new("-");
377389
}
378390

391+
/// A logical term.
379392
#[derive(Debug, Clone)]
380393
pub enum Term<V = TermVarIdx> {
381394
Null,
@@ -693,6 +706,11 @@ impl<V> Term<V> {
693706
}
694707

695708
rustc_index::newtype_index! {
709+
/// An index representing predicate variables.
710+
///
711+
/// We manage predicate variables using indices that are unique in a CHC system.
712+
/// [`System`] contains `IndexVec<PredVarId, PredVarDef>` that manages the indices
713+
/// and signatures of the predicate variables.
696714
#[debug_format = "p{}"]
697715
pub struct PredVarId { }
698716
}
@@ -720,6 +738,9 @@ impl PredVarId {
720738
}
721739
}
722740

741+
/// A known predicate.
742+
///
743+
/// A known predicate is a predicate that has a fixed meaning, such as `true`, `false`, `=`, etc.
723744
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
724745
pub struct KnownPred {
725746
name: &'static str,
@@ -804,6 +825,25 @@ impl KnownPred {
804825
pub const GREATER_THAN: KnownPred = KnownPred::infix(">");
805826
}
806827

828+
/// A matcher predicate.
829+
///
830+
/// A matcher predicate is a predicate that relates a value of a datatype with its contents.
831+
/// For example, given the following `enum` datatype:
832+
///
833+
/// ```rust
834+
/// pub enum X {
835+
/// A(i64),
836+
/// B(bool),
837+
/// }
838+
/// ```
839+
///
840+
/// The corresponding matcher predicate is defined as:
841+
///
842+
/// ```smtlib2
843+
/// (define-fun matcher_pred<X> ((x0 Int) (x1 Bool) (v X)) Bool (or (= v (X.A x0)) (= v (X.B x1))))
844+
/// ```
845+
///
846+
/// See the implementation in the [`smtlib2`] module for the details.
807847
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
808848
pub struct MatcherPred {
809849
datatype_symbol: DatatypeSymbol,
@@ -851,6 +891,7 @@ impl MatcherPred {
851891
}
852892
}
853893

894+
/// A predicate.
854895
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
855896
pub enum Pred {
856897
Known(KnownPred),
@@ -942,6 +983,7 @@ impl Pred {
942983
}
943984
}
944985

986+
/// An atom is a predicate applied to a list of terms.
945987
#[derive(Debug, Clone)]
946988
pub struct Atom<V = TermVarIdx> {
947989
pub pred: Pred,
@@ -1030,6 +1072,11 @@ impl<V> Atom<V> {
10301072
}
10311073
}
10321074

1075+
/// An arbitrary formula built with atoms and logical connectives.
1076+
///
1077+
/// While it allows arbitrary [`Atom`] in its `Atom` variant, we only expect atoms with known
1078+
/// predicates (i.e., predicates other than `Pred::Var`) to appear in formulas. It is our TODO to
1079+
/// enforce this restriction statically. Also see the definition of [`Body`].
10331080
#[derive(Debug, Clone)]
10341081
pub enum Formula<V = TermVarIdx> {
10351082
Atom(Atom<V>),
@@ -1248,10 +1295,11 @@ impl<V> Formula<V> {
12481295
}
12491296
}
12501297

1298+
/// The body part of a clause, consisting of atoms and a formula.
12511299
#[derive(Debug, Clone)]
12521300
pub struct Body<V = TermVarIdx> {
12531301
pub atoms: Vec<Atom<V>>,
1254-
// `formula` doesn't contain PredVar
1302+
/// NOTE: This doesn't contain predicate variables. Also see [`Formula`].
12551303
pub formula: Formula<V>,
12561304
}
12571305

@@ -1391,6 +1439,10 @@ where
13911439
}
13921440
}
13931441

1442+
/// A constrained Horn clause.
1443+
///
1444+
/// A constrained Horn clause is a formula of the form `∀vars. body ⇒ head` where `body` is a conjunction of
1445+
/// atoms and underlying logical formula, and `head` is an atom.
13941446
#[derive(Debug, Clone)]
13951447
pub struct Clause {
13961448
pub vars: IndexVec<TermVarIdx, Sort>,
@@ -1441,19 +1493,26 @@ impl Clause {
14411493
}
14421494
}
14431495

1496+
/// A selector for a datatype constructor.
1497+
///
1498+
/// A selector is a function that extracts a field from a datatype value.
1499+
/// Through currently we don't use selectors to access datatype fields in [`Term`]s,
1500+
/// we require the symbol as selector name to emit SMT-LIB2 representation of datatypes.
14441501
#[derive(Debug, Clone)]
14451502
pub struct DatatypeSelector {
14461503
pub symbol: DatatypeSymbol,
14471504
pub sort: Sort,
14481505
}
14491506

1507+
/// A datatype constructor.
14501508
#[derive(Debug, Clone)]
14511509
pub struct DatatypeCtor {
14521510
pub symbol: DatatypeSymbol,
14531511
pub selectors: Vec<DatatypeSelector>,
14541512
pub discriminant: u32,
14551513
}
14561514

1515+
/// A datatype definition.
14571516
#[derive(Debug, Clone)]
14581517
pub struct Datatype {
14591518
pub symbol: DatatypeSymbol,
@@ -1462,18 +1521,25 @@ pub struct Datatype {
14621521
}
14631522

14641523
rustc_index::newtype_index! {
1524+
/// An index of [`Clause`].
1525+
///
1526+
/// [`System`] contains `IndexVec<ClauseId, Clause>` that manages the indices and the clauses.
14651527
#[debug_format = "c{}"]
14661528
pub struct ClauseId { }
14671529
}
14681530

14691531
pub type PredSig = Vec<Sort>;
14701532

1533+
/// A predicate variable definition.
14711534
#[derive(Debug, Clone)]
14721535
pub struct PredVarDef {
14731536
pub sig: PredSig,
1537+
/// We may attach a debug information to include in the resulting SMT-LIB2 file to indicate the
1538+
/// origin of predicate variables.
14741539
pub debug_info: DebugInfo,
14751540
}
14761541

1542+
/// A CHC system.
14771543
#[derive(Debug, Clone, Default)]
14781544
pub struct System {
14791545
pub datatypes: Vec<Datatype>,
@@ -1498,6 +1564,13 @@ impl System {
14981564
smtlib2::System::new(self)
14991565
}
15001566

1567+
/// Solves the CHC using an external SMT solver.
1568+
///
1569+
/// This method first performs some optimization of the CHC,
1570+
/// then formats it to SMT-LIB2, and finally calls the configured CHC solver.
1571+
/// The solver and its arguments can be configured using environment
1572+
/// variables
1573+
/// (see <https://github.com/coord-e/thrust?tab=readme-ov-file#configuration>).
15011574
pub fn solve(&self) -> Result<(), CheckSatError> {
15021575
let system = unbox(self.clone());
15031576
if let Ok(file) = std::env::var("THRUST_PRETTY_OUTPUT") {

0 commit comments

Comments
 (0)