conjure_cp_core/ast/
pretty.rs

1//! Functions for pretty printing Conjure models.
2//!
3//! Most things can be pretty printed using `Display`; however some, notably collections
4//! can not, for example, Vec<Expression>
5
6use std::fmt::Display;
7
8use super::{CnfClause, Expression, Name, SymbolTable};
9use crate::ast::domains::HasDomain;
10use itertools::Itertools;
11
12/// Pretty prints a `Vec<Expression>` as if it were a top level constraint list in a `such that`.
13///
14/// Each expression is printed on a new line, and expressions are delimited by commas.
15///
16/// For some input expressions A,B,C:
17/// ```text
18/// A,
19/// B,
20/// C
21/// ```
22///
23/// Each `Expression` is printed using its underlying `Display` implementation.
24pub fn pretty_expressions_as_top_level(expressions: &[Expression]) -> String {
25    expressions.iter().map(|x| format!("{x}")).join(",\n")
26}
27
28/// Pretty prints a `Vec<CnfClause>` as a list of clauses as disjunctions
29///
30/// Each clause is printed on a new line, and expressions are delimited by commas.
31///
32/// For some input expressions A,B,C:
33/// ```text
34/// (a_0 \/ ¬a_1 ...),
35/// (b_0 \/ b_1 ...),
36/// (¬c_0 \/ c_1 ...)
37/// ```
38///
39/// Each `Expression` is printed using its underlying `Display` implementation.
40pub fn pretty_clauses(clauses: &[CnfClause]) -> String {
41    clauses.iter().map(|clause| format!("{clause}")).join(",\n")
42}
43
44/// Pretty prints a `Vec<Expression>` as if it were a conjunction.
45///
46/// For some input expressions A,B,C:
47///
48/// ```text
49/// (A /\ B /\ C)
50/// ```
51///
52/// Each `Expression` is printed using its underlying `Display` implementation.
53pub fn pretty_expressions_as_conjunction(expressions: &[Expression]) -> String {
54    let mut str = expressions.iter().map(|x| format!("{x}")).join(" /\\ ");
55
56    str.insert(0, '(');
57    str.push(')');
58
59    str
60}
61
62/// Pretty prints a `Vec<T>` in a vector like syntax.
63///
64/// For some input values A,B,C:
65///
66/// ```text
67/// [A,B,C]
68/// ````
69///
70/// Each element is printed using its underlying `Display` implementation.
71pub fn pretty_vec<T: Display>(elems: &[T]) -> String {
72    let mut str = elems.iter().map(|x| format!("{x}")).join(", ");
73    str.insert(0, '[');
74    str.push(']');
75
76    str
77}
78
79/// Pretty prints, in essence syntax, the variable declaration for the given symbol.
80///
81/// E.g.
82///
83/// ```text
84/// find a: int(1..5)
85/// ```
86///
87/// Returns None if the symbol is not in the symbol table, or if it is not a variable.
88pub fn pretty_variable_declaration(symbol_table: &SymbolTable, var_name: &Name) -> Option<String> {
89    let decl = symbol_table.lookup(var_name)?;
90    let var = decl.as_var()?;
91    let domain = &var.domain_of();
92    Some(format!("find {var_name}: {domain}"))
93}
94
95/// Pretty prints, in essence syntax, the declaration for the given value letting.
96///
97/// E.g.
98///
99/// ```text
100/// letting A be 1+2+3
101/// ```
102///
103/// Returns None if the symbol is not in the symbol table, or if it is not a value letting.
104pub fn pretty_value_letting_declaration(symbol_table: &SymbolTable, name: &Name) -> Option<String> {
105    let decl = symbol_table.lookup(name)?;
106    let letting = decl.as_value_letting()?;
107    Some(format!("letting {name} be {letting}"))
108}
109
110/// Pretty prints, in essence syntax, the declaration for the given domain letting.
111///
112/// E.g.
113///
114/// ```text
115/// letting A be domain bool
116/// ```
117///
118/// Returns None if the symbol is not in the symbol table, or if it is not a domain letting.
119pub fn pretty_domain_letting_declaration(
120    symbol_table: &SymbolTable,
121    name: &Name,
122) -> Option<String> {
123    let decl = symbol_table.lookup(name)?;
124    let letting = decl.as_domain_letting()?;
125    Some(format!("letting {name} be domain {letting}"))
126}