mirror of
https://github.com/Z3Prover/z3
synced 2025-08-22 11:07:51 +00:00
Xor (#6448)
* Added function to select the next variable to split on * Fixed typo * Small fixes * uint -> int * Fixed missing assignment for binary clauses * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation * Update (not compiling yet) * #6429 * remove ternary clause optimization Removing ternary clause optimization from sat_solver simplifies special case handling of ternary clauses throughout the sat solver and dependent solvers (pb_solver). Benchmarking on QF_BV suggests the ternary clause optimization does not have any effect. While removing ternary clause optimization two bugs in unit propagation were also uncovered: it missed propagations when the only a single undef literal remained in the non-watched literals and it did not update blocked literals in cases where it could in the watch list. These performance bugs were for general clauses, ternary clause propagation did not miss propagations (and don't use blocked literals), but fixing these issues for general clauses appear to have made ternary clause optimization irrelevant based on what was measured. * Update: Missing data-structures (still not compiling) * Nearly compiling * Some missing arguments * Polishing * Only conflicts/propagations/justifications are missing for making it compile * Added propagation (justifications for them are still missing) * Use the right deallocation * Use Z3's memory allocation system * Ported "seen" * Polishing * Added 64-bit "1" counting * More polishing * minor fixes - ensure mk_extract performs simplification to distribute over extract and removing extract if the range is the entire bit-vector - ensure bool_rewriter simplifeis disjunctions when applicable. * adding simplifiers layer simplifiers layer is a common substrate for global non-incremental and incremental processing. The first two layers are new, but others are to be ported form tactics. - bv::slice - rewrites equations to cut-dice-slice bit-vector extractions until they align. It creates opportunities for rewriting portions of bit-vectors to common sub-expressions, including values. - euf::completion - generalizes the KB simplifcation from asserted formulas to use the E-graph to establish a global and order-independent canonization. The interface dependent_expr_simplifier is amenable to forming tactics. Plugins for asserted-formulas is also possible but not yet realized. * Create bv_slice_tactic.cpp missing file * adding virtual destructor Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * Added 64-bit "1" counting (#6434) * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation * Added 64-bit "1" counting * remove incorrect assertion Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * Added limit to "visit" to allow detecting multiple visits (#6435) * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation * Added limit to "visit" to allow detecting multiple visits * Putting visit in a separate class (Reason: We will probably need two of them in the sat::solver) * Bugfix * init solve_eqs * working on solve_eqs * Update .gitignore * wip - converting the equation solver as a simplifier * make visited_helper independent of literals re-introduce shorthands in sat::solver for visited and have them convert literals to unsigned. * build fix * move model and proof converters to self-contained module * Create solve_eqs2_tactic.h * add converters module to python build * move tactic_params to params * move more converters * move horn_subsume_model_converter to ast/converters * add initial stubs for model reconstruction trail * fixing build Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fixes #6439 #6436 * It's compiling (However, two important functions are commented out) Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
b651e57ca2
commit
002d166f72
165 changed files with 4849 additions and 846 deletions
|
@ -1,25 +1,19 @@
|
|||
z3_add_component(tactic
|
||||
SOURCES
|
||||
dependency_converter.cpp
|
||||
equiv_proof_converter.cpp
|
||||
generic_model_converter.cpp
|
||||
goal.cpp
|
||||
goal_num_occurs.cpp
|
||||
goal_shared_occs.cpp
|
||||
goal_util.cpp
|
||||
horn_subsume_model_converter.cpp
|
||||
model_converter.cpp
|
||||
probe.cpp
|
||||
proof_converter.cpp
|
||||
replace_proof_converter.cpp
|
||||
tactical.cpp
|
||||
tactic.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
ast
|
||||
model
|
||||
simplifiers
|
||||
converters
|
||||
TACTIC_HEADERS
|
||||
probe.h
|
||||
tactic.h
|
||||
PYG_FILES
|
||||
tactic_params.pyg
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ Notes:
|
|||
#include "ast/rewriter/pb2bv_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class card2bv_tactic : public tactic {
|
||||
ast_manager & m;
|
||||
|
|
|
@ -20,7 +20,7 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "tactic/core/simplify_tactic.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
|
|
@ -23,7 +23,7 @@ Revision History:
|
|||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
|
|
@ -25,7 +25,7 @@ Notes:
|
|||
#include "ast/ast_pp_util.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class lia2card_tactic : public tactic {
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ Revision History:
|
|||
#include "tactic/arith/bound_manager.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
|
|
@ -27,7 +27,7 @@ Notes:
|
|||
#include "util/optional.h"
|
||||
#include "tactic/arith/bv2int_rewriter.h"
|
||||
#include "tactic/arith/bv2real_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
#include "util/obj_pair_hashtable.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
|
|
@ -21,7 +21,7 @@ Revision History:
|
|||
#include "tactic/tactical.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
|
|
@ -18,7 +18,7 @@ Notes:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
|
||||
class pb2bv_model_converter : public model_converter {
|
||||
|
|
|
@ -29,7 +29,7 @@ Notes:
|
|||
#include "ast/rewriter/pb2bv_rewriter.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "tactic/arith/pb2bv_model_converter.h"
|
||||
#include "tactic/arith/pb2bv_tactic.h"
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ Revision History:
|
|||
#include "tactic/core/nnf_tactic.h"
|
||||
#include "tactic/core/simplify_tactic.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/rewriter/expr_replacer.h"
|
||||
|
|
|
@ -57,7 +57,7 @@ Revision History:
|
|||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "util/dec_ref_util.h"
|
||||
|
|
|
@ -8,6 +8,7 @@ z3_add_component(bv_tactics
|
|||
bv_bound_chk_tactic.cpp
|
||||
bv_bounds_tactic.cpp
|
||||
bv_size_reduction_tactic.cpp
|
||||
bv_slice_tactic.cpp
|
||||
dt2bv_tactic.cpp
|
||||
elim_small_bv_tactic.cpp
|
||||
max_bv_sharing_tactic.cpp
|
||||
|
@ -21,6 +22,7 @@ z3_add_component(bv_tactics
|
|||
bv_bound_chk_tactic.h
|
||||
bv_bounds_tactic.h
|
||||
bv_size_reduction_tactic.h
|
||||
bv_slice_tactic.h
|
||||
bvarray2uf_tactic.h
|
||||
dt2bv_tactic.h
|
||||
elim_small_bv_tactic.h
|
||||
|
|
|
@ -18,7 +18,7 @@ Notes:
|
|||
--*/
|
||||
#include "model/model.h"
|
||||
#include "model/model_pp.h"
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
|
|
@ -18,7 +18,7 @@ Notes:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
|
||||
model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits, ptr_vector<func_decl> const& newbits);
|
||||
model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map<func_decl, expr*> const & const2bits, ptr_vector<func_decl> const& newbits);
|
||||
|
|
|
@ -24,7 +24,7 @@ Notes:
|
|||
#include "tactic/tactical.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/expr_replacer.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
namespace {
|
||||
|
|
33
src/tactic/bv/bv_slice_tactic.cpp
Normal file
33
src/tactic/bv/bv_slice_tactic.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_slice_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for simplifying with bit-vector slices
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-30
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/simplifiers/bv_slice.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "tactic/dependent_expr_state_tactic.h"
|
||||
#include "tactic/bv/bv_slice_tactic.h"
|
||||
|
||||
|
||||
class bv_slice_factory : public dependent_expr_simplifier_factory {
|
||||
public:
|
||||
dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override {
|
||||
return alloc(bv::slice, m, s);
|
||||
}
|
||||
};
|
||||
|
||||
tactic* mk_bv_slice_tactic(ast_manager& m, params_ref const& p) {
|
||||
return alloc(dependent_expr_state_tactic, m, p, alloc(bv_slice_factory), "bv-slice");
|
||||
}
|
29
src/tactic/bv/bv_slice_tactic.h
Normal file
29
src/tactic/bv/bv_slice_tactic.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_slice_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for simplifying with bit-vector slices
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-30
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_bv_slice_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
/*
|
||||
ADD_TACTIC("bv-slice", "simplify using bit-vector slices.", "mk_bv_slice_tactic(m, p)")
|
||||
*/
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#pragma once
|
||||
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class bvarray2uf_rewriter_cfg : public default_rewriter_cfg {
|
||||
ast_manager & m_manager;
|
||||
|
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#include "tactic/tactical.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/expr_replacer.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
#include "tactic/bv/bvarray2uf_tactic.h"
|
||||
|
|
|
@ -21,7 +21,7 @@ Revision History:
|
|||
|
||||
#include "tactic/bv/dt2bv_tactic.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
|
|
|
@ -18,7 +18,7 @@ Revision History:
|
|||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/used_vars.h"
|
||||
#include "ast/well_sorted.h"
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract class and templates for proof and model converters.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-11-14
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/vector.h"
|
||||
#include "util/ref.h"
|
||||
#include "ast/ast_translation.h"
|
||||
|
||||
class converter {
|
||||
unsigned m_ref_count;
|
||||
public:
|
||||
converter():m_ref_count(0) {}
|
||||
virtual ~converter() = default;
|
||||
|
||||
void inc_ref() { ++m_ref_count; }
|
||||
|
||||
void dec_ref() {
|
||||
--m_ref_count;
|
||||
if (m_ref_count == 0) {
|
||||
dealloc(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cancel() {}
|
||||
|
||||
virtual void display(std::ostream & out) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class concat_converter : public T {
|
||||
protected:
|
||||
ref<T> m_c1;
|
||||
ref<T> m_c2;
|
||||
|
||||
template<typename T2>
|
||||
T * translate_core(ast_translation & translator) {
|
||||
T * t1 = m_c1->translate(translator);
|
||||
T * t2 = m_c2->translate(translator);
|
||||
return alloc(T2, t1, t2);
|
||||
}
|
||||
|
||||
public:
|
||||
concat_converter(T * c1, T * c2):m_c1(c1), m_c2(c2) {}
|
||||
|
||||
void cancel() override {
|
||||
m_c2->cancel();
|
||||
m_c1->cancel();
|
||||
}
|
||||
|
||||
virtual char const * get_name() const = 0;
|
||||
|
||||
void display(std::ostream & out) override {
|
||||
m_c1->display(out);
|
||||
m_c2->display(out);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class concat_star_converter : public T {
|
||||
protected:
|
||||
ref<T> m_c1;
|
||||
ptr_vector<T> m_c2s;
|
||||
unsigned_vector m_szs;
|
||||
|
||||
template<typename T2>
|
||||
T * translate_core(ast_translation & translator) {
|
||||
T * t1 = m_c1 ? m_c1->translate(translator) : nullptr;
|
||||
ptr_buffer<T> t2s;
|
||||
for (T* c : m_c2s)
|
||||
t2s.push_back(c ? c->translate(translator) : nullptr);
|
||||
return alloc(T2, t1, m_c2s.size(), t2s.data(), m_szs.data());
|
||||
}
|
||||
|
||||
public:
|
||||
concat_star_converter(T * c1, unsigned num, T * const * c2s, unsigned * szs):
|
||||
m_c1(c1) {
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
T * c2 = c2s[i];
|
||||
if (c2)
|
||||
c2->inc_ref();
|
||||
m_c2s.push_back(c2);
|
||||
m_szs.push_back(szs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
~concat_star_converter() override {
|
||||
for (T* c : m_c2s)
|
||||
if (c) c->dec_ref();
|
||||
}
|
||||
|
||||
void cancel() override {
|
||||
if (m_c1)
|
||||
m_c1->cancel();
|
||||
for (T* c : m_c2s)
|
||||
if (c) c->cancel();
|
||||
}
|
||||
|
||||
virtual char const * get_name() const = 0;
|
||||
|
||||
void display(std::ostream & out) override {
|
||||
if (m_c1)
|
||||
m_c1->display(out);
|
||||
for (T* c : m_c2s)
|
||||
if (c) c->display(out);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ z3_add_component(core_tactics
|
|||
dom_simplify_tactic.cpp
|
||||
elim_term_ite_tactic.cpp
|
||||
elim_uncnstr_tactic.cpp
|
||||
euf_completion_tactic.cpp
|
||||
injectivity_tactic.cpp
|
||||
nnf_tactic.cpp
|
||||
occf_tactic.cpp
|
||||
|
@ -38,6 +39,7 @@ z3_add_component(core_tactics
|
|||
dom_simplify_tactic.h
|
||||
elim_term_ite_tactic.h
|
||||
elim_uncnstr_tactic.h
|
||||
euf_completion_tactic.h
|
||||
injectivity_tactic.h
|
||||
nnf_tactic.h
|
||||
occf_tactic.h
|
||||
|
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/scoped_proof.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/tactic_params.hpp"
|
||||
#include "params/tactic_params.hpp"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#include "tactic/tactical.h"
|
||||
#include "ast/normal_forms/defined_names.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class elim_term_ite_tactic : public tactic {
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
|
|
32
src/tactic/core/euf_completion_tactic.cpp
Normal file
32
src/tactic/core/euf_completion_tactic.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
euf_completion_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for simplifying with equations.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-30
|
||||
|
||||
--*/
|
||||
|
||||
#include "tactic/tactic.h"
|
||||
#include "tactic/dependent_expr_state_tactic.h"
|
||||
#include "ast/simplifiers/euf_completion.h"
|
||||
#include "tactic/core/euf_completion_tactic.h"
|
||||
|
||||
class euf_completion_tactic_factory : public dependent_expr_simplifier_factory {
|
||||
public:
|
||||
dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override {
|
||||
return alloc(euf::completion, m, s);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_euf_completion_tactic(ast_manager& m, params_ref const& p) {
|
||||
return alloc(dependent_expr_state_tactic, m, p, alloc(euf_completion_tactic_factory), "euf-completion");
|
||||
}
|
29
src/tactic/core/euf_completion_tactic.h
Normal file
29
src/tactic/core/euf_completion_tactic.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
euf_completion_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for simplifying with equations.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-30
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_euf_completion_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
/*
|
||||
ADD_TACTIC("euf-completion", "simplify using equalities.", "mk_euf_completion_tactic(m, p)")
|
||||
*/
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ Revision History:
|
|||
--*/
|
||||
#include "ast/normal_forms/nnf.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class nnf_tactic : public tactic {
|
||||
params_ref m_params;
|
||||
|
|
|
@ -23,7 +23,7 @@ Revision History:
|
|||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/core/occf_tactic.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
class occf_tactic : public tactic {
|
||||
struct imp {
|
||||
|
|
|
@ -33,7 +33,7 @@ Notes:
|
|||
--*/
|
||||
#include "tactic/core/pb_preprocess_tactic.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/pb_decl_plugin.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
|
|
|
@ -24,7 +24,7 @@ Revision History:
|
|||
#include "ast/ast_pp.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "tactic/goal_shared_occs.h"
|
||||
#include "tactic/tactic_params.hpp"
|
||||
#include "params/tactic_params.hpp"
|
||||
|
||||
namespace {
|
||||
class propagate_values_tactic : public tactic {
|
||||
|
|
|
@ -22,7 +22,7 @@ Notes:
|
|||
#include "ast/has_free_vars.h"
|
||||
#include "util/map.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
|
||||
/**
|
||||
\brief Reduce the number of arguments in function applications.
|
||||
|
|
|
@ -29,7 +29,7 @@ Notes:
|
|||
#include "tactic/tactic.h"
|
||||
#include "tactic/core/reduce_invertible_tactic.h"
|
||||
#include "tactic/core/collect_occs.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
|
41
src/tactic/core/solve_eqs2_tactic.h
Normal file
41
src/tactic/core/solve_eqs2_tactic.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
solve_eqs2_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for solving variables
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-10-30
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/params.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "tactic/dependent_expr_state_tactic.h"
|
||||
#include "ast/simplifiers/solve_eqs.h"
|
||||
|
||||
|
||||
class solve_eqs2_tactic_factory : public dependent_expr_simplifier_factory {
|
||||
public:
|
||||
dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override {
|
||||
return alloc(euf::solve_eqs, m, s);
|
||||
}
|
||||
};
|
||||
|
||||
inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p) {
|
||||
return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs2");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ADD_TACTIC("solve-eqs2", "solve for variables.", "mk_solve_eqs2_tactic(m, p)")
|
||||
*/
|
||||
|
||||
|
|
@ -27,8 +27,8 @@ Revision History:
|
|||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "tactic/goal_shared_occs.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "tactic/tactic_params.hpp"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "params/tactic_params.hpp"
|
||||
|
||||
class solve_eqs_tactic : public tactic {
|
||||
struct imp {
|
||||
|
@ -977,14 +977,8 @@ class solve_eqs_tactic : public tactic {
|
|||
if (m_produce_models) {
|
||||
if (!mc.get())
|
||||
mc = alloc(gmc, m(), "solve-eqs");
|
||||
for (app* v : m_ordered_vars) {
|
||||
expr * def = nullptr;
|
||||
proof * pr;
|
||||
expr_dependency * dep = nullptr;
|
||||
m_norm_subst->find(v, def, pr, dep);
|
||||
SASSERT(def);
|
||||
static_cast<gmc*>(mc.get())->add(v, def);
|
||||
}
|
||||
for (app* v : m_ordered_vars)
|
||||
static_cast<gmc*>(mc.get())->add(v, m_norm_subst->find(v));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,9 +1135,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r) {
|
||||
if (r == nullptr)
|
||||
return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true));
|
||||
else
|
||||
return clean(alloc(solve_eqs_tactic, m, p, r, false));
|
||||
tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true));
|
||||
}
|
||||
|
|
|
@ -21,9 +21,8 @@ Revision History:
|
|||
#include "util/params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
class expr_replacer;
|
||||
|
||||
tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref(), expr_replacer * r = nullptr);
|
||||
tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
/*
|
||||
ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs_tactic(m, p)")
|
||||
|
|
|
@ -18,6 +18,7 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/goal_proof_converter.h"
|
||||
#include "tactic/core/split_clause_tactic.h"
|
||||
|
||||
class split_clause_tactic : public tactic {
|
||||
|
|
|
@ -25,6 +25,7 @@ Notes:
|
|||
#include "ast/rewriter/expr_replacer.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
|
||||
class symmetry_reduce_tactic : public tactic {
|
||||
class imp;
|
||||
|
@ -608,12 +609,12 @@ private:
|
|||
return (j == A.size())?0:A[j];
|
||||
}
|
||||
|
||||
app* mk_member(app* t, term_set const& C) {
|
||||
expr* mk_member(app* t, term_set const& C) {
|
||||
expr_ref_vector eqs(m());
|
||||
for (unsigned i = 0; i < C.size(); ++i) {
|
||||
eqs.push_back(m().mk_eq(t, C[i]));
|
||||
}
|
||||
return m().mk_or(eqs.size(), eqs.data());
|
||||
return mk_or(m(), eqs.size(), eqs.data());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ Notes:
|
|||
#include "ast/ast_pp.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/goal_shared_occs.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "tactic/core/simplify_tactic.h"
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Notes:
|
|||
#include "util/ref.h"
|
||||
#include "ast/ast_pp_util.h"
|
||||
#include "model/model.h"
|
||||
#include "tactic/converter.h"
|
||||
#include "ast/converters/converter.h"
|
||||
|
||||
class goal;
|
||||
|
||||
|
|
103
src/tactic/dependent_expr_state_tactic.h
Normal file
103
src/tactic/dependent_expr_state_tactic.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dependent_expr_state_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
The dependent_expr_state_tactic creates a tactic from a dependent_expr_simplifier.
|
||||
It relies on a factory for building simplifiers.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-11-2.
|
||||
|
||||
--*/
|
||||
#include "tactic/tactic.h"
|
||||
#include "ast/simplifiers/dependent_expr_state.h"
|
||||
|
||||
class dependent_expr_state_tactic : public tactic, public dependent_expr_state {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
std::string m_name;
|
||||
ref<dependent_expr_simplifier_factory> m_factory;
|
||||
scoped_ptr<dependent_expr_simplifier> m_simp;
|
||||
goal_ref m_goal;
|
||||
dependent_expr m_dep;
|
||||
|
||||
void init() {
|
||||
if (!m_simp)
|
||||
m_simp = m_factory->mk(m, m_params, *this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f, char const* name):
|
||||
m(m),
|
||||
m_params(p),
|
||||
m_name(name),
|
||||
m_factory(f),
|
||||
m_simp(f->mk(m, p, *this)),
|
||||
m_dep(m, m.mk_true(), nullptr)
|
||||
{}
|
||||
|
||||
/**
|
||||
* size(), [](), update() and inconsisent() implement the abstract interface of dependent_expr_state
|
||||
*/
|
||||
unsigned size() const override { return m_goal->size(); }
|
||||
|
||||
dependent_expr const& operator[](unsigned i) override {
|
||||
m_dep = dependent_expr(m, m_goal->form(i), m_goal->dep(i));
|
||||
return m_dep;
|
||||
}
|
||||
void update(unsigned i, dependent_expr const& j) override {
|
||||
auto [f, d] = j();
|
||||
m_goal->update(i, f, nullptr, d);
|
||||
}
|
||||
|
||||
bool inconsistent() override {
|
||||
return m_goal->inconsistent();
|
||||
}
|
||||
|
||||
char const* name() const override { return m_name.c_str(); }
|
||||
|
||||
void updt_params(params_ref const & p) override {
|
||||
m_params.append(p);
|
||||
init();
|
||||
m_simp->updt_params(m_params);
|
||||
}
|
||||
|
||||
tactic * translate(ast_manager & m) override {
|
||||
return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get(), name());
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result) override {
|
||||
if (in->proofs_enabled())
|
||||
throw tactic_exception("tactic does not support low level proofs");
|
||||
init();
|
||||
tactic_report report(name(), *in);
|
||||
m_goal = in.get();
|
||||
m_simp->reduce();
|
||||
m_goal->inc_depth();
|
||||
if (in->models_enabled())
|
||||
in->set(m_simp->get_model_converter().get());
|
||||
result.push_back(in.get());
|
||||
}
|
||||
|
||||
void cleanup() override {
|
||||
}
|
||||
|
||||
void collect_statistics(statistics & st) const override {
|
||||
if (m_simp)
|
||||
m_simp->collect_statistics(st);
|
||||
}
|
||||
|
||||
void reset_statistics() override {
|
||||
if (m_simp)
|
||||
m_simp->reset_statistics();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
equiv_proof_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter that applies equivalence rule to leaves.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "tactic/equiv_proof_converter.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/scoped_proof.h"
|
||||
|
||||
void equiv_proof_converter::insert(expr* fml1, expr* fml2) {
|
||||
if (fml1 != fml2) {
|
||||
scoped_proof _sp(m);
|
||||
proof_ref p1(m), p2(m), p3(m);
|
||||
p1 = m.mk_asserted(fml1);
|
||||
p2 = m.mk_rewrite(fml1, fml2);
|
||||
p3 = m.mk_modus_ponens(p1, p2);
|
||||
TRACE("proof_converter", tout << mk_pp(p3.get(), m) << "\n";);
|
||||
SASSERT(m.has_fact(p3));
|
||||
m_replace.insert(p3);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
equiv_proof_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter that applies equivalence rule to leaves.
|
||||
|
||||
Given a proof P with occurrences of [asserted fml]
|
||||
replace [asserted fml] by a proof of the form
|
||||
[mp [asserted fml'] [~ fml fml']]
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tactic/replace_proof_converter.h"
|
||||
|
||||
class equiv_proof_converter : public proof_converter {
|
||||
ast_manager& m;
|
||||
replace_proof_converter m_replace;
|
||||
public:
|
||||
|
||||
equiv_proof_converter(ast_manager& m): m(m), m_replace(m) {}
|
||||
|
||||
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
|
||||
return m_replace(m, num_source, source);
|
||||
}
|
||||
|
||||
proof_converter * translate(ast_translation & translator) override {
|
||||
return m_replace.translate(translator);
|
||||
}
|
||||
|
||||
void insert(expr* fml1, expr* fml2);
|
||||
|
||||
ast_manager& get_manager() { return m; }
|
||||
|
||||
void display(std::ostream & out) override {}
|
||||
};
|
||||
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#include "solver/solver_na2as.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "ast/rewriter/pb2bv_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
#include "tactic/arith/bound_manager.h"
|
||||
|
|
|
@ -26,7 +26,7 @@ Notes:
|
|||
#include "ast/rewriter/enum2bv_rewriter.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "tactic/fd_solver/enum2bv_solver.h"
|
||||
#include "solver/solver_na2as.h"
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Notes:
|
|||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "solver/solver_na2as.h"
|
||||
#include "tactic/fd_solver/pb2bv_solver.h"
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Notes:
|
|||
#pragma once
|
||||
|
||||
#include "ast/fpa/fpa2bv_converter.h"
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "ast/fpa/bv2fpa_converter.h"
|
||||
|
||||
class fpa2bv_model_converter : public model_converter {
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
generic_model_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Generic model converter that hides and adds entries.
|
||||
It subsumes filter_model_converter and extension_model_converter.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-10-29
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/occurs.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "model/model_v2_pp.h"
|
||||
#include "model/model_evaluator.h"
|
||||
|
||||
|
||||
generic_model_converter::~generic_model_converter() {
|
||||
}
|
||||
|
||||
|
||||
void generic_model_converter::add(func_decl * d, expr* e) {
|
||||
VERIFY(e);
|
||||
VERIFY(d->get_range() == e->get_sort());
|
||||
m_first_idx.insert_if_not_there(d, m_entries.size());
|
||||
m_entries.push_back(entry(d, e, m, ADD));
|
||||
}
|
||||
|
||||
void generic_model_converter::operator()(model_ref & md) {
|
||||
TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout););
|
||||
|
||||
model_evaluator ev(*(md.get()));
|
||||
ev.set_model_completion(true);
|
||||
ev.set_expand_array_equalities(false);
|
||||
expr_ref val(m);
|
||||
unsigned arity;
|
||||
bool reset_ev = false;
|
||||
for (unsigned i = m_entries.size(); i-- > 0; ) {
|
||||
entry const& e = m_entries[i];
|
||||
switch (e.m_instruction) {
|
||||
case instruction::HIDE:
|
||||
md->unregister_decl(e.m_f);
|
||||
break;
|
||||
case instruction::ADD:
|
||||
ev(e.m_def, val);
|
||||
TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";);
|
||||
arity = e.m_f->get_arity();
|
||||
reset_ev = false;
|
||||
if (arity == 0) {
|
||||
expr* old_val = md->get_const_interp(e.m_f);
|
||||
if (old_val && old_val == val) {
|
||||
// skip
|
||||
}
|
||||
else {
|
||||
reset_ev = old_val != nullptr;
|
||||
md->register_decl(e.m_f, val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
func_interp * old_val = md->get_func_interp(e.m_f);
|
||||
if (old_val && old_val->get_else() == val) {
|
||||
// skip
|
||||
}
|
||||
else {
|
||||
reset_ev = old_val != nullptr;
|
||||
func_interp * new_fi = alloc(func_interp, m, arity);
|
||||
new_fi->set_else(val);
|
||||
md->register_decl(e.m_f, new_fi);
|
||||
}
|
||||
}
|
||||
if (reset_ev) {
|
||||
ev.reset();
|
||||
ev.set_model_completion(true);
|
||||
ev.set_expand_array_equalities(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
TRACE("model_converter", tout << "after generic_model_converter\n"; model_v2_pp(tout, *md););
|
||||
}
|
||||
|
||||
void generic_model_converter::display(std::ostream & out) {
|
||||
for (entry const& e : m_entries) {
|
||||
switch (e.m_instruction) {
|
||||
case instruction::HIDE:
|
||||
display_del(out, e.m_f);
|
||||
break;
|
||||
case instruction::ADD:
|
||||
display_add(out, m, e.m_f, e.m_def);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generic_model_converter * generic_model_converter::copy(ast_translation & translator) {
|
||||
ast_manager& to = translator.to();
|
||||
generic_model_converter * res = alloc(generic_model_converter, to, m_orig.c_str());
|
||||
for (entry const& e : m_entries) {
|
||||
func_decl_ref d(translator(e.m_f.get()), to);
|
||||
switch (e.m_instruction) {
|
||||
case instruction::HIDE:
|
||||
res->hide(d);
|
||||
break;
|
||||
case instruction::ADD: {
|
||||
expr_ref def(translator(e.m_def.get()), to);
|
||||
res->add(d, def);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void generic_model_converter::set_env(ast_pp_util* visitor) {
|
||||
if (!visitor) {
|
||||
m_env = nullptr;
|
||||
}
|
||||
else {
|
||||
m_env = &visitor->env();
|
||||
for (entry const& e : m_entries) {
|
||||
visitor->coll.visit_func(e.m_f);
|
||||
if (e.m_def) visitor->coll.visit(e.m_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generic_model_converter::get_units(obj_map<expr, bool>& units) {
|
||||
th_rewriter rw(m);
|
||||
expr_safe_replace rep(m);
|
||||
expr_ref tmp(m);
|
||||
for (auto const& kv : units) {
|
||||
rep.insert(kv.m_key, kv.m_value ? m.mk_true() : m.mk_false());
|
||||
}
|
||||
for (unsigned i = m_entries.size(); i-- > 0;) {
|
||||
entry const& e = m_entries[i];
|
||||
switch (e.m_instruction) {
|
||||
case HIDE:
|
||||
tmp = m.mk_const(e.m_f);
|
||||
if (units.contains(tmp)) {
|
||||
m.dec_ref(tmp);
|
||||
units.remove(tmp);
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
if (e.m_f->get_arity() == 0 && m.is_bool(e.m_f->get_range())) {
|
||||
tmp = m.mk_const(e.m_f);
|
||||
if (units.contains(tmp)) {
|
||||
break;
|
||||
}
|
||||
tmp = e.m_def;
|
||||
rep(tmp);
|
||||
rw(tmp);
|
||||
if (m.is_true(tmp)) {
|
||||
tmp = m.mk_const(e.m_f);
|
||||
m.inc_ref(tmp);
|
||||
units.insert(tmp, true);
|
||||
rep.insert(tmp, m.mk_true());
|
||||
}
|
||||
else if (m.is_false(tmp)) {
|
||||
tmp = m.mk_const(e.m_f);
|
||||
m.inc_ref(tmp);
|
||||
units.insert(tmp, false);
|
||||
rep.insert(tmp, m.mk_false());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
\brief simplify definition expansion from model converter in the case they come from blocked clauses.
|
||||
In this case the definitions are of the form:
|
||||
|
||||
x <=> x or not (C)
|
||||
|
||||
or dually,
|
||||
|
||||
x <=> not (not x or not C)
|
||||
|
||||
in either case the definitions simplify to
|
||||
|
||||
x or C
|
||||
|
||||
*/
|
||||
expr_ref generic_model_converter::simplify_def(entry const& e) {
|
||||
expr_ref c(m.mk_const(e.m_f), m);
|
||||
if (m.is_bool(c) && occurs(c, e.m_def)) {
|
||||
expr_safe_replace rep(m);
|
||||
expr_ref result1 = e.m_def;
|
||||
expr_ref result2 = e.m_def;
|
||||
rep.apply_substitution(c, m.mk_true(), result1);
|
||||
rep.apply_substitution(c, m.mk_false(), result2);
|
||||
th_rewriter rw(m);
|
||||
expr_ref result(m.mk_and(m.mk_implies(result2, c), m.mk_implies(c, result1)), m);
|
||||
rw(result);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return expr_ref(m.mk_eq(c, e.m_def), m);
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
generic_model_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Generic model converter that hides and adds entries.
|
||||
It subsumes filter_model_converter and extension_model_converter.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2017-10-29
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "tactic/model_converter.h"
|
||||
|
||||
class generic_model_converter : public model_converter {
|
||||
enum instruction { HIDE, ADD };
|
||||
struct entry {
|
||||
func_decl_ref m_f;
|
||||
expr_ref m_def;
|
||||
instruction m_instruction;
|
||||
entry(func_decl* f, expr* d, ast_manager& m, instruction i):
|
||||
m_f(f, m), m_def(d, m), m_instruction(i) {}
|
||||
};
|
||||
ast_manager& m;
|
||||
std::string m_orig;
|
||||
vector<entry> m_entries;
|
||||
obj_map<func_decl, unsigned> m_first_idx;
|
||||
|
||||
expr_ref simplify_def(entry const& e);
|
||||
|
||||
public:
|
||||
generic_model_converter(ast_manager & m, char const* orig) : m(m), m_orig(orig) {}
|
||||
|
||||
~generic_model_converter() override;
|
||||
|
||||
void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); }
|
||||
|
||||
void hide(func_decl * f) { m_entries.push_back(entry(f, nullptr, m, HIDE)); }
|
||||
|
||||
void add(func_decl * d, expr* e);
|
||||
|
||||
void add(expr * d, expr* e) { SASSERT(is_app(d) && to_app(d)->get_num_args() == 0); add(to_app(d)->get_decl(), e); }
|
||||
|
||||
void operator()(labels_vec & labels) override {}
|
||||
|
||||
void operator()(model_ref & md) override;
|
||||
|
||||
void operator()(expr_ref& fml) override { UNREACHABLE(); }
|
||||
|
||||
void cancel() override {}
|
||||
|
||||
void display(std::ostream & out) override;
|
||||
|
||||
model_converter * translate(ast_translation & translator) override { return copy(translator); }
|
||||
|
||||
generic_model_converter* copy(ast_translation & translator);
|
||||
|
||||
void set_env(ast_pp_util* visitor) override;
|
||||
|
||||
void get_units(obj_map<expr, bool>& units) override;
|
||||
};
|
||||
|
||||
typedef ref<generic_model_converter> generic_model_converter_ref;
|
||||
|
|
@ -34,8 +34,8 @@ Revision History:
|
|||
#include "util/ref.h"
|
||||
#include "util/ref_vector.h"
|
||||
#include "util/ref_buffer.h"
|
||||
#include "tactic/model_converter.h"
|
||||
#include "tactic/proof_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "ast/converters/proof_converter.h"
|
||||
#include "tactic/dependency_converter.h"
|
||||
|
||||
class goal {
|
||||
|
|
63
src/tactic/goal_proof_converter.h
Normal file
63
src/tactic/goal_proof_converter.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
goal_proof_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter for goals
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-11-23
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ast/converters/proof_converter.h"
|
||||
class goal;
|
||||
|
||||
/**
|
||||
\brief create a proof converter that takes a set of subgoals and converts their proofs to a proof of
|
||||
the goal they were derived from.
|
||||
*/
|
||||
proof_converter * concat(proof_converter *pc1, unsigned n, goal* const* goals);
|
||||
|
||||
class subgoal_proof_converter : public proof_converter {
|
||||
proof_converter_ref m_pc;
|
||||
goal_ref_buffer m_goals;
|
||||
public:
|
||||
subgoal_proof_converter(proof_converter* pc, unsigned n, goal * const* goals):
|
||||
m_pc(pc)
|
||||
{
|
||||
for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]);
|
||||
}
|
||||
|
||||
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
|
||||
// ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals.
|
||||
SASSERT(num_source == 0);
|
||||
proof_converter_ref_buffer pc_buffer;
|
||||
for (goal_ref g : m_goals) {
|
||||
pc_buffer.push_back(g->pc());
|
||||
|
||||
}
|
||||
return apply(m, m_pc, pc_buffer);
|
||||
}
|
||||
|
||||
proof_converter* translate(ast_translation& tr) override {
|
||||
proof_converter_ref pc1 = m_pc->translate(tr);
|
||||
goal_ref_buffer goals;
|
||||
for (goal_ref g : m_goals) goals.push_back(g->translate(tr));
|
||||
return alloc(subgoal_proof_converter, pc1.get(), goals.size(), goals.data());
|
||||
}
|
||||
|
||||
void display(std::ostream& out) override {}
|
||||
|
||||
};
|
||||
|
||||
inline proof_converter * concat(proof_converter *pc, unsigned n, goal* const* goals) {
|
||||
return alloc(subgoal_proof_converter, pc, n, goals);
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
horn_subsume_model_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Model converter for redundant Horn clauses.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-16
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "tactic/horn_subsume_model_converter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/well_sorted.h"
|
||||
|
||||
void horn_subsume_model_converter::insert(app* head, expr* body) {
|
||||
m_delay_head.push_back(head);
|
||||
m_delay_body.push_back(body);
|
||||
}
|
||||
|
||||
void horn_subsume_model_converter::insert(app* head, unsigned sz, expr* const* body) {
|
||||
expr_ref b(m);
|
||||
bool_rewriter(m).mk_and(sz, body, b);
|
||||
insert(head, b.get());
|
||||
}
|
||||
|
||||
|
||||
bool horn_subsume_model_converter::mk_horn(
|
||||
app* head, expr* body, func_decl_ref& pred, expr_ref& body_res) {
|
||||
|
||||
expr_ref_vector conjs(m), subst(m);
|
||||
ptr_vector<sort> sorts2;
|
||||
var_subst vs(m, false);
|
||||
|
||||
if (!is_uninterp(head)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pred = head->get_decl();
|
||||
unsigned arity = head->get_num_args();
|
||||
|
||||
expr_free_vars fv;
|
||||
fv(head);
|
||||
fv.accumulate(body);
|
||||
|
||||
if (arity == 0 && fv.empty()) {
|
||||
body_res = body;
|
||||
return true;
|
||||
}
|
||||
fv.set_default_sort(m.mk_bool_sort());
|
||||
|
||||
svector<symbol> names;
|
||||
for (unsigned i = 0; i < fv.size(); ++i) {
|
||||
names.push_back(symbol(i));
|
||||
}
|
||||
names.reverse();
|
||||
fv.reverse();
|
||||
conjs.push_back(body);
|
||||
for (unsigned i = 0; i < arity; ++i) {
|
||||
expr* arg = head->get_arg(i);
|
||||
var_ref v(m);
|
||||
v = m.mk_var(fv.size()+i, arg->get_sort());
|
||||
|
||||
if (is_var(arg)) {
|
||||
unsigned w = to_var(arg)->get_idx();
|
||||
if (w >= subst.size()) {
|
||||
subst.resize(w+1);
|
||||
}
|
||||
if (subst.get(w)) {
|
||||
conjs.push_back(m.mk_eq(v, subst.get(w)));
|
||||
}
|
||||
else {
|
||||
subst[w] = v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
conjs.push_back(m.mk_eq(v, arg));
|
||||
}
|
||||
}
|
||||
expr_ref body_expr(m);
|
||||
body_expr = m.mk_and(conjs);
|
||||
|
||||
// substitute variables directly.
|
||||
if (!subst.empty()) {
|
||||
body_expr = vs(body_expr, subst);
|
||||
}
|
||||
|
||||
if (fv.empty()) {
|
||||
SASSERT(subst.empty());
|
||||
body_res = body_expr;
|
||||
}
|
||||
else {
|
||||
body_res = m.mk_exists(fv.size(), fv.data(), names.data(), body_expr.get());
|
||||
m_rewrite(body_res);
|
||||
|
||||
}
|
||||
TRACE("mc",
|
||||
tout << mk_pp(head, m) << " :- " << mk_pp(body, m) << "\n";
|
||||
tout << pred->get_name() << " :- " << mk_pp(body_res.get(), m) << "\n";);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool horn_subsume_model_converter::mk_horn(
|
||||
expr* clause, func_decl_ref& pred, expr_ref& body) {
|
||||
|
||||
// formula is closed.
|
||||
DEBUG_CODE(expr_free_vars fv; fv(clause); SASSERT(fv.empty()););
|
||||
|
||||
while (is_quantifier(clause) && to_quantifier(clause)->get_kind() == forall_k) {
|
||||
quantifier* q = to_quantifier(clause);
|
||||
clause = q->get_expr();
|
||||
}
|
||||
expr* e1, *e2;
|
||||
if (m.is_implies(clause, e1, e2)) {
|
||||
if (!is_uninterp(e2)) {
|
||||
return false;
|
||||
}
|
||||
return mk_horn(to_app(e2), e1, pred, body);
|
||||
}
|
||||
else if (m.is_or(clause)) {
|
||||
// todo?
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void horn_subsume_model_converter::add_default_proc::operator()(app* n) {
|
||||
|
||||
//
|
||||
// predicates that have not been assigned values
|
||||
// in the Horn model are assumed false.
|
||||
//
|
||||
if (m.is_bool(n) &&
|
||||
!m_md->has_interpretation(n->get_decl()) &&
|
||||
(n->get_family_id() == null_family_id)) {
|
||||
TRACE("mc", tout << "adding: " << n->get_decl()->get_name() << "\n";);
|
||||
if (n->get_decl()->get_arity() == 0) {
|
||||
m_md->register_decl(n->get_decl(), m.mk_false());
|
||||
}
|
||||
else {
|
||||
func_interp* fi = alloc(func_interp, m, n->get_decl()->get_arity());
|
||||
fi->set_else(m.mk_false());
|
||||
m_md->register_decl(n->get_decl(), fi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void horn_subsume_model_converter::add_default_false_interpretation(expr* e, model_ref& md) {
|
||||
add_default_proc proc(m, md);
|
||||
for_each_expr(proc, e);
|
||||
}
|
||||
|
||||
|
||||
void horn_subsume_model_converter::operator()(model_ref& mr) {
|
||||
|
||||
func_decl_ref pred(m);
|
||||
expr_ref body_res(m);
|
||||
for (unsigned i = 0; i < m_delay_head.size(); ++i) {
|
||||
VERIFY(mk_horn(m_delay_head.get(i), m_delay_body.get(i), pred, body_res));
|
||||
insert(pred.get(), body_res.get());
|
||||
}
|
||||
m_delay_head.reset();
|
||||
m_delay_body.reset();
|
||||
|
||||
TRACE("mc", tout << m_funcs.size() << "\n"; model_smt2_pp(tout, m, *mr, 0););
|
||||
for (unsigned i = m_funcs.size(); i-- > 0; ) {
|
||||
func_decl* h = m_funcs.get(i);
|
||||
expr_ref body(m_bodies.get(i), m);
|
||||
unsigned arity = h->get_arity();
|
||||
add_default_false_interpretation(body, mr);
|
||||
SASSERT(m.is_bool(body));
|
||||
|
||||
TRACE("mc", tout << "eval: " << h->get_name() << "\n" << body << "\n";);
|
||||
body = (*mr)(body);
|
||||
|
||||
TRACE("mc", tout << "to:\n" << body << "\n";);
|
||||
|
||||
if (arity == 0) {
|
||||
expr* e = mr->get_const_interp(h);
|
||||
if (e) {
|
||||
body = m.mk_or(e, body);
|
||||
}
|
||||
m_rewrite(body);
|
||||
mr->register_decl(h, body);
|
||||
}
|
||||
else {
|
||||
func_interp* f = mr->get_func_interp(h);
|
||||
if (f) {
|
||||
expr* e = f->get_else();
|
||||
body = m.mk_or(e, body);
|
||||
}
|
||||
else {
|
||||
f = alloc(func_interp, m, arity);
|
||||
mr->register_decl(h, f);
|
||||
}
|
||||
m_rewrite(body);
|
||||
f->set_else(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
model_converter* horn_subsume_model_converter::translate(ast_translation & translator) {
|
||||
horn_subsume_model_converter* mc = alloc(horn_subsume_model_converter, translator.to());
|
||||
for (unsigned i = 0; i < m_funcs.size(); ++i) {
|
||||
mc->insert(translator(m_funcs[i].get()), translator(m_bodies[i].get()));
|
||||
}
|
||||
return mc;
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
horn_subsume_model_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Model converter for redundant Horn clauses.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-16
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Subsumption transformation (remove Horn clause):
|
||||
|
||||
P(x) :- Body(x,y) Rules
|
||||
----------------------------
|
||||
Rules
|
||||
|
||||
|
||||
Model converter:
|
||||
|
||||
P(x) := P(x) or (exists y. Body(x,y))
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
|
||||
class horn_subsume_model_converter : public model_converter {
|
||||
ast_manager& m;
|
||||
func_decl_ref_vector m_funcs;
|
||||
expr_ref_vector m_bodies;
|
||||
th_rewriter m_rewrite;
|
||||
app_ref_vector m_delay_head;
|
||||
expr_ref_vector m_delay_body;
|
||||
|
||||
void add_default_false_interpretation(expr* e, model_ref& md);
|
||||
|
||||
struct add_default_proc {
|
||||
ast_manager& m;
|
||||
model_ref& m_md;
|
||||
add_default_proc(ast_manager& m, model_ref& md): m(m), m_md(md) {}
|
||||
void operator()(app* n);
|
||||
void operator()(expr* n) {}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
horn_subsume_model_converter(ast_manager& m):
|
||||
m(m), m_funcs(m), m_bodies(m), m_rewrite(m), m_delay_head(m), m_delay_body(m) {}
|
||||
|
||||
bool mk_horn(expr* clause, func_decl_ref& pred, expr_ref& body);
|
||||
|
||||
bool mk_horn(app* head, expr* body, func_decl_ref& pred, expr_ref& body_res);
|
||||
|
||||
void insert(app* head, expr* body);
|
||||
|
||||
void insert(app* head, unsigned sz, expr* const* body);
|
||||
|
||||
void insert(func_decl* p, expr* body) { m_funcs.push_back(p); m_bodies.push_back(body); }
|
||||
|
||||
void operator()(model_ref& _m) override;
|
||||
|
||||
model_converter * translate(ast_translation & translator) override;
|
||||
|
||||
ast_manager& get_manager() { return m; }
|
||||
|
||||
void display(std::ostream & out) override {}
|
||||
|
||||
void get_units(obj_map<expr, bool>& units) override { units.reset(); }
|
||||
|
||||
};
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
model_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract interface for converting models.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-04-21
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include "tactic/model_converter.h"
|
||||
#include "model/model_v2_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
/*
|
||||
* Add or overwrite value in model.
|
||||
*/
|
||||
void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e) {
|
||||
VERIFY(e);
|
||||
VERIFY(f->get_range() == e->get_sort());
|
||||
ast_smt2_pp(out, f, e, env, params_ref(), 0, "model-add") << "\n";
|
||||
}
|
||||
|
||||
void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const {
|
||||
smt2_pp_environment_dbg dbgenv(m);
|
||||
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
|
||||
display_add(out, env, m, f, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* A value is removed from the model.
|
||||
*/
|
||||
void model_converter::display_del(std::ostream& out, func_decl* f) const {
|
||||
if (m_env) {
|
||||
ast_smt2_pp(out << "(model-del ", f->get_name(), f->is_skolem(), *m_env) << ")\n";
|
||||
}
|
||||
else {
|
||||
out << "(model-del " << f->get_name() << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
void model_converter::set_env(ast_pp_util* visitor) {
|
||||
if (visitor) {
|
||||
m_env = &visitor->env();
|
||||
}
|
||||
else {
|
||||
m_env = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void model_converter::display_add(std::ostream& out, ast_manager& m) {
|
||||
// default printer for converter that adds entries
|
||||
model_ref mdl = alloc(model, m);
|
||||
(*this)(mdl);
|
||||
smt2_pp_environment_dbg dbgenv(m);
|
||||
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
|
||||
display_add(out, env, *mdl);
|
||||
}
|
||||
|
||||
void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, model& mdl) {
|
||||
|
||||
ast_manager& m = mdl.get_manager();
|
||||
for (unsigned i = 0, sz = mdl.get_num_constants(); i < sz; ++i) {
|
||||
func_decl* f = mdl.get_constant(i);
|
||||
display_add(out, env, m, f, mdl.get_const_interp(f));
|
||||
}
|
||||
for (unsigned i = 0, sz = mdl.get_num_functions(); i < sz; ++i) {
|
||||
func_decl* f = mdl.get_function(i);
|
||||
func_interp* fi = mdl.get_func_interp(f);
|
||||
display_add(out, env, m, f, fi->get_interp());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class concat_model_converter : public concat_converter<model_converter> {
|
||||
public:
|
||||
concat_model_converter(model_converter * mc1, model_converter * mc2): concat_converter<model_converter>(mc1, mc2) {
|
||||
VERIFY(m_c1 && m_c2);
|
||||
}
|
||||
|
||||
void operator()(model_ref & m) override {
|
||||
this->m_c2->operator()(m);
|
||||
this->m_c1->operator()(m);
|
||||
}
|
||||
|
||||
void operator()(expr_ref & fml) override {
|
||||
this->m_c2->operator()(fml);
|
||||
this->m_c1->operator()(fml);
|
||||
}
|
||||
|
||||
void operator()(labels_vec & r) override {
|
||||
this->m_c2->operator()(r);
|
||||
this->m_c1->operator()(r);
|
||||
}
|
||||
|
||||
void get_units(obj_map<expr, bool>& fmls) override {
|
||||
m_c2->get_units(fmls);
|
||||
m_c1->get_units(fmls);
|
||||
}
|
||||
|
||||
char const * get_name() const override { return "concat-model-converter"; }
|
||||
|
||||
model_converter * translate(ast_translation & translator) override {
|
||||
return this->translate_core<concat_model_converter>(translator);
|
||||
}
|
||||
|
||||
void set_env(ast_pp_util* visitor) override {
|
||||
this->m_c1->set_env(visitor);
|
||||
this->m_c2->set_env(visitor);
|
||||
}
|
||||
};
|
||||
|
||||
model_converter * concat(model_converter * mc1, model_converter * mc2) {
|
||||
if (mc1 == nullptr)
|
||||
return mc2;
|
||||
if (mc2 == nullptr)
|
||||
return mc1;
|
||||
return alloc(concat_model_converter, mc1, mc2);
|
||||
}
|
||||
|
||||
|
||||
class model2mc : public model_converter {
|
||||
model_ref m_model;
|
||||
labels_vec m_labels;
|
||||
public:
|
||||
model2mc(model * m):m_model(m) {}
|
||||
|
||||
model2mc(model * m, labels_vec const & r):m_model(m), m_labels(r) {}
|
||||
|
||||
void operator()(model_ref & m) override {
|
||||
if (!m || !m_model) {
|
||||
m = m_model;
|
||||
return;
|
||||
}
|
||||
m->copy_const_interps(*m_model.get());
|
||||
m->copy_func_interps(*m_model.get());
|
||||
m->copy_usort_interps(*m_model.get());
|
||||
}
|
||||
|
||||
void operator()(labels_vec & r) override {
|
||||
r.append(m_labels.size(), m_labels.data());
|
||||
}
|
||||
|
||||
void operator()(expr_ref& fml) override {
|
||||
model::scoped_model_completion _scm(m_model, false);
|
||||
fml = (*m_model)(fml);
|
||||
}
|
||||
|
||||
void get_units(obj_map<expr, bool>& fmls) override {
|
||||
// no-op
|
||||
}
|
||||
|
||||
void cancel() override {
|
||||
}
|
||||
|
||||
void display(std::ostream & out) override {
|
||||
ast_manager& m = m_model->get_manager();
|
||||
smt2_pp_environment_dbg dbgenv(m);
|
||||
smt2_pp_environment& env = m_env ? *m_env : dbgenv;
|
||||
model_converter::display_add(out, env, *m_model);
|
||||
}
|
||||
|
||||
model_converter * translate(ast_translation & translator) override {
|
||||
model * m = m_model->translate(translator);
|
||||
return alloc(model2mc, m, m_labels);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
model_converter * model2model_converter(model * m) {
|
||||
if (!m) return nullptr;
|
||||
return alloc(model2mc, m);
|
||||
}
|
||||
|
||||
model_converter * model_and_labels2model_converter(model * m, labels_vec const & r) {
|
||||
if (!m) return nullptr;
|
||||
return alloc(model2mc, m, r);
|
||||
}
|
||||
|
||||
void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m) {
|
||||
if (mc) {
|
||||
m = alloc(model, mng);
|
||||
(*mc)(m);
|
||||
}
|
||||
}
|
||||
|
||||
void apply(model_converter_ref & mc, model_ref & m) {
|
||||
if (mc) {
|
||||
(*mc)(m);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
model_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract interface for converting models.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-04-21
|
||||
|
||||
Notes:
|
||||
|
||||
A model converter, mc, can be used to convert a model for one
|
||||
of a generated subgoal into a model for an initial goal or solver state.
|
||||
For a goal or solver state that is decided, a model converter can be
|
||||
a simple wrapper around a model.
|
||||
|
||||
Logically, given a formula F and subgoal formula F_s a model converter mc
|
||||
for F_s relative to F has the property:
|
||||
|
||||
m |= F_s iff mc(m) |= F for every model m
|
||||
|
||||
For the evaluator associated with models, m, we expect
|
||||
|
||||
eval(m)(F_s) <=> eval(mc(m))(F)
|
||||
|
||||
This property holds for both eval, that decides on a fixed value
|
||||
for constants that have no interpretation in m and for 'peval'
|
||||
(partial eval) that returns just the constants that are unfixed.
|
||||
(in the model evaluator one can control this behavior using a
|
||||
configuration flag)
|
||||
|
||||
and more generally over the eval method have:
|
||||
|
||||
G => F_s iff peval(mc(e))(G) => F for every formula G
|
||||
|
||||
|
||||
where e is the empty model (a model that does not evaluate any
|
||||
|
||||
When a model converter supports application to a formula it satisfies
|
||||
the following property:
|
||||
|
||||
mc(G) & F_s is SAT iff G & F is SAT
|
||||
|
||||
For a model converter that is a sequence of definitions and removals
|
||||
of functions we can obtain mc(G) by adding back or expanding definitions
|
||||
that are required to interpret G fully in the context of F_s.
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/ref.h"
|
||||
#include "ast/ast_pp_util.h"
|
||||
#include "model/model.h"
|
||||
#include "tactic/converter.h"
|
||||
|
||||
class labels_vec : public svector<symbol> {};
|
||||
class smt2_pp_environment;
|
||||
|
||||
class model_converter : public converter {
|
||||
protected:
|
||||
smt2_pp_environment* m_env;
|
||||
static void display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e);
|
||||
void display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const;
|
||||
void display_del(std::ostream& out, func_decl* f) const;
|
||||
void display_add(std::ostream& out, ast_manager& m);
|
||||
public:
|
||||
|
||||
model_converter(): m_env(nullptr) {}
|
||||
|
||||
virtual void operator()(model_ref & m) = 0;
|
||||
|
||||
virtual void operator()(labels_vec & r) {}
|
||||
|
||||
virtual void operator()(expr_ref& fml) { UNREACHABLE(); }
|
||||
|
||||
virtual model_converter * translate(ast_translation & translator) = 0;
|
||||
|
||||
virtual void set_env(ast_pp_util* visitor);
|
||||
|
||||
/**
|
||||
\brief we are adding a formula to the context of the model converter.
|
||||
The operator has as side effect of adding definitions as assertions to the
|
||||
formula and removing these definitions from the model converter.
|
||||
*/
|
||||
|
||||
virtual void get_units(obj_map<expr, bool>& fmls) { UNREACHABLE(); }
|
||||
|
||||
static void display_add(std::ostream& out, smt2_pp_environment& env, model& mdl);
|
||||
|
||||
};
|
||||
|
||||
typedef ref<model_converter> model_converter_ref;
|
||||
typedef sref_vector<model_converter> model_converter_ref_vector;
|
||||
typedef sref_buffer<model_converter> model_converter_ref_buffer;
|
||||
|
||||
model_converter * concat(model_converter * mc1, model_converter * mc2);
|
||||
|
||||
model_converter * model2model_converter(model * m);
|
||||
|
||||
model_converter * model_and_labels2model_converter(model * m, labels_vec const &r);
|
||||
|
||||
void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m);
|
||||
|
||||
void apply(model_converter_ref & mc, model_ref & m);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ Notes:
|
|||
#include "solver/solver2tactic.h"
|
||||
#include "solver/parallel_tactic.h"
|
||||
#include "solver/parallel_params.hpp"
|
||||
#include "tactic/tactic_params.hpp"
|
||||
#include "params/tactic_params.hpp"
|
||||
#include "parsers/smt2/smt2parser.h"
|
||||
|
||||
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
proof_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract interface for converting proofs, and basic combinators
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-11-14
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include "tactic/proof_converter.h"
|
||||
#include "tactic/goal.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
class concat_proof_converter : public concat_converter<proof_converter> {
|
||||
public:
|
||||
concat_proof_converter(proof_converter * pc1, proof_converter * pc2):concat_converter<proof_converter>(pc1, pc2) {}
|
||||
|
||||
char const * get_name() const override { return "concat-proof-converter"; }
|
||||
|
||||
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
|
||||
proof_ref tmp(m);
|
||||
tmp = this->m_c2->operator()(m, num_source, source);
|
||||
proof * new_source = tmp.get();
|
||||
return this->m_c1->operator()(m, 1, &new_source);
|
||||
}
|
||||
|
||||
proof_converter * translate(ast_translation & translator) override {
|
||||
return this->translate_core<concat_proof_converter>(translator);
|
||||
}
|
||||
};
|
||||
|
||||
proof_converter * concat(proof_converter * pc1, proof_converter * pc2) {
|
||||
if (pc1 == nullptr)
|
||||
return pc2;
|
||||
if (pc2 == nullptr)
|
||||
return pc1;
|
||||
return alloc(concat_proof_converter, pc1, pc2);
|
||||
}
|
||||
|
||||
class subgoal_proof_converter : public proof_converter {
|
||||
proof_converter_ref m_pc;
|
||||
goal_ref_buffer m_goals;
|
||||
public:
|
||||
subgoal_proof_converter(proof_converter* pc, unsigned n, goal * const* goals):
|
||||
m_pc(pc)
|
||||
{
|
||||
for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]);
|
||||
}
|
||||
|
||||
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
|
||||
// ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals.
|
||||
SASSERT(num_source == 0);
|
||||
proof_converter_ref_buffer pc_buffer;
|
||||
for (goal_ref g : m_goals) {
|
||||
pc_buffer.push_back(g->pc());
|
||||
|
||||
}
|
||||
return apply(m, m_pc, pc_buffer);
|
||||
}
|
||||
|
||||
proof_converter* translate(ast_translation& tr) override {
|
||||
proof_converter_ref pc1 = m_pc->translate(tr);
|
||||
goal_ref_buffer goals;
|
||||
for (goal_ref g : m_goals) goals.push_back(g->translate(tr));
|
||||
return alloc(subgoal_proof_converter, pc1.get(), goals.size(), goals.data());
|
||||
}
|
||||
|
||||
void display(std::ostream& out) override {}
|
||||
|
||||
};
|
||||
|
||||
proof_converter * concat(proof_converter *pc, unsigned n, goal* const* goals) {
|
||||
return alloc(subgoal_proof_converter, pc, n, goals);
|
||||
}
|
||||
|
||||
class proof2pc : public proof_converter {
|
||||
proof_ref m_pr;
|
||||
public:
|
||||
proof2pc(ast_manager & m, proof * pr):m_pr(pr, m) {}
|
||||
|
||||
proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override {
|
||||
SASSERT(num_source == 0);
|
||||
return m_pr;
|
||||
}
|
||||
|
||||
proof_converter * translate(ast_translation & translator) override {
|
||||
return alloc(proof2pc, translator.to(), translator(m_pr.get()));
|
||||
}
|
||||
|
||||
void display(std::ostream & out) override {
|
||||
out << "(proof->proof-converter-wrapper\n" << mk_ismt2_pp(m_pr.get(), m_pr.get_manager()) << ")\n";
|
||||
}
|
||||
};
|
||||
|
||||
proof_converter * proof2proof_converter(ast_manager & m, proof * pr) {
|
||||
if (pr == nullptr)
|
||||
return nullptr;
|
||||
return alloc(proof2pc, m, pr);
|
||||
}
|
||||
|
||||
void apply(ast_manager & m, proof_converter * pc, proof_ref & pr) {
|
||||
if (pc) {
|
||||
proof * _pr = pr.get();
|
||||
pr = (*pc)(m, 1, &_pr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Let pc2s be a buffer of proof converters that are wrappers for proofs.
|
||||
That is, they are functors of the form: unit -> Proof
|
||||
Then, this function applies pc1 to the proofs produced by pc2s's and store
|
||||
the resultant proof in result.
|
||||
|
||||
pc1 and pc2s must be different from 0.
|
||||
*/
|
||||
proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s) {
|
||||
SASSERT(pc1);
|
||||
proof_ref_buffer prs(m);
|
||||
unsigned sz = pc2s.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
proof_ref pr(m);
|
||||
SASSERT(pc2s[i]); // proof production is enabled
|
||||
pr = pc2s[i]->operator()(m, 0, nullptr);
|
||||
prs.push_back(pr);
|
||||
}
|
||||
return (*pc1)(m, sz, prs.data());
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
proof_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract interface for converting proofs, and basic combinators.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-04-26
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "util/ref.h"
|
||||
#include "tactic/converter.h"
|
||||
class goal;
|
||||
|
||||
class proof_converter : public converter {
|
||||
public:
|
||||
virtual proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) = 0;
|
||||
virtual proof_converter * translate(ast_translation & translator) = 0;
|
||||
};
|
||||
|
||||
typedef ref<proof_converter> proof_converter_ref;
|
||||
typedef sref_vector<proof_converter> proof_converter_ref_vector;
|
||||
typedef sref_buffer<proof_converter> proof_converter_ref_buffer;
|
||||
|
||||
|
||||
proof_converter * concat(proof_converter * pc1, proof_converter * pc2);
|
||||
|
||||
/**
|
||||
\brief create a proof converter that takes a set of subgoals and converts their proofs to a proof of
|
||||
the goal they were derived from.
|
||||
*/
|
||||
proof_converter * concat(proof_converter *pc1, unsigned n, goal* const* goals);
|
||||
|
||||
proof_converter * proof2proof_converter(ast_manager & m, proof * pr);
|
||||
|
||||
void apply(ast_manager & m, proof_converter * pc, proof_ref & pr);
|
||||
|
||||
proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s);
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
replace_proof_converter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter that replaces asserted by sub-proof.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-16
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "tactic/replace_proof_converter.h"
|
||||
#include "ast/expr_functors.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
|
||||
/**
|
||||
\brief Replace expressions by other expressions.
|
||||
|
||||
replace_map is caching, so inserting src |-> dst has no effect if
|
||||
src is a sub-expression of something that has already been visited.
|
||||
The assumption is that proof replacements are inserted into
|
||||
the replace_proof_converter in the order that they are introduced, so
|
||||
there are no such clashes.
|
||||
|
||||
map_proc is used as expr_replacer behaves differently
|
||||
when proof mode is turned on.
|
||||
*/
|
||||
class replace_map : public map_proc {
|
||||
public:
|
||||
replace_map(ast_manager& m): map_proc(m) {}
|
||||
|
||||
void insert(expr* src, expr* dst) {
|
||||
m_map.insert(src, dst, nullptr);
|
||||
}
|
||||
|
||||
void operator()(var* v) { visit(v); }
|
||||
void operator()(app* a) { if (!get_expr(a)) { reconstruct(a); } }
|
||||
void operator()(quantifier* q) { visit(q); }
|
||||
|
||||
void apply(expr_ref& e) {
|
||||
for_each_expr(*this, e);
|
||||
e = get_expr(e);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
proof_ref replace_proof_converter::operator()(ast_manager & m, unsigned num_source, proof * const * source) {
|
||||
SASSERT(num_source == 1);
|
||||
replace_map replace(m);
|
||||
proof_ref p(m);
|
||||
expr_ref tmp(source[0], m), e(m), f(m);
|
||||
|
||||
// apply the substitution to the prefix before inserting it.
|
||||
for (unsigned i = 0; i < m_proofs.size(); ++i) {
|
||||
p = m_proofs[i].get();
|
||||
e = p;
|
||||
replace.apply(e);
|
||||
f = m.mk_asserted(m.get_fact(p));
|
||||
replace.insert(f, e);
|
||||
TRACE("proof_converter", tout << f->get_id() << " " << mk_pp(f, m) <<
|
||||
"\n|-> " << mk_pp(e, m) << "\n";);
|
||||
}
|
||||
replace.apply(tmp);
|
||||
TRACE("proof_converter", tout << mk_pp(source[0], m) << "\n";
|
||||
tout << mk_pp(tmp.get(), m) << "\n";);
|
||||
return proof_ref(to_app(tmp), m);
|
||||
}
|
||||
|
||||
proof_converter * replace_proof_converter::translate(ast_translation & translator) {
|
||||
replace_proof_converter* rp = alloc(replace_proof_converter, m);
|
||||
for (proof* p : m_proofs) rp->insert(translator(p));
|
||||
return rp;
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
replace_proof_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof converter to replace asserted leaves by proofs.
|
||||
|
||||
Given a proof P with occurrences of [asserted fml]
|
||||
Replace [asserted fml] by proofs whose conclusions are fml.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-9-16
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tactic/proof_converter.h"
|
||||
|
||||
class replace_proof_converter : public proof_converter {
|
||||
ast_manager& m;
|
||||
proof_ref_vector m_proofs;
|
||||
public:
|
||||
|
||||
replace_proof_converter(ast_manager& _m): m(_m), m_proofs(m) {}
|
||||
|
||||
proof_ref operator()(ast_manager & _m, unsigned num_source, proof * const * source) override;
|
||||
|
||||
proof_converter * translate(ast_translation & translator) override;
|
||||
|
||||
void insert(proof* p) { m_proofs.push_back(p); }
|
||||
|
||||
ast_manager& get_manager() { return m; }
|
||||
|
||||
// run the replacements the inverse direction.
|
||||
void invert() { m_proofs.reverse(); }
|
||||
|
||||
void display(std::ostream & out) override {}
|
||||
|
||||
};
|
||||
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
|
||||
#include "util/stopwatch.h"
|
||||
#include "util/lbool.h"
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "tactic/goal.h"
|
||||
|
||||
#include "tactic/sls/sls_tracker.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "tactic/model_converter.h"
|
||||
#include "ast/converters/model_converter.h"
|
||||
#include "ackermannization/ackr_info.h"
|
||||
|
||||
model_converter * mk_qfufbv_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model);
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
def_module_params('tactic',
|
||||
description='tactic parameters',
|
||||
export=True,
|
||||
params=(('solve_eqs.context_solve', BOOL, True, "solve equalities within disjunctions."),
|
||||
('solve_eqs.theory_solver', BOOL, True, "use theory solvers."),
|
||||
('solve_eqs.ite_solver', BOOL, True, "use if-then-else solvers."),
|
||||
('solve_eqs.max_occs', UINT, UINT_MAX, "maximum number of occurrences for considering a variable for gaussian eliminations."),
|
||||
('blast_term_ite.max_inflation', UINT, UINT_MAX, "multiplicative factor of initial term size."),
|
||||
('blast_term_ite.max_steps', UINT, UINT_MAX, "maximal number of steps allowed for tactic."),
|
||||
('propagate_values.max_rounds', UINT, 4, "maximal number of rounds to propagate values."),
|
||||
('default_tactic', SYMBOL, '', "overwrite default tactic in strategic solver"),
|
||||
|
||||
# ('aig.per_assertion', BOOL, True, "process one assertion at a time"),
|
||||
# ('add_bounds.lower, INT, -2, "lower bound to be added to unbounded variables."),
|
||||
# ('add_bounds.upper, INT, 2, "upper bound to be added to unbounded variables."),
|
||||
# ('fm.real_only', BOOL, True, "consider only real variables for FM"),
|
||||
# ('fm.occ', BOOL, False, "consider inequalities occurring in clauses for FM."),
|
||||
# ('fm.limit', UINT, 5000000, "maximal number of constraints, monomials, clauses visited during FM."),
|
||||
# etc: lia2card, factor, nla2bv, normalize_bounds, pb2bv, purify_arith, bit_blaster, bv_bounds
|
||||
))
|
||||
|
|
@ -20,6 +20,7 @@ Notes:
|
|||
#include "util/cancel_eh.h"
|
||||
#include "util/scoped_ptr_vector.h"
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/goal_proof_converter.h"
|
||||
#ifndef SINGLE_THREAD
|
||||
#include <thread>
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@ Notes:
|
|||
#include "ast/recfun_decl_plugin.h"
|
||||
#include "ast/macros/macro_manager.h"
|
||||
#include "ast/macros/macro_finder.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "tactic/ufbv/macro_finder_tactic.h"
|
||||
|
||||
class macro_finder_tactic : public tactic {
|
||||
|
|
|
@ -17,7 +17,7 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include "tactic/tactical.h"
|
||||
#include "tactic/generic_model_converter.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "ast/macros/macro_manager.h"
|
||||
#include "ast/macros/macro_finder.h"
|
||||
#include "ast/macros/quasi_macros.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue