Skip to content

Commit b936ead

Browse files
authored
Add support for datatypes updater elimination rules in Eunoia (cvc5#11625)
Furthermore, simplifies the updater elimination rule in a minor way for simplicity. Also, fixes a bug in how tuple update terms were output in cpc, and adds their (missing) definition to the theory file. This completes the CPC+Eunoia signature for datatypes.
1 parent 76b59f0 commit b936ead

File tree

6 files changed

+154
-17
lines changed

6 files changed

+154
-17
lines changed

proofs/eo/cpc/programs/Datatypes.eo

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,4 @@
9999
; return: >
100100
; The nth argument of t.
101101
(define $dt_arg_nth ((T Type :implicit) (t T) (n Int))
102-
(eo::list_nth @list ($dt_arg_list t) n)
103-
)
102+
(eo::list_nth @list ($dt_arg_list t) n))

proofs/eo/cpc/rules/Datatypes.eo

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,134 @@
295295
:requires ((($dt_find_cycle t (@list s)) true))
296296
:conclusion (= (= s t) false)
297297
)
298+
299+
;;;;; ProofRewriteRule::DT_COLLAPSE_UPDATER
300+
301+
; program: $mk_dt_collapse_updater_rhs
302+
; args:
303+
; - c U: The remaining term to process.
304+
; - a T: The value to replace as an argument of t.
305+
; - n Int: The argument position (from the end) which a should replace.
306+
; return: >
307+
; The result of updating the n^th argument from the end in t.
308+
(program $dt_collapse_updater_rhs ((U Type) (T Type) (f (-> T U)) (x T) (a T) (n Int))
309+
(U T Int) U
310+
(
311+
(($dt_collapse_updater_rhs (f x) a 0) (f a))
312+
(($dt_collapse_updater_rhs (f x) a n) (_ ($dt_collapse_updater_rhs f a (eo::add n -1)) x))
313+
)
314+
)
315+
316+
; program: $tuple_collapse_updater_rhs
317+
; args:
318+
; - c U: The remaining tuple term to process.
319+
; - a T: The value to replace as an argument of t.
320+
; - n Int: The argument position which a should replace.
321+
; return: >
322+
; The result of updating the n^th argument in t.
323+
(program $tuple_collapse_updater_rhs ((U Type) (T Type) (W Type) (f (-> T U)) (x T) (a T) (b T) (n Int) (ts W :list))
324+
(U T Int) U
325+
(
326+
(($tuple_collapse_updater_rhs (tuple b ts) a 0) (tuple a ts))
327+
(($tuple_collapse_updater_rhs (tuple b ts) a n) (eo::cons tuple b ($tuple_collapse_updater_rhs ts a (eo::add n -1))))
328+
(($tuple_collapse_updater_rhs tuple.unit a n) tuple.unit)
329+
)
330+
)
331+
332+
; program: $mk_dt_collapse_updater_rhs
333+
; args:
334+
; - c U: The update term to process, expected to be an updater applied to a constructor application.
335+
; return: >
336+
; The result of collasping the update term.
337+
(program $mk_dt_collapse_updater_rhs ((D Type) (T Type) (W Type) (s (-> D T)) (t D) (a T) (tr D) (n Int))
338+
(D) Bool
339+
(
340+
(($mk_dt_collapse_updater_rhs (update s t a)) (eo::define ((c ($get_fun t)))
341+
(eo::define ((ss ($dt_get_selectors (eo::typeof t) c)))
342+
(eo::define ((index (eo::list_find eo::List::cons ss s)))
343+
(eo::ite (eo::is_neg index)
344+
t ; unchanged if not correct constructor
345+
($dt_collapse_updater_rhs t a (eo::add (eo::len ss) index -1)))))))
346+
(($mk_dt_collapse_updater_rhs (tuple.update n t a)) ($tuple_collapse_updater_rhs t a n))
347+
)
348+
)
349+
350+
; rule: dt-collapse-updater
351+
; implements: ProofRewriteRule::DT_COLLAPSE_UPDATER
352+
; args:
353+
; - eq Bool: The equality to prove.
354+
; requires: >
355+
; We require that the index^th argument of the term t we are selecting from
356+
; is the right hand side of the equality, where index is the index of the
357+
; selector in the constructor of t.
358+
; conclusion: The given equality.
359+
(declare-rule dt-collapse-updater ((D Type) (t D) (s D))
360+
:args ((= t s))
361+
:requires ((($mk_dt_collapse_updater_rhs t) s))
362+
:conclusion (= t s)
363+
)
364+
365+
;;;;; ProofRewriteRule::DT_UPDATER_ELIM
366+
367+
; program: $dt_updater_elim_rhs
368+
; args:
369+
; - s (-> D T): the selector specifying the argument.
370+
; - D t: The datatype term we are updating.
371+
; - a T: The value to replace at the s argument of t.
372+
; - ss eo::List: The remaining selector arguments to process.
373+
; - c U: The result of updating t we have accumulated so far.
374+
; return: >
375+
; The result of updating the argument specified by s in t.
376+
(program $dt_updater_elim_rhs ((D Type) (T Type) (U Type) (s (-> D T)) (s1 (-> D T)) (t D) (a T) (ss eo::List :list) (c U))
377+
((-> D T) D T eo::List U) D
378+
(
379+
(($dt_updater_elim_rhs s t a (eo::List::cons s ss) c) ($dt_updater_elim_rhs s t a ss (c a)))
380+
(($dt_updater_elim_rhs s t a (eo::List::cons s1 ss) c) ($dt_updater_elim_rhs s t a ss (c (s1 t))))
381+
(($dt_updater_elim_rhs s t a eo::List::nil c) c)
382+
)
383+
)
384+
385+
; program: $tuple_updater_elim_rhs
386+
; args:
387+
; - n Int: the index specifying the argument.
388+
; - D t: The tuple term we are updating.
389+
; - a T: The value to replace at the n^th argument of t.
390+
; - ss eo::List: The remaining selector arguments to process.
391+
; return: >
392+
; The result of updating the argument specified by s in t.
393+
(program $tuple_updater_elim_rhs ((D Type) (T Type) (U Type) (n Int) (s (-> D T)) (t D) (a T) (ss eo::List :list) (c U))
394+
(Int D T eo::List) D
395+
(
396+
(($tuple_updater_elim_rhs n t a (eo::List::cons (tuple.select n) ss)) (eo::cons tuple a ($tuple_updater_elim_rhs n t a ss)))
397+
(($tuple_updater_elim_rhs n t a (eo::List::cons s ss)) (eo::cons tuple (s t) ($tuple_updater_elim_rhs n t a ss)))
398+
(($tuple_updater_elim_rhs n t a eo::List::nil) tuple.unit)
399+
)
400+
)
401+
402+
; program: $mk_dt_updater_elim_rhs
403+
; args:
404+
; - s D: The update term.
405+
; - ss eo::List: The list of selectors for the type of s.
406+
; return: >
407+
; The right hand side is obtained by updating the proper argument of t.
408+
(program $mk_dt_updater_elim_rhs ((D Type) (T Type) (U Type) (s (-> D T)) (t D) (a T) (tr D) (c U) (n Int) (ss eo::List))
409+
(D U eo::List) Bool
410+
(
411+
(($mk_dt_updater_elim_rhs (update s t a) c ss) ($dt_updater_elim_rhs s t a ss ($dt_inst_cons_of (eo::typeof t) c))) ; ensure the constructor is annotated
412+
(($mk_dt_updater_elim_rhs (tuple.update n t a) tuple ss) ($tuple_updater_elim_rhs n t a ss))
413+
)
414+
)
415+
416+
; rule: dt-updater-elim
417+
; implements: ProofRewriteRule::DT_UPDATER_ELIM
418+
; args:
419+
; - eq Bool: The equality to prove.
420+
; requires: >
421+
; We require that the right hand side is an ITE where the then branch is
422+
; obtained by updating the proper argument of t, as implemented by $is_dt_updater_elim.
423+
; conclusion: The given equality.
424+
(declare-rule dt-updater-elim ((D Type) (S Type) (T Type) (C Type) (s S) (t D) (a T) (u (-> S D T D)) (tu D) (c C))
425+
:args ((= (u s t a) (ite (is c t) tu t)))
426+
:requires ((($mk_dt_updater_elim_rhs (u s t a) c ($dt_get_selectors (eo::typeof t) c)) tu))
427+
:conclusion (= (u s t a) (ite (is c t) tu t))
428+
)

proofs/eo/cpc/theories/Datatypes.eo

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
(declare-const tuple.select
3333
(-> (! Type :var T :implicit)
3434
(! Int :var i) T (eo::list_nth Tuple T i)))
35+
; disclaimer: This function is not in the SMT-LIB standard.
36+
(declare-const tuple.update
37+
(-> (! Type :var T :implicit)
38+
(! Int :var i) T (eo::list_nth Tuple T i) T))
3539

3640
; disclaimer: >
3741
; This sort is not in the SMT-LIB standard. All further function

src/proof/alf/alf_node_converter.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ BaseAlfNodeConverter::BaseAlfNodeConverter(NodeManager* nm) : NodeConverter(nm)
5454

5555
AlfNodeConverter::AlfNodeConverter(NodeManager* nm) : BaseAlfNodeConverter(nm)
5656
{
57-
d_sortType = nm->mkSort("sortType");
57+
// use builtin operator type as the type of sorts, which makes a difference
58+
// e.g. for converting terms of kind SORT_TO_TERM.
59+
d_sortType = nm->builtinOperatorType();
5860
}
5961

6062
AlfNodeConverter::~AlfNodeConverter() {}
@@ -155,7 +157,7 @@ Node AlfNodeConverter::postConvert(Node n)
155157
// must ensure we print higher-order function applications with "_"
156158
if (!n.getOperator().isVar())
157159
{
158-
TypeNode tn = n.getType();
160+
TypeNode tn = n.getType();
159161
std::vector<Node> args;
160162
args.push_back(n.getOperator());
161163
args.insert(args.end(), n.begin(), n.end());
@@ -322,6 +324,10 @@ Node AlfNodeConverter::postConvert(Node n)
322324
// is refactored to silently ignore this kind, this case can be deleted.
323325
return n[0];
324326
}
327+
else if (k == Kind::SORT_TO_TERM)
328+
{
329+
return typeAsNode(n.getConst<SortToTerm>().getType());
330+
}
325331
else if (GenericOp::isIndexedOperatorKind(k))
326332
{
327333
TypeNode tn = n.getType();
@@ -524,17 +530,14 @@ Node AlfNodeConverter::getOperatorOfTerm(Node n)
524530
size_t index = DType::indexOf(op);
525531
const DType& dt = DType::datatypeOf(op);
526532
size_t cindex = DType::cindexOf(op);
527-
opName << "update";
528533
if (dt.isTuple())
529534
{
530-
std::vector<Node> args;
531-
args.push_back(d_nm->mkConstInt(cindex));
532-
Node ssym = mkInternalApp(
533-
"tuple.select", args, dt[cindex][index].getSelector().getType());
534-
indices.push_back(ssym);
535+
opName << "tuple.update";
536+
indices.push_back(d_nm->mkConstInt(index));
535537
}
536538
else
537539
{
540+
opName << "update";
538541
indices.push_back(dt[cindex][index].getSelector());
539542
}
540543
}

src/proof/alf/alf_printer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ bool AlfPrinter::isHandledTheoryRewrite(ProofRewriteRule id, const Node& n)
309309
case ProofRewriteRule::DT_CONS_EQ:
310310
case ProofRewriteRule::DT_CONS_EQ_CLASH:
311311
case ProofRewriteRule::DT_CYCLE:
312+
case ProofRewriteRule::DT_COLLAPSE_UPDATER:
313+
case ProofRewriteRule::DT_UPDATER_ELIM:
312314
case ProofRewriteRule::QUANT_MERGE_PRENEX:
313315
case ProofRewriteRule::QUANT_MINISCOPE_AND:
314316
case ProofRewriteRule::QUANT_MINISCOPE_OR:

src/theory/datatypes/datatypes_rewriter.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,13 +1158,11 @@ Node DatatypesRewriter::expandUpdater(const Node& n)
11581158
}
11591159
}
11601160
ret = b;
1161-
if (dt.getNumConstructors() > 1)
1162-
{
1163-
// must be the right constructor to update
1164-
Node tester = nm->mkNode(Kind::APPLY_TESTER, dc.getTester(), n[0]);
1165-
ret = nm->mkNode(Kind::ITE, tester, ret, n[0]);
1166-
}
1167-
return ret;
1161+
// note it may be that this dt has one constructor, in which case this
1162+
// tester will rewrite to true.
1163+
// must be the right constructor to update
1164+
Node tester = nm->mkNode(Kind::APPLY_TESTER, dc.getTester(), n[0]);
1165+
return nm->mkNode(Kind::ITE, tester, ret, n[0]);
11681166
}
11691167
Node DatatypesRewriter::expandNullableLift(Node n)
11701168
{

0 commit comments

Comments
 (0)