mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
isolated proto_model obsolete code
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
24efe18d3f
commit
759504880a
17 changed files with 68 additions and 78 deletions
|
@ -1,206 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array_factory.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"array_factory.h"
|
||||
#include"array_decl_plugin.h"
|
||||
#include"proto_model.h"
|
||||
#include"func_interp.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
func_decl * mk_aux_decl_for_array_sort(ast_manager & m, sort * s) {
|
||||
ptr_buffer<sort> domain;
|
||||
sort * range = get_array_range(s);
|
||||
unsigned arity = get_array_arity(s);
|
||||
for (unsigned i = 0; i < arity; i++) {
|
||||
domain.push_back(get_array_domain(s, i));
|
||||
}
|
||||
return m.mk_fresh_func_decl(symbol::null, symbol::null, arity, domain.c_ptr(), range);
|
||||
}
|
||||
|
||||
array_factory::array_factory(ast_manager & m, proto_model & md):
|
||||
struct_factory(m, m.get_family_id("array"), md) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brieft Return as-array[f] where f is a fresh function symbol with the right domain and range for the array sort s.
|
||||
Store in fi the function interpretation for f.
|
||||
*/
|
||||
expr * array_factory::mk_array_interp(sort * s, func_interp * & fi) {
|
||||
func_decl * f = mk_aux_decl_for_array_sort(m_manager, s);
|
||||
fi = alloc(func_interp, m_manager, get_array_arity(s));
|
||||
m_model.register_decl(f, fi);
|
||||
parameter p[1] = { parameter(f) };
|
||||
expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, p);
|
||||
register_value(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void array_factory::get_some_args_for(sort * s, ptr_buffer<expr> & args) {
|
||||
unsigned arity = get_array_arity(s);
|
||||
for (unsigned i = 0; i < arity; i++) {
|
||||
sort * d = get_array_domain(s, i);
|
||||
expr * a = m_model.get_some_value(d);
|
||||
args.push_back(a);
|
||||
}
|
||||
}
|
||||
|
||||
expr * array_factory::get_some_value(sort * s) {
|
||||
TRACE("array_factory", tout << mk_pp(s, m_manager) << "\n";);
|
||||
value_set * set = 0;
|
||||
if (m_sort2value_set.find(s, set) && !set->empty())
|
||||
return *(set->begin());
|
||||
func_interp * fi;
|
||||
expr * val = mk_array_interp(s, fi);
|
||||
ptr_buffer<expr> args;
|
||||
get_some_args_for(s, args);
|
||||
fi->insert_entry(args.c_ptr(), m_model.get_some_value(get_array_range(s)));
|
||||
return val;
|
||||
}
|
||||
|
||||
bool array_factory::mk_two_diff_values_for(sort * s) {
|
||||
DEBUG_CODE({
|
||||
value_set * set = 0;
|
||||
SASSERT(!m_sort2value_set.find(s, set) || set->size() == 0);
|
||||
});
|
||||
expr_ref r1(m_manager);
|
||||
expr_ref r2(m_manager);
|
||||
sort * range = get_array_range(s);
|
||||
if (!m_model.get_some_values(range, r1, r2))
|
||||
return false; // failed... the range is probably unit.
|
||||
ptr_buffer<expr> args;
|
||||
get_some_args_for(s, args);
|
||||
func_interp * fi1;
|
||||
func_interp * fi2;
|
||||
mk_array_interp(s, fi1);
|
||||
mk_array_interp(s, fi2);
|
||||
fi1->insert_entry(args.c_ptr(), r1);
|
||||
fi2->insert_entry(args.c_ptr(), r2);
|
||||
DEBUG_CODE({
|
||||
value_set * set = 0;
|
||||
SASSERT(m_sort2value_set.find(s, set) && set->size() == 2);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool array_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
value_set * set = 0;
|
||||
if (!m_sort2value_set.find(s, set) || set->size() == 0) {
|
||||
if (!mk_two_diff_values_for(s))
|
||||
return false;
|
||||
}
|
||||
m_sort2value_set.find(s, set);
|
||||
SASSERT(set != 0);
|
||||
SASSERT(set->size() > 0);
|
||||
|
||||
if (set->size() == 1) {
|
||||
v1 = *(set->begin());
|
||||
v2 = get_fresh_value(s);
|
||||
return v2.get() != 0;
|
||||
}
|
||||
else {
|
||||
SASSERT(set->size() >= 2);
|
||||
value_set::iterator it = set->begin();
|
||||
v1 = *it;
|
||||
++it;
|
||||
v2 = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: I have to check if the following procedure is really correct.
|
||||
// I'm supporting partial arrays where the "else" can be set later by the model_finder or model classes.
|
||||
// Projection functions may be also used.
|
||||
//
|
||||
// If projections are not used, then the following code should work if the "else" of a partial array
|
||||
// is set with the result of some entry.
|
||||
//
|
||||
expr * array_factory::get_fresh_value(sort * s) {
|
||||
value_set * set = get_value_set(s);
|
||||
if (set->empty()) {
|
||||
// easy case
|
||||
return get_some_value(s);
|
||||
}
|
||||
sort * range = get_array_range(s);
|
||||
expr * range_val = m_model.get_fresh_value(range);
|
||||
if (range_val != 0) {
|
||||
// easy case
|
||||
func_interp * fi;
|
||||
expr * val = mk_array_interp(s, fi);
|
||||
ptr_buffer<expr> args;
|
||||
get_some_args_for(s, args);
|
||||
fi->insert_entry(args.c_ptr(), range_val);
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
TRACE("array_factory_bug", tout << "array fresh value: using fresh index, range: " << mk_pp(range, m_manager) << "\n";);
|
||||
expr_ref v1(m_manager);
|
||||
expr_ref v2(m_manager);
|
||||
if (m_model.get_some_values(range, v1, v2)) {
|
||||
// Claim: A is fresh if A[i1] = v1 and A[i2] = v2 where i1 and i2 are fresh values,
|
||||
// and v1 and v2 are distinct.
|
||||
//
|
||||
// Proof: let assume there is an Array A' such that A' = A.
|
||||
// Then A[i1] == A'[i1] and A[i2] == A'[i2]. Since, i1 and i2 are fresh,
|
||||
// A' does not have an entry for i1 or i2, So A'[i1] == A'[i2] == A'.m_else.
|
||||
// Thus, A[i1] == A[i2] which is a contradiction since v1 != v2 and A[i1] = v1 and A[i2] = v2.
|
||||
TRACE("array_factory_bug", tout << "v1: " << mk_pp(v1, m_manager) << " v2: " << mk_pp(v2, m_manager) << "\n";);
|
||||
ptr_buffer<expr> args1;
|
||||
ptr_buffer<expr> args2;
|
||||
bool found = false;
|
||||
unsigned arity = get_array_arity(s);
|
||||
for (unsigned i = 0; i < arity; i++) {
|
||||
sort * d = get_array_domain(s, i);
|
||||
if (!found) {
|
||||
expr * arg1 = m_model.get_fresh_value(d);
|
||||
expr * arg2 = m_model.get_fresh_value(d);
|
||||
if (arg1 != 0 && arg2 != 0) {
|
||||
found = true;
|
||||
args1.push_back(arg1);
|
||||
args2.push_back(arg2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
expr * arg = m_model.get_some_value(d);
|
||||
args1.push_back(arg);
|
||||
args2.push_back(arg);
|
||||
}
|
||||
if (found) {
|
||||
func_interp * fi;
|
||||
expr * val = mk_array_interp(s, fi);
|
||||
fi->insert_entry(args1.c_ptr(), v1);
|
||||
fi->insert_entry(args2.c_ptr(), v2);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use more expensive procedures to create a fresh array value.
|
||||
// Example: track the values used in the domain.
|
||||
|
||||
// Remark: in the current implementation, this function
|
||||
// will never fail, since if a type is finite, then
|
||||
// type_pred will be applied and get_fresh_value will not
|
||||
// need to be used.
|
||||
|
||||
// failed to create a fresh array value
|
||||
TRACE("array_factory_bug", tout << "failed to build fresh array value\n";);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array_factory.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _ARRAY_FACTORY_H_
|
||||
#define _ARRAY_FACTORY_H_
|
||||
|
||||
#include"struct_factory.h"
|
||||
|
||||
class func_interp;
|
||||
|
||||
func_decl * mk_aux_decl_for_array_sort(ast_manager & m, sort * s);
|
||||
|
||||
class array_factory : public struct_factory {
|
||||
expr * mk_array_interp(sort * s, func_interp * & fi);
|
||||
void get_some_args_for(sort * s, ptr_buffer<expr> & args);
|
||||
bool mk_two_diff_values_for(sort * s);
|
||||
public:
|
||||
array_factory(ast_manager & m, proto_model & md);
|
||||
|
||||
virtual ~array_factory() {}
|
||||
|
||||
virtual expr * get_some_value(sort * s);
|
||||
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
|
||||
|
||||
virtual expr * get_fresh_value(sort * s);
|
||||
};
|
||||
|
||||
#endif /* _ARRAY_FACTORY_H_ */
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
datatype_factory.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-11-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"datatype_factory.h"
|
||||
#include"proto_model.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
|
||||
datatype_factory::datatype_factory(ast_manager & m, proto_model & md):
|
||||
struct_factory(m, m.get_family_id("datatype"), md),
|
||||
m_util(m) {
|
||||
}
|
||||
|
||||
expr * datatype_factory::get_some_value(sort * s) {
|
||||
value_set * set = 0;
|
||||
if (m_sort2value_set.find(s, set) && !set->empty())
|
||||
return *(set->begin());
|
||||
func_decl * c = m_util.get_non_rec_constructor(s);
|
||||
ptr_vector<expr> args;
|
||||
unsigned num = c->get_arity();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
args.push_back(m_model.get_some_value(c->get_domain(i)));
|
||||
}
|
||||
expr * r = m_manager.mk_app(c, args.size(), args.c_ptr());
|
||||
register_value(r);
|
||||
TRACE("datatype_factory", tout << mk_pp(r, m_util.get_manager()) << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the last fresh (or almost) fresh value of sort s.
|
||||
*/
|
||||
expr * datatype_factory::get_last_fresh_value(sort * s) {
|
||||
expr * val = 0;
|
||||
if (m_last_fresh_value.find(s, val))
|
||||
return val;
|
||||
value_set * set = get_value_set(s);
|
||||
if (set->empty())
|
||||
val = get_some_value(s);
|
||||
else
|
||||
val = *(set->begin());
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create an almost fresh value. If s is recursive, then the result is not 0.
|
||||
It also updates m_last_fresh_value
|
||||
*/
|
||||
expr * datatype_factory::get_almost_fresh_value(sort * s) {
|
||||
value_set * set = get_value_set(s);
|
||||
if (set->empty()) {
|
||||
expr * val = get_some_value(s);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, val);
|
||||
return val;
|
||||
}
|
||||
// Traverse constructors, and try to invoke get_fresh_value of one of the arguments (if the argument is not a sibling datatype of s).
|
||||
// If the argumet is a sibling datatype of s, then
|
||||
// use get_last_fresh_value.
|
||||
ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s);
|
||||
ptr_vector<func_decl>::const_iterator it = constructors->begin();
|
||||
ptr_vector<func_decl>::const_iterator end = constructors->end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * constructor = *it;
|
||||
expr_ref_vector args(m_manager);
|
||||
bool found_fresh_arg = false;
|
||||
bool recursive = false;
|
||||
unsigned num = constructor->get_arity();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
sort * s_arg = constructor->get_domain(i);
|
||||
if (!found_fresh_arg && (!m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) {
|
||||
expr * new_arg = m_model.get_fresh_value(s_arg);
|
||||
if (new_arg != 0) {
|
||||
found_fresh_arg = true;
|
||||
args.push_back(new_arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!found_fresh_arg && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) {
|
||||
recursive = true;
|
||||
expr * last_fresh = get_last_fresh_value(s_arg);
|
||||
args.push_back(last_fresh);
|
||||
}
|
||||
else {
|
||||
expr * some_arg = m_model.get_some_value(s_arg);
|
||||
args.push_back(some_arg);
|
||||
}
|
||||
}
|
||||
if (recursive || found_fresh_arg) {
|
||||
expr * new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
SASSERT(!found_fresh_arg || !set->contains(new_value));
|
||||
register_value(new_value);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
return new_value;
|
||||
}
|
||||
}
|
||||
SASSERT(!m_util.is_recursive(s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
expr * datatype_factory::get_fresh_value(sort * s) {
|
||||
TRACE("datatype_factory", tout << "generating fresh value for: " << s->get_name() << "\n";);
|
||||
value_set * set = get_value_set(s);
|
||||
// Approach 0)
|
||||
// if no value for s was generated so far, then used get_some_value
|
||||
if (set->empty()) {
|
||||
expr * val = get_some_value(s);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, val);
|
||||
TRACE("datatype_factory", tout << "0. result: " << mk_pp(val, m_manager) << "\n";);
|
||||
return val;
|
||||
}
|
||||
// Approach 1)
|
||||
// Traverse constructors, and try to invoke get_fresh_value of one of the
|
||||
// arguments (if the argument is not a sibling datatype of s).
|
||||
// Two datatypes are siblings if they were defined together in the same mutually recursive definition.
|
||||
ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s);
|
||||
ptr_vector<func_decl>::const_iterator it = constructors->begin();
|
||||
ptr_vector<func_decl>::const_iterator end = constructors->end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * constructor = *it;
|
||||
expr_ref_vector args(m_manager);
|
||||
bool found_fresh_arg = false;
|
||||
unsigned num = constructor->get_arity();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
sort * s_arg = constructor->get_domain(i);
|
||||
if (!found_fresh_arg && (!m_util.is_recursive(s) || !m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) {
|
||||
expr * new_arg = m_model.get_fresh_value(s_arg);
|
||||
if (new_arg != 0) {
|
||||
found_fresh_arg = true;
|
||||
args.push_back(new_arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
expr * some_arg = m_model.get_some_value(s_arg);
|
||||
args.push_back(some_arg);
|
||||
}
|
||||
expr_ref new_value(m_manager);
|
||||
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
CTRACE("datatype_factory", found_fresh_arg && set->contains(new_value), tout << mk_pp(new_value, m_manager) << "\n";);
|
||||
SASSERT(!found_fresh_arg || !set->contains(new_value));
|
||||
if (!set->contains(new_value)) {
|
||||
register_value(new_value);
|
||||
if (m_util.is_recursive(s))
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
TRACE("datatype_factory", tout << "1. result: " << mk_pp(new_value, m_manager) << "\n";);
|
||||
return new_value;
|
||||
}
|
||||
}
|
||||
// Approach 2)
|
||||
// For recursive datatypes.
|
||||
// search for constructor...
|
||||
if (m_util.is_recursive(s)) {
|
||||
while(true) {
|
||||
TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
|
||||
ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s);
|
||||
ptr_vector<func_decl>::const_iterator it = constructors->begin();
|
||||
ptr_vector<func_decl>::const_iterator end = constructors->end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * constructor = *it;
|
||||
expr_ref_vector args(m_manager);
|
||||
bool found_sibling = false;
|
||||
unsigned num = constructor->get_arity();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
sort * s_arg = constructor->get_domain(i);
|
||||
if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) {
|
||||
found_sibling = true;
|
||||
expr * maybe_new_arg = get_almost_fresh_value(s_arg);
|
||||
args.push_back(maybe_new_arg);
|
||||
}
|
||||
else {
|
||||
expr * some_arg = m_model.get_some_value(s_arg);
|
||||
args.push_back(some_arg);
|
||||
}
|
||||
}
|
||||
if (found_sibling) {
|
||||
expr_ref new_value(m_manager);
|
||||
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
|
||||
m_last_fresh_value.insert(s, new_value);
|
||||
if (!set->contains(new_value)) {
|
||||
register_value(new_value);
|
||||
TRACE("datatype_factory", tout << "2. result: " << mk_pp(new_value, m_manager) << "\n";);
|
||||
return new_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Approach 3)
|
||||
// for non-recursive datatypes.
|
||||
// Search for value that was not created before.
|
||||
SASSERT(!m_util.is_recursive(s));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
datatype_factory.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-11-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DATATYPE_FACTORY_H_
|
||||
#define _DATATYPE_FACTORY_H_
|
||||
|
||||
#include"struct_factory.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
|
||||
class datatype_factory : public struct_factory {
|
||||
datatype_util m_util;
|
||||
obj_map<sort, expr *> m_last_fresh_value;
|
||||
|
||||
expr * get_last_fresh_value(sort * s);
|
||||
expr * get_almost_fresh_value(sort * s);
|
||||
|
||||
public:
|
||||
datatype_factory(ast_manager & m, proto_model & md);
|
||||
virtual ~datatype_factory() {}
|
||||
virtual expr * get_some_value(sort * s);
|
||||
virtual expr * get_fresh_value(sort * s);
|
||||
};
|
||||
|
||||
#endif /* _DATATYPE_FACTORY_H_ */
|
||||
|
|
@ -16,8 +16,6 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include"func_interp.h"
|
||||
#include"simplifier.h"
|
||||
#include"basic_simplifier_plugin.h"
|
||||
#include"var_subst.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"ast_pp.h"
|
||||
|
@ -182,71 +180,6 @@ bool func_interp::eval_else(expr * const * args, expr_ref & result) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Store in r the result of applying args to this function.
|
||||
Return true in case of success.
|
||||
The function may fail if m_else == 0.
|
||||
*/
|
||||
bool func_interp::eval(simplifier & s, expr * const * args, expr_ref & result) {
|
||||
bool actuals_are_values = true;
|
||||
|
||||
if (!m_entries.empty()) {
|
||||
for (unsigned i = 0; actuals_are_values && i < m_arity; i++) {
|
||||
actuals_are_values = m_manager.is_value(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
func_entry * entry = get_entry(args);
|
||||
if (entry != 0) {
|
||||
result = entry->get_result();
|
||||
TRACE("func_interp", tout << "found entry for: ";
|
||||
for(unsigned i = 0; i < m_arity; i++)
|
||||
tout << mk_pp(args[i], m_manager) << " ";
|
||||
tout << "\nresult: " << mk_pp(result, m_manager) << "\n";);
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACE("func_interp", tout << "failed to find entry for: ";
|
||||
for(unsigned i = 0; i < m_arity; i++)
|
||||
tout << mk_pp(args[i], m_manager) << " ";
|
||||
tout << "\nis partial: " << is_partial() << "\n";);
|
||||
|
||||
if (!eval_else(args, result)) {
|
||||
TRACE("func_interp", tout << "function is partial, failed to evaluate\n";);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actuals_are_values && m_args_are_values) {
|
||||
// cheap case... we are done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// build symbolic result... the actuals may be equal to the args of one of the entries.
|
||||
basic_simplifier_plugin * bs = static_cast<basic_simplifier_plugin*>(s.get_plugin(m_manager.get_basic_family_id()));
|
||||
ptr_vector<func_entry>::iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
SASSERT(!curr->eq_args(m_arity, args));
|
||||
if (!actuals_are_values || !curr->args_are_values()) {
|
||||
expr_ref_buffer eqs(m_manager);
|
||||
unsigned i = m_arity;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
expr_ref new_eq(m_manager);
|
||||
bs->mk_eq(curr->get_arg(i), args[i], new_eq);
|
||||
eqs.push_back(new_eq);
|
||||
}
|
||||
SASSERT(eqs.size() == m_arity);
|
||||
expr_ref new_cond(m_manager);
|
||||
bs->mk_and(eqs.size(), eqs.c_ptr(), new_cond);
|
||||
bs->mk_ite(new_cond, curr->get_result(), result, result);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the result with the maximal number of occurrencies in m_entries.
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,6 @@ Revision History:
|
|||
#include"ast_translation.h"
|
||||
|
||||
class func_interp;
|
||||
class simplifier;
|
||||
|
||||
class func_entry {
|
||||
bool m_args_are_values; //!< true if is_value(m_args[i]) is true for all i in [0, arity)
|
||||
|
@ -50,10 +49,10 @@ class func_entry {
|
|||
friend class func_interp;
|
||||
|
||||
void set_result(ast_manager & m, expr * r);
|
||||
bool args_are_values() const { return m_args_are_values; }
|
||||
|
||||
public:
|
||||
static func_entry * mk(ast_manager & m, unsigned arity, expr * const * args, expr * result);
|
||||
bool args_are_values() const { return m_args_are_values; }
|
||||
void deallocate(ast_manager & m, unsigned arity);
|
||||
expr * get_result() const { return m_result; }
|
||||
expr * get_arg(unsigned idx) const { return m_args[idx]; }
|
||||
|
@ -81,6 +80,8 @@ public:
|
|||
func_interp(ast_manager & m, unsigned arity);
|
||||
~func_interp();
|
||||
|
||||
ast_manager & m () const { return m_manager; }
|
||||
|
||||
func_interp * copy() const;
|
||||
|
||||
unsigned get_arity() const { return m_arity; }
|
||||
|
@ -88,8 +89,9 @@ public:
|
|||
bool is_partial() const { return m_else == 0; }
|
||||
// A function interpretation is said to be simple if m_else is ground.
|
||||
bool is_simple() const { return is_partial() || is_ground(m_else); }
|
||||
|
||||
bool is_constant() const;
|
||||
// Return true if all arguments of the function graph are values.
|
||||
bool args_are_values() const { return m_args_are_values; }
|
||||
|
||||
expr * get_else() const { return m_else; }
|
||||
void set_else(expr * e);
|
||||
|
@ -98,7 +100,6 @@ public:
|
|||
void insert_new_entry(expr * const * args, expr * r);
|
||||
func_entry * get_entry(expr * const * args) const;
|
||||
bool eval_else(expr * const * args, expr_ref & result) const;
|
||||
bool eval(simplifier & s, expr * const * args, expr_ref & result);
|
||||
unsigned num_entries() const { return m_entries.size(); }
|
||||
func_entry const * const * get_entries() const { return m_entries.c_ptr(); }
|
||||
func_entry const * get_entry(unsigned idx) const { return m_entries[idx]; }
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
model_params.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-08-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"model_params.h"
|
||||
|
||||
void model_params::register_params(ini_params & p) {
|
||||
p.register_bool_param("MODEL_PARTIAL", m_model_partial, "enable/disable partial function interpretations", true);
|
||||
p.register_bool_param("MODEL_HIDE_UNUSED_PARTITIONS", m_model_hide_unused_partitions, "hide unused partitions, some partitions are associated with internal terms/formulas created by Z3", true);
|
||||
p.register_bool_param("MODEL_V1", m_model_v1_pp,
|
||||
"use Z3 version 1.x pretty printer", true);
|
||||
p.register_bool_param("MODEL_V2", m_model_v2_pp,
|
||||
"use Z3 version 2.x (x <= 16) pretty printer", true);
|
||||
p.register_bool_param("MODEL_COMPACT", m_model_compact,
|
||||
"try to compact function graph (i.e., function interpretations that are lookup tables", true);
|
||||
p.register_bool_param("MODEL_COMPLETION", m_model_completion,
|
||||
"assigns an interptetation to symbols that do not have one in the current model, when evaluating expressions in the current model", true);
|
||||
p.register_bool_param("MODEL_DISPLAY_ARG_SORT", m_model_display_arg_sort,
|
||||
"display the sort of each argument when printing function interpretations", true);
|
||||
}
|
||||
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
model_params.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-08-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MODEL_PARAMS_H_
|
||||
#define _MODEL_PARAMS_H_
|
||||
|
||||
#include"ini_file.h"
|
||||
|
||||
struct model_params {
|
||||
bool m_model_partial;
|
||||
bool m_model_hide_unused_partitions;
|
||||
bool m_model_compact;
|
||||
bool m_model_v1_pp;
|
||||
bool m_model_v2_pp;
|
||||
bool m_model_completion;
|
||||
bool m_model_display_arg_sort;
|
||||
|
||||
model_params():
|
||||
m_model_partial(false),
|
||||
m_model_hide_unused_partitions(true),
|
||||
m_model_compact(false),
|
||||
m_model_v1_pp(false),
|
||||
m_model_v2_pp(false),
|
||||
m_model_completion(false),
|
||||
m_model_display_arg_sort(true) {
|
||||
}
|
||||
|
||||
void register_params(ini_params & p);
|
||||
};
|
||||
|
||||
#endif /* _MODEL_PARAMS_H_ */
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
numeral_factory.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"numeral_factory.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
app * arith_factory::mk_value_core(rational const & val, sort * s) {
|
||||
return m_util.mk_numeral(val, s);
|
||||
}
|
||||
|
||||
arith_factory::arith_factory(ast_manager & m):
|
||||
numeral_factory(m, m.get_family_id("arith")),
|
||||
m_util(m) {
|
||||
}
|
||||
|
||||
arith_factory::~arith_factory() {
|
||||
}
|
||||
|
||||
app * arith_factory::mk_value(rational const & val, bool is_int) {
|
||||
return numeral_factory::mk_value(val, is_int ? m_util.mk_int() : m_util.mk_real());
|
||||
}
|
||||
|
||||
bv_factory::bv_factory(ast_manager & m):
|
||||
numeral_factory(m, m.get_family_id("bv")),
|
||||
m_util(m) {
|
||||
}
|
||||
|
||||
bv_factory::~bv_factory() {
|
||||
}
|
||||
|
||||
app * bv_factory::mk_value_core(rational const & val, sort * s) {
|
||||
return m_util.mk_numeral(val, s);
|
||||
}
|
||||
|
||||
app * bv_factory::mk_value(rational const & val, unsigned bv_size) {
|
||||
return numeral_factory::mk_value(val, m_util.mk_sort(bv_size));
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
numeral_factory.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _NUMERAL_FACTORY_H_
|
||||
#define _NUMERAL_FACTORY_H_
|
||||
|
||||
#include"value_factory.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
|
||||
class numeral_factory : public simple_factory<rational> {
|
||||
public:
|
||||
numeral_factory(ast_manager & m, family_id fid):simple_factory<rational>(m, fid) {}
|
||||
virtual ~numeral_factory() {}
|
||||
};
|
||||
|
||||
class arith_factory : public numeral_factory {
|
||||
arith_util m_util;
|
||||
|
||||
virtual app * mk_value_core(rational const & val, sort * s);
|
||||
|
||||
public:
|
||||
arith_factory(ast_manager & m);
|
||||
virtual ~arith_factory();
|
||||
|
||||
app * mk_value(rational const & val, bool is_int);
|
||||
};
|
||||
|
||||
class bv_factory : public numeral_factory {
|
||||
bv_util m_util;
|
||||
|
||||
virtual app * mk_value_core(rational const & val, sort * s);
|
||||
|
||||
public:
|
||||
bv_factory(ast_manager & m);
|
||||
virtual ~bv_factory();
|
||||
|
||||
app * mk_value(rational const & val, unsigned bv_size);
|
||||
};
|
||||
|
||||
#endif /* _NUMERAL_FACTORY_H_ */
|
||||
|
|
@ -1,607 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
proto_model.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-03-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"proto_model.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"var_subst.h"
|
||||
#include"array_decl_plugin.h"
|
||||
#include"well_sorted.h"
|
||||
#include"used_symbols.h"
|
||||
#include"model_v2_pp.h"
|
||||
|
||||
proto_model::proto_model(ast_manager & m, simplifier & s, model_params const & p):
|
||||
model_core(m),
|
||||
m_params(p),
|
||||
m_asts(m),
|
||||
m_simplifier(s),
|
||||
m_afid(m.get_family_id(symbol("array"))) {
|
||||
register_factory(alloc(basic_factory, m));
|
||||
m_user_sort_factory = alloc(user_sort_factory, m);
|
||||
register_factory(m_user_sort_factory);
|
||||
}
|
||||
|
||||
void proto_model::reset_finterp() {
|
||||
decl2finterp::iterator it = m_finterp.begin();
|
||||
decl2finterp::iterator end = m_finterp.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
proto_model::~proto_model() {
|
||||
reset_finterp();
|
||||
}
|
||||
|
||||
void proto_model::register_decl(func_decl * d, expr * v) {
|
||||
SASSERT(d->get_arity() == 0);
|
||||
if (m_interp.contains(d)) {
|
||||
DEBUG_CODE({
|
||||
expr * old_v = 0;
|
||||
m_interp.find(d, old_v);
|
||||
SASSERT(old_v == v);
|
||||
});
|
||||
return;
|
||||
}
|
||||
SASSERT(!m_interp.contains(d));
|
||||
m_decls.push_back(d);
|
||||
m_asts.push_back(d);
|
||||
m_asts.push_back(v);
|
||||
m_interp.insert(d, v);
|
||||
m_const_decls.push_back(d);
|
||||
}
|
||||
|
||||
void proto_model::register_decl(func_decl * d, func_interp * fi, bool aux) {
|
||||
SASSERT(d->get_arity() > 0);
|
||||
SASSERT(!m_finterp.contains(d));
|
||||
m_decls.push_back(d);
|
||||
m_asts.push_back(d);
|
||||
m_finterp.insert(d, fi);
|
||||
m_func_decls.push_back(d);
|
||||
if (aux)
|
||||
m_aux_decls.insert(d);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set new_fi as the new interpretation for f.
|
||||
If f_aux != 0, then assign the old interpretation of f to f_aux.
|
||||
If f_aux == 0, then delete the old interpretation of f.
|
||||
|
||||
f_aux is marked as a auxiliary declaration.
|
||||
*/
|
||||
void proto_model::reregister_decl(func_decl * f, func_interp * new_fi, func_decl * f_aux) {
|
||||
func_interp * fi = get_func_interp(f);
|
||||
if (fi == 0) {
|
||||
register_decl(f, new_fi);
|
||||
}
|
||||
else {
|
||||
if (f_aux != 0) {
|
||||
register_decl(f_aux, fi);
|
||||
m_aux_decls.insert(f_aux);
|
||||
}
|
||||
else {
|
||||
dealloc(fi);
|
||||
}
|
||||
m_finterp.insert(f, new_fi);
|
||||
}
|
||||
}
|
||||
|
||||
expr * proto_model::mk_some_interp_for(func_decl * d) {
|
||||
SASSERT(!has_interpretation(d));
|
||||
expr * r = get_some_value(d->get_range()); // if t is a function, then it will be the constant function.
|
||||
if (d->get_arity() == 0) {
|
||||
register_decl(d, r);
|
||||
}
|
||||
else {
|
||||
func_interp * new_fi = alloc(func_interp, m_manager, d->get_arity());
|
||||
new_fi->set_else(r);
|
||||
register_decl(d, new_fi);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the expression e in the current model, and store the result in \c result.
|
||||
It returns \c true if succeeded, and false otherwise. If the evaluation fails,
|
||||
then r contains a term that is simplified as much as possible using the interpretations
|
||||
available in the model.
|
||||
|
||||
When model_completion == true, if the model does not assign an interpretation to a
|
||||
declaration it will build one for it. Moreover, partial functions will also be completed.
|
||||
So, if model_completion == true, the evaluator never fails if it doesn't contain quantifiers.
|
||||
*/
|
||||
bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
|
||||
bool is_ok = true;
|
||||
SASSERT(is_well_sorted(m_manager, e));
|
||||
TRACE("model_eval", tout << mk_pp(e, m_manager) << "\n";
|
||||
tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n";);
|
||||
|
||||
obj_map<expr, expr*> eval_cache;
|
||||
expr_ref_vector trail(m_manager);
|
||||
sbuffer<std::pair<expr*, expr*>, 128> todo;
|
||||
ptr_buffer<expr> args;
|
||||
expr * null = static_cast<expr*>(0);
|
||||
todo.push_back(std::make_pair(e, null));
|
||||
|
||||
expr * a;
|
||||
expr * expanded_a;
|
||||
while (!todo.empty()) {
|
||||
std::pair<expr *, expr *> & p = todo.back();
|
||||
a = p.first;
|
||||
expanded_a = p.second;
|
||||
if (expanded_a != 0) {
|
||||
expr * r = 0;
|
||||
eval_cache.find(expanded_a, r);
|
||||
SASSERT(r != 0);
|
||||
todo.pop_back();
|
||||
eval_cache.insert(a, r);
|
||||
TRACE("model_eval",
|
||||
tout << "orig:\n" << mk_pp(a, m_manager) << "\n";
|
||||
tout << "after beta reduction:\n" << mk_pp(expanded_a, m_manager) << "\n";
|
||||
tout << "new:\n" << mk_pp(r, m_manager) << "\n";);
|
||||
}
|
||||
else {
|
||||
switch(a->get_kind()) {
|
||||
case AST_APP: {
|
||||
app * t = to_app(a);
|
||||
bool visited = true;
|
||||
args.reset();
|
||||
unsigned num_args = t->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
expr * arg = 0;
|
||||
if (!eval_cache.find(t->get_arg(i), arg)) {
|
||||
visited = false;
|
||||
todo.push_back(std::make_pair(t->get_arg(i), null));
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (!visited) {
|
||||
continue;
|
||||
}
|
||||
SASSERT(args.size() == t->get_num_args());
|
||||
expr_ref new_t(m_manager);
|
||||
func_decl * f = t->get_decl();
|
||||
|
||||
if (!has_interpretation(f)) {
|
||||
// the model does not assign an interpretation to f.
|
||||
SASSERT(new_t.get() == 0);
|
||||
if (f->get_family_id() == null_family_id) {
|
||||
if (model_completion) {
|
||||
// create an interpretation for f.
|
||||
new_t = mk_some_interp_for(f);
|
||||
}
|
||||
else {
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
if (new_t.get() == 0) {
|
||||
// t is interpreted or model completion is disabled.
|
||||
m_simplifier.mk_app(f, num_args, args.c_ptr(), new_t);
|
||||
trail.push_back(new_t);
|
||||
if (!is_app(new_t) || to_app(new_t)->get_decl() != f) {
|
||||
// if the result is not of the form (f ...), then assume we must simplify it.
|
||||
expr * new_new_t = 0;
|
||||
if (!eval_cache.find(new_t.get(), new_new_t)) {
|
||||
todo.back().second = new_t;
|
||||
todo.push_back(std::make_pair(new_t, null));
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
new_t = new_new_t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the model has an interpretaion for f.
|
||||
if (num_args == 0) {
|
||||
// t is a constant
|
||||
new_t = get_const_interp(f);
|
||||
}
|
||||
else {
|
||||
// t is a function application
|
||||
SASSERT(new_t.get() == 0);
|
||||
// try to use function graph first
|
||||
func_interp * fi = get_func_interp(f);
|
||||
SASSERT(fi->get_arity() == num_args);
|
||||
expr_ref r1(m_manager);
|
||||
// fi may be partial...
|
||||
if (!fi->eval(m_simplifier, args.c_ptr(), r1)) {
|
||||
SASSERT(fi->is_partial()); // fi->eval only fails when fi is partial.
|
||||
if (model_completion) {
|
||||
expr * r = get_some_value(f->get_range());
|
||||
fi->set_else(r);
|
||||
SASSERT(!fi->is_partial());
|
||||
new_t = r;
|
||||
}
|
||||
else {
|
||||
// f is an uninterpreted function, there is no need to use m_simplifier.mk_app
|
||||
new_t = m_manager.mk_app(f, num_args, args.c_ptr());
|
||||
trail.push_back(new_t);
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(r1);
|
||||
trail.push_back(r1);
|
||||
expr * r2 = 0;
|
||||
if (!eval_cache.find(r1.get(), r2)) {
|
||||
todo.back().second = r1;
|
||||
todo.push_back(std::make_pair(r1, null));
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
new_t = r2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("model_eval",
|
||||
tout << "orig:\n" << mk_pp(t, m_manager) << "\n";
|
||||
tout << "new:\n" << mk_pp(new_t, m_manager) << "\n";);
|
||||
todo.pop_back();
|
||||
SASSERT(new_t.get() != 0);
|
||||
eval_cache.insert(t, new_t);
|
||||
break;
|
||||
}
|
||||
case AST_VAR:
|
||||
SASSERT(a != 0);
|
||||
eval_cache.insert(a, a);
|
||||
todo.pop_back();
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
is_ok = false; // evaluator does not handle quantifiers.
|
||||
SASSERT(a != 0);
|
||||
eval_cache.insert(a, a);
|
||||
todo.pop_back();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!eval_cache.find(e, a)) {
|
||||
TRACE("model_eval", tout << "FAILED e: " << mk_bounded_pp(e, m_manager) << "\n";);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
result = a;
|
||||
TRACE("model_eval",
|
||||
ast_ll_pp(tout << "original: ", m_manager, e);
|
||||
ast_ll_pp(tout << "evaluated: ", m_manager, a);
|
||||
ast_ll_pp(tout << "reduced: ", m_manager, result.get());
|
||||
tout << "sort: " << mk_pp(m_manager.get_sort(e), m_manager) << "\n";
|
||||
);
|
||||
SASSERT(is_well_sorted(m_manager, result.get()));
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Replace uninterpreted constants occurring in fi->get_else()
|
||||
by their interpretations.
|
||||
*/
|
||||
void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_aux_fs) {
|
||||
if (fi->is_partial())
|
||||
return;
|
||||
expr * fi_else = fi->get_else();
|
||||
TRACE("model_bug", tout << "cleaning up:\n" << mk_pp(fi_else, m_manager) << "\n";);
|
||||
|
||||
obj_map<expr, expr*> cache;
|
||||
expr_ref_vector trail(m_manager);
|
||||
ptr_buffer<expr, 128> todo;
|
||||
ptr_buffer<expr> args;
|
||||
todo.push_back(fi_else);
|
||||
|
||||
expr * a;
|
||||
while (!todo.empty()) {
|
||||
a = todo.back();
|
||||
if (is_uninterp_const(a)) {
|
||||
todo.pop_back();
|
||||
func_decl * a_decl = to_app(a)->get_decl();
|
||||
expr * ai = get_const_interp(a_decl);
|
||||
if (ai == 0) {
|
||||
ai = get_some_value(a_decl->get_range());
|
||||
register_decl(a_decl, ai);
|
||||
}
|
||||
cache.insert(a, ai);
|
||||
}
|
||||
else {
|
||||
switch(a->get_kind()) {
|
||||
case AST_APP: {
|
||||
app * t = to_app(a);
|
||||
bool visited = true;
|
||||
args.reset();
|
||||
unsigned num_args = t->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
expr * arg = 0;
|
||||
if (!cache.find(t->get_arg(i), arg)) {
|
||||
visited = false;
|
||||
todo.push_back(t->get_arg(i));
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (!visited) {
|
||||
continue;
|
||||
}
|
||||
func_decl * f = t->get_decl();
|
||||
if (m_aux_decls.contains(f))
|
||||
found_aux_fs.insert(f);
|
||||
expr_ref new_t(m_manager);
|
||||
m_simplifier.mk_app(f, num_args, args.c_ptr(), new_t);
|
||||
if (t != new_t.get())
|
||||
trail.push_back(new_t);
|
||||
todo.pop_back();
|
||||
cache.insert(t, new_t);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SASSERT(a != 0);
|
||||
cache.insert(a, a);
|
||||
todo.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache.find(fi_else, a)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
fi->set_else(a);
|
||||
}
|
||||
|
||||
void proto_model::remove_aux_decls_not_in_set(ptr_vector<func_decl> & decls, func_decl_set const & s) {
|
||||
unsigned sz = decls.size();
|
||||
unsigned i = 0;
|
||||
unsigned j = 0;
|
||||
for (; i < sz; i++) {
|
||||
func_decl * f = decls[i];
|
||||
if (!m_aux_decls.contains(f) || s.contains(f)) {
|
||||
decls[j] = f;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
decls.shrink(j);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Replace uninterpreted constants occurring in the func_interp's get_else()
|
||||
by their interpretations.
|
||||
*/
|
||||
void proto_model::cleanup() {
|
||||
func_decl_set found_aux_fs;
|
||||
decl2finterp::iterator it = m_finterp.begin();
|
||||
decl2finterp::iterator end = m_finterp.end();
|
||||
for (; it != end; ++it) {
|
||||
func_interp * fi = (*it).m_value;
|
||||
cleanup_func_interp(fi, found_aux_fs);
|
||||
}
|
||||
|
||||
// remove auxiliary declarations that are not used.
|
||||
if (found_aux_fs.size() != m_aux_decls.size()) {
|
||||
remove_aux_decls_not_in_set(m_decls, found_aux_fs);
|
||||
remove_aux_decls_not_in_set(m_func_decls, found_aux_fs);
|
||||
|
||||
func_decl_set::iterator it2 = m_aux_decls.begin();
|
||||
func_decl_set::iterator end2 = m_aux_decls.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
func_decl * faux = *it2;
|
||||
if (!found_aux_fs.contains(faux)) {
|
||||
TRACE("cleanup_bug", tout << "eliminating " << faux->get_name() << "\n";);
|
||||
func_interp * fi = 0;
|
||||
m_finterp.find(faux, fi);
|
||||
SASSERT(fi != 0);
|
||||
m_finterp.erase(faux);
|
||||
dealloc(fi);
|
||||
}
|
||||
}
|
||||
m_aux_decls.swap(found_aux_fs);
|
||||
}
|
||||
}
|
||||
|
||||
value_factory * proto_model::get_factory(family_id fid) {
|
||||
return m_factories.get_plugin(fid);
|
||||
}
|
||||
|
||||
void proto_model::freeze_universe(sort * s) {
|
||||
SASSERT(m_manager.is_uninterp(s));
|
||||
m_user_sort_factory->freeze_universe(s);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the known universe of an uninterpreted sort.
|
||||
*/
|
||||
obj_hashtable<expr> const & proto_model::get_known_universe(sort * s) const {
|
||||
SASSERT(m_manager.is_uninterp(s));
|
||||
return m_user_sort_factory->get_known_universe(s);
|
||||
}
|
||||
|
||||
ptr_vector<expr> const & proto_model::get_universe(sort * s) const {
|
||||
ptr_vector<expr> & tmp = const_cast<proto_model*>(this)->m_tmp;
|
||||
tmp.reset();
|
||||
obj_hashtable<expr> const & u = get_known_universe(s);
|
||||
obj_hashtable<expr>::iterator it = u.begin();
|
||||
obj_hashtable<expr>::iterator end = u.end();
|
||||
for (; it != end; ++it)
|
||||
tmp.push_back(*it);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned proto_model::get_num_uninterpreted_sorts() const {
|
||||
return m_user_sort_factory->get_num_sorts();
|
||||
}
|
||||
|
||||
sort * proto_model::get_uninterpreted_sort(unsigned idx) const {
|
||||
SASSERT(idx < get_num_uninterpreted_sorts());
|
||||
return m_user_sort_factory->get_sort(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the given sort is uninterpreted and has a finite interpretation
|
||||
in the model.
|
||||
*/
|
||||
bool proto_model::is_finite(sort * s) const {
|
||||
return m_manager.is_uninterp(s) && m_user_sort_factory->is_finite(s);
|
||||
}
|
||||
|
||||
expr * proto_model::get_some_value(sort * s) {
|
||||
family_id fid = s->get_family_id();
|
||||
if (fid == null_family_id) {
|
||||
return m_user_sort_factory->get_some_value(s);
|
||||
}
|
||||
value_factory * f = get_factory(fid);
|
||||
if (f)
|
||||
return f->get_some_value(s);
|
||||
// there is no factory for the family id, then assume s is uninterpreted.
|
||||
return m_user_sort_factory->get_some_value(s);
|
||||
}
|
||||
|
||||
bool proto_model::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
family_id fid = s->get_family_id();
|
||||
if (fid == null_family_id) {
|
||||
return m_user_sort_factory->get_some_values(s, v1, v2);
|
||||
}
|
||||
value_factory * f = get_factory(fid);
|
||||
if (f)
|
||||
return f->get_some_values(s, v1, v2);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
expr * proto_model::get_fresh_value(sort * s) {
|
||||
family_id fid = s->get_family_id();
|
||||
if (fid == null_family_id)
|
||||
return m_user_sort_factory->get_fresh_value(s);
|
||||
value_factory * f = get_factory(fid);
|
||||
if (f)
|
||||
return f->get_fresh_value(s);
|
||||
else
|
||||
// Use user_sort_factory if the theory has no support for model construnction.
|
||||
// This is needed when dummy theories are used for arithmetic or arrays.
|
||||
return m_user_sort_factory->get_fresh_value(s);
|
||||
}
|
||||
|
||||
void proto_model::register_value(expr * n) {
|
||||
sort * s = m_manager.get_sort(n);
|
||||
family_id fid = s->get_family_id();
|
||||
if (fid == null_family_id) {
|
||||
m_user_sort_factory->register_value(n);
|
||||
}
|
||||
else {
|
||||
value_factory * f = get_factory(fid);
|
||||
if (f)
|
||||
f->register_value(n);
|
||||
}
|
||||
}
|
||||
|
||||
bool proto_model::is_array_value(expr * v) const {
|
||||
return is_app_of(v, m_afid, OP_AS_ARRAY);
|
||||
}
|
||||
|
||||
void proto_model::compress() {
|
||||
ptr_vector<func_decl>::iterator it = m_func_decls.begin();
|
||||
ptr_vector<func_decl>::iterator end = m_func_decls.end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * f = *it;
|
||||
func_interp * fi = get_func_interp(f);
|
||||
SASSERT(fi != 0);
|
||||
fi->compress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Complete the interpretation fi of f if it is partial.
|
||||
If f does not have an interpretation in the given model, then this is a noop.
|
||||
*/
|
||||
void proto_model::complete_partial_func(func_decl * f) {
|
||||
func_interp * fi = get_func_interp(f);
|
||||
if (fi && fi->is_partial()) {
|
||||
expr * else_value = 0;
|
||||
#if 0
|
||||
// For UFBV benchmarks, setting the "else" to false is not a good idea.
|
||||
// TODO: find a permanent solution. A possibility is to add another option.
|
||||
if (m_manager.is_bool(f->get_range())) {
|
||||
else_value = m_manager.mk_false();
|
||||
}
|
||||
else {
|
||||
else_value = fi->get_max_occ_result();
|
||||
if (else_value == 0)
|
||||
else_value = get_some_value(f->get_range());
|
||||
}
|
||||
#else
|
||||
else_value = fi->get_max_occ_result();
|
||||
if (else_value == 0)
|
||||
else_value = get_some_value(f->get_range());
|
||||
#endif
|
||||
fi->set_else(else_value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set the (else) field of function interpretations...
|
||||
*/
|
||||
void proto_model::complete_partial_funcs() {
|
||||
if (m_params.m_model_partial)
|
||||
return;
|
||||
|
||||
ptr_vector<func_decl>::iterator it = m_func_decls.begin();
|
||||
ptr_vector<func_decl>::iterator end = m_func_decls.end();
|
||||
for (; it != end; ++it)
|
||||
complete_partial_func(*it);
|
||||
}
|
||||
|
||||
model * proto_model::mk_model() {
|
||||
TRACE("proto_model", tout << "mk_model\n"; model_v2_pp(tout, *this););
|
||||
model * m = alloc(model, m_manager);
|
||||
|
||||
decl2expr::iterator it1 = m_interp.begin();
|
||||
decl2expr::iterator end1 = m_interp.end();
|
||||
for (; it1 != end1; ++it1) {
|
||||
m->register_decl(it1->m_key, it1->m_value);
|
||||
}
|
||||
|
||||
decl2finterp::iterator it2 = m_finterp.begin();
|
||||
decl2finterp::iterator end2 = m_finterp.end();
|
||||
for (; it2 != end2; ++it2) {
|
||||
m->register_decl(it2->m_key, it2->m_value);
|
||||
}
|
||||
m_finterp.reset(); // m took the ownership of the func_interp's
|
||||
|
||||
unsigned sz = get_num_uninterpreted_sorts();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
sort * s = get_uninterpreted_sort(i);
|
||||
TRACE("proto_model", tout << "copying uninterpreted sorts...\n" << mk_pp(s, m_manager) << "\n";);
|
||||
ptr_buffer<expr> buf;
|
||||
obj_hashtable<expr> const & u = get_known_universe(s);
|
||||
obj_hashtable<expr>::iterator it = u.begin();
|
||||
obj_hashtable<expr>::iterator end = u.end();
|
||||
for (; it != end; ++it) {
|
||||
buf.push_back(*it);
|
||||
}
|
||||
m->register_usort(s, buf.size(), buf.c_ptr());
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
proto_model.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the old model object.
|
||||
smt::context used it during model construction and for
|
||||
reporting the model for external consumers.
|
||||
The whole value_factory "business" was due to model construction
|
||||
and unnecessary for external consumers.
|
||||
Future solvers will not use value_factory objects for
|
||||
helping during model construction.
|
||||
|
||||
After smt::context finishes building the model, it is converted
|
||||
into a new (light) model object.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-03-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PROTO_MODEL_H_
|
||||
#define _PROTO_MODEL_H_
|
||||
|
||||
#include"model_core.h"
|
||||
#include"model_params.h"
|
||||
#include"value_factory.h"
|
||||
#include"plugin_manager.h"
|
||||
#include"simplifier.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"func_decl_dependencies.h"
|
||||
#include"model.h"
|
||||
|
||||
class proto_model : public model_core {
|
||||
model_params const & m_params;
|
||||
ast_ref_vector m_asts;
|
||||
plugin_manager<value_factory> m_factories;
|
||||
user_sort_factory * m_user_sort_factory;
|
||||
simplifier & m_simplifier;
|
||||
family_id m_afid; //!< array family id: hack for displaying models in V1.x style
|
||||
func_decl_set m_aux_decls;
|
||||
ptr_vector<expr> m_tmp;
|
||||
|
||||
void reset_finterp();
|
||||
|
||||
expr * mk_some_interp_for(func_decl * d);
|
||||
|
||||
// Invariant: m_decls subset m_func_decls union m_const_decls union union m_value_decls
|
||||
// Invariant: m_func_decls subset m_decls
|
||||
// Invariant: m_const_decls subset m_decls
|
||||
|
||||
void remove_aux_decls_not_in_set(ptr_vector<func_decl> & decls, func_decl_set const & s);
|
||||
void cleanup_func_interp(func_interp * fi, func_decl_set & found_aux_fs);
|
||||
|
||||
|
||||
public:
|
||||
proto_model(ast_manager & m, simplifier & s, model_params const & p);
|
||||
virtual ~proto_model();
|
||||
|
||||
model_params const & get_model_params() const { return m_params; }
|
||||
|
||||
void register_factory(value_factory * f) { m_factories.register_plugin(f); }
|
||||
|
||||
bool eval(expr * e, expr_ref & result, bool model_completion = false);
|
||||
|
||||
bool is_array_value(expr * v) const;
|
||||
|
||||
value_factory * get_factory(family_id fid);
|
||||
|
||||
expr * get_some_value(sort * s);
|
||||
|
||||
bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
|
||||
|
||||
expr * get_fresh_value(sort * s);
|
||||
|
||||
void register_value(expr * n);
|
||||
|
||||
//
|
||||
// Primitives for building models
|
||||
//
|
||||
void register_decl(func_decl * d, expr * v);
|
||||
void register_decl(func_decl * f, func_interp * fi, bool aux = false);
|
||||
void reregister_decl(func_decl * f, func_interp * new_fi, func_decl * f_aux);
|
||||
void compress();
|
||||
void cleanup();
|
||||
|
||||
//
|
||||
// Primitives for building finite interpretations for uninterpreted sorts,
|
||||
// and retrieving the known universe.
|
||||
//
|
||||
void freeze_universe(sort * s);
|
||||
bool is_finite(sort * s) const;
|
||||
obj_hashtable<expr> const & get_known_universe(sort * s) const;
|
||||
virtual ptr_vector<expr> const & get_universe(sort * s) const;
|
||||
virtual unsigned get_num_uninterpreted_sorts() const;
|
||||
virtual sort * get_uninterpreted_sort(unsigned idx) const;
|
||||
|
||||
//
|
||||
// Complete partial function interps
|
||||
//
|
||||
void complete_partial_func(func_decl * f);
|
||||
void complete_partial_funcs();
|
||||
|
||||
//
|
||||
// Create final model object.
|
||||
// proto_model is corrupted after that.
|
||||
model * mk_model();
|
||||
};
|
||||
|
||||
typedef ref<proto_model> proto_model_ref;
|
||||
|
||||
#endif /* _PROTO_MODEL_H_ */
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
struct_factory.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-11-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"struct_factory.h"
|
||||
#include"proto_model.h"
|
||||
|
||||
struct_factory::value_set * struct_factory::get_value_set(sort * s) {
|
||||
value_set * set = 0;
|
||||
if (!m_sort2value_set.find(s, set)) {
|
||||
set = alloc(value_set);
|
||||
m_sort2value_set.insert(s, set);
|
||||
m_sorts.push_back(s);
|
||||
m_sets.push_back(set);
|
||||
}
|
||||
SASSERT(set != 0);
|
||||
return set;
|
||||
}
|
||||
|
||||
struct_factory::struct_factory(ast_manager & m, family_id fid, proto_model & md):
|
||||
value_factory(m, fid),
|
||||
m_model(md),
|
||||
m_values(m),
|
||||
m_sorts(m) {
|
||||
}
|
||||
|
||||
struct_factory::~struct_factory() {
|
||||
std::for_each(m_sets.begin(), m_sets.end(), delete_proc<value_set>());
|
||||
}
|
||||
|
||||
void struct_factory::register_value(expr * new_value) {
|
||||
sort * s = m_manager.get_sort(new_value);
|
||||
value_set * set = get_value_set(s);
|
||||
if (!set->contains(new_value)) {
|
||||
m_values.push_back(new_value);
|
||||
set->insert(new_value);
|
||||
}
|
||||
}
|
||||
|
||||
bool struct_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
value_set * set = get_value_set(s);
|
||||
switch (set->size()) {
|
||||
case 0:
|
||||
v1 = get_fresh_value(s);
|
||||
v2 = get_fresh_value(s);
|
||||
return v1 != 0 && v2 != 0;
|
||||
case 1:
|
||||
v1 = get_some_value(s);
|
||||
v2 = get_fresh_value(s);
|
||||
return v2 != 0;
|
||||
default:
|
||||
obj_hashtable<expr>::iterator it = set->begin();
|
||||
v1 = *it;
|
||||
++it;
|
||||
v2 = *it;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
struct_factory.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-11-06.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _STRUCT_FACTORY_H_
|
||||
#define _STRUCT_FACTORY_H_
|
||||
|
||||
#include"value_factory.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
class proto_model;
|
||||
|
||||
/**
|
||||
\brief Abstract factory for structured values such as: arrays and algebraic datatypes.
|
||||
*/
|
||||
class struct_factory : public value_factory {
|
||||
protected:
|
||||
typedef obj_hashtable<expr> value_set;
|
||||
typedef obj_map<sort, value_set *> sort2value_set;
|
||||
|
||||
proto_model & m_model;
|
||||
sort2value_set m_sort2value_set;
|
||||
expr_ref_vector m_values;
|
||||
sort_ref_vector m_sorts;
|
||||
ptr_vector<value_set> m_sets;
|
||||
|
||||
value_set * get_value_set(sort * s);
|
||||
|
||||
public:
|
||||
struct_factory(ast_manager & m, family_id fid, proto_model & md);
|
||||
|
||||
virtual ~struct_factory();
|
||||
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
|
||||
|
||||
virtual void register_value(expr * array_value);
|
||||
|
||||
proto_model & get_model() { return m_model; }
|
||||
};
|
||||
|
||||
#endif /* _STRUCT_FACTORY_H_ */
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
value_factory.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"value_factory.h"
|
||||
|
||||
value_factory::value_factory(ast_manager & m, family_id fid):
|
||||
m_manager(m),
|
||||
m_fid(fid) {
|
||||
}
|
||||
|
||||
value_factory::~value_factory() {
|
||||
}
|
||||
|
||||
basic_factory::basic_factory(ast_manager & m):
|
||||
value_factory(m, m.get_basic_family_id()) {
|
||||
}
|
||||
|
||||
expr * basic_factory::get_some_value(sort * s) {
|
||||
if (m_manager.is_bool(s))
|
||||
return m_manager.mk_false();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool basic_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
if (m_manager.is_bool(s)) {
|
||||
v1 = m_manager.mk_false();
|
||||
v2 = m_manager.mk_true();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
expr * basic_factory::get_fresh_value(sort * s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
user_sort_factory::user_sort_factory(ast_manager & m):
|
||||
simple_factory<unsigned>(m, m.get_family_id("user-sort")) {
|
||||
}
|
||||
|
||||
void user_sort_factory::freeze_universe(sort * s) {
|
||||
if (!m_finite.contains(s)) {
|
||||
value_set * set = 0;
|
||||
m_sort2value_set.find(s, set);
|
||||
if (!m_sort2value_set.find(s, set) || set->m_values.empty()) {
|
||||
// we cannot freeze an empty universe.
|
||||
get_some_value(s); // add one element to the universe...
|
||||
}
|
||||
SASSERT(m_sort2value_set.find(s, set) && set != 0 && !set->m_values.empty());
|
||||
m_finite.insert(s);
|
||||
}
|
||||
}
|
||||
|
||||
obj_hashtable<expr> const & user_sort_factory::get_known_universe(sort * s) const {
|
||||
value_set * set = 0;
|
||||
if (m_sort2value_set.find(s, set)) {
|
||||
return set->m_values;
|
||||
}
|
||||
return m_empty_universe;
|
||||
}
|
||||
|
||||
expr * user_sort_factory::get_some_value(sort * s) {
|
||||
if (is_finite(s)) {
|
||||
value_set * set = 0;
|
||||
m_sort2value_set.find(s, set);
|
||||
SASSERT(set != 0);
|
||||
SASSERT(!set->m_values.empty());
|
||||
return *(set->m_values.begin());
|
||||
}
|
||||
return simple_factory<unsigned>::get_some_value(s);
|
||||
}
|
||||
|
||||
bool user_sort_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
if (is_finite(s)) {
|
||||
value_set * set = 0;
|
||||
if (m_sort2value_set.find(s, set) && set->m_values.size() >= 2) {
|
||||
obj_hashtable<expr>::iterator it = set->m_values.begin();
|
||||
v1 = *it;
|
||||
++it;
|
||||
v2 = *it;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return simple_factory<unsigned>::get_some_values(s, v1, v2);
|
||||
}
|
||||
|
||||
expr * user_sort_factory::get_fresh_value(sort * s) {
|
||||
if (is_finite(s))
|
||||
return 0;
|
||||
return simple_factory<unsigned>::get_fresh_value(s);
|
||||
}
|
||||
|
||||
void user_sort_factory::register_value(expr * n) {
|
||||
SASSERT(!is_finite(m_manager.get_sort(n)));
|
||||
simple_factory<unsigned>::register_value(n);
|
||||
}
|
||||
|
||||
app * user_sort_factory::mk_value_core(unsigned const & val, sort * s) {
|
||||
return m_manager.mk_model_value(val, s);
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
value_factory.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _VALUE_FACTORY_H_
|
||||
#define _VALUE_FACTORY_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
/**
|
||||
\brief Auxiliary object used during model construction.
|
||||
*/
|
||||
class value_factory {
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
family_id m_fid;
|
||||
public:
|
||||
value_factory(ast_manager & m, family_id fid);
|
||||
|
||||
virtual ~value_factory();
|
||||
|
||||
/**
|
||||
\brief Return some value of the given sort. The result is always different from zero.
|
||||
*/
|
||||
virtual expr * get_some_value(sort * s) = 0;
|
||||
|
||||
/**
|
||||
\brief Return two distinct values of the given sort. The results are stored in v1 and v2.
|
||||
Return false if the intended interpretation of the given sort has only one element.
|
||||
*/
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) = 0;
|
||||
|
||||
/**
|
||||
\brief Return a fresh value of the given sort.
|
||||
Return 0 if it is not possible to do that (e.g., the sort is finite).
|
||||
*/
|
||||
virtual expr * get_fresh_value(sort * s) = 0;
|
||||
|
||||
/**
|
||||
\brief Used to register that the given value was used in model construction.
|
||||
So, get_fresh_value cannot return this value anymore.
|
||||
*/
|
||||
virtual void register_value(expr * n) = 0;
|
||||
|
||||
family_id get_family_id() const { return m_fid; }
|
||||
};
|
||||
|
||||
class basic_factory : public value_factory {
|
||||
public:
|
||||
basic_factory(ast_manager & m);
|
||||
|
||||
virtual expr * get_some_value(sort * s);
|
||||
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
|
||||
|
||||
virtual expr * get_fresh_value(sort * s);
|
||||
|
||||
virtual void register_value(expr * n) { }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Template for value factories for numeric (and enumeration-like) sorts
|
||||
*/
|
||||
template<typename Number>
|
||||
class simple_factory : public value_factory {
|
||||
protected:
|
||||
struct value_set {
|
||||
obj_hashtable<expr> m_values;
|
||||
Number m_next;
|
||||
value_set():
|
||||
m_next(0) {
|
||||
}
|
||||
};
|
||||
|
||||
typedef obj_map<sort, value_set *> sort2value_set;
|
||||
|
||||
sort2value_set m_sort2value_set;
|
||||
expr_ref_vector m_values;
|
||||
sort_ref_vector m_sorts;
|
||||
ptr_vector<value_set> m_sets;
|
||||
|
||||
value_set * get_value_set(sort * s) {
|
||||
value_set * set = 0;
|
||||
if (!m_sort2value_set.find(s, set)) {
|
||||
set = alloc(value_set);
|
||||
m_sort2value_set.insert(s, set);
|
||||
m_sorts.push_back(s);
|
||||
m_sets.push_back(set);
|
||||
}
|
||||
SASSERT(set != 0);
|
||||
DEBUG_CODE({
|
||||
value_set * set2 = 0;
|
||||
SASSERT(m_sort2value_set.find(s, set2));
|
||||
SASSERT(set == set2);
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
virtual app * mk_value_core(Number const & val, sort * s) = 0;
|
||||
|
||||
app * mk_value(Number const & val, sort * s, bool & is_new) {
|
||||
value_set * set = get_value_set(s);
|
||||
app * new_val = mk_value_core(val, s);
|
||||
is_new = false;
|
||||
if (!set->m_values.contains(new_val)) {
|
||||
m_values.push_back(new_val);
|
||||
set->m_values.insert(new_val);
|
||||
is_new = true;
|
||||
}
|
||||
SASSERT(set->m_values.contains(new_val));
|
||||
return new_val;
|
||||
}
|
||||
|
||||
public:
|
||||
simple_factory(ast_manager & m, family_id fid):
|
||||
value_factory(m, fid),
|
||||
m_values(m),
|
||||
m_sorts(m) {
|
||||
}
|
||||
|
||||
virtual ~simple_factory() {
|
||||
std::for_each(m_sets.begin(), m_sets.end(), delete_proc<value_set>());
|
||||
}
|
||||
|
||||
virtual expr * get_some_value(sort * s) {
|
||||
value_set * set = 0;
|
||||
expr * result = 0;
|
||||
if (m_sort2value_set.find(s, set) && !set->m_values.empty())
|
||||
result = *(set->m_values.begin());
|
||||
else
|
||||
result = mk_value(Number(0), s);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
value_set * set = 0;
|
||||
if (m_sort2value_set.find(s, set)) {
|
||||
switch (set->m_values.size()) {
|
||||
case 0:
|
||||
v1 = mk_value(Number(0), s);
|
||||
v2 = mk_value(Number(1), s);
|
||||
break;
|
||||
case 1:
|
||||
v1 = *(set->m_values.begin());
|
||||
v2 = mk_value(Number(0), s);
|
||||
if (v1 == v2)
|
||||
v2 = mk_value(Number(1), s);
|
||||
break;
|
||||
default:
|
||||
obj_hashtable<expr>::iterator it = set->m_values.begin();
|
||||
v1 = *it;
|
||||
++it;
|
||||
v2 = *it;
|
||||
break;
|
||||
}
|
||||
SASSERT(v1 != v2);
|
||||
return true;
|
||||
}
|
||||
v1 = mk_value(Number(0), s);
|
||||
v2 = mk_value(Number(1), s);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual expr * get_fresh_value(sort * s) {
|
||||
value_set * set = get_value_set(s);
|
||||
bool is_new = false;
|
||||
expr * result = 0;
|
||||
Number & next = set->m_next;
|
||||
while (!is_new) {
|
||||
result = mk_value(next, s, is_new);
|
||||
next++;
|
||||
}
|
||||
SASSERT(result != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void register_value(expr * n) {
|
||||
sort * s = this->m_manager.get_sort(n);
|
||||
value_set * set = get_value_set(s);
|
||||
if (!set->m_values.contains(n)) {
|
||||
m_values.push_back(n);
|
||||
set->m_values.insert(n);
|
||||
}
|
||||
}
|
||||
|
||||
virtual app * mk_value(Number const & val, sort * s) {
|
||||
bool is_new;
|
||||
return mk_value(val, s, is_new);
|
||||
}
|
||||
|
||||
unsigned get_num_sorts() const { return m_sorts.size(); }
|
||||
|
||||
sort * get_sort(unsigned idx) const { return m_sorts.get(idx); }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Factory for creating values for uninterpreted sorts and user
|
||||
declared (uninterpreted) sorts.
|
||||
*/
|
||||
class user_sort_factory : public simple_factory<unsigned> {
|
||||
obj_hashtable<sort> m_finite; //!< set of sorts that are marked as finite.
|
||||
obj_hashtable<expr> m_empty_universe;
|
||||
virtual app * mk_value_core(unsigned const & val, sort * s);
|
||||
public:
|
||||
user_sort_factory(ast_manager & m);
|
||||
virtual ~user_sort_factory() {}
|
||||
|
||||
/**
|
||||
\brief Make the universe of \c s finite, by preventing new
|
||||
elements to be added to its universe.
|
||||
*/
|
||||
void freeze_universe(sort * s);
|
||||
|
||||
/**
|
||||
\brief Return true if the universe of \c s is frozen and finite.
|
||||
*/
|
||||
bool is_finite(sort * s) const {
|
||||
return m_finite.contains(s);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the "known" universe of \c s. It doesn't matter whether
|
||||
s is finite or not. If \c s is finite, then it is the whole universe.
|
||||
*/
|
||||
obj_hashtable<expr> const & get_known_universe(sort * s) const;
|
||||
|
||||
/**
|
||||
\brief Return sorts with finite interpretations.
|
||||
*/
|
||||
obj_hashtable<sort> const & get_finite_sorts() const { return m_finite; }
|
||||
|
||||
virtual expr * get_some_value(sort * s);
|
||||
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2);
|
||||
|
||||
virtual expr * get_fresh_value(sort * s);
|
||||
|
||||
virtual void register_value(expr * n);
|
||||
};
|
||||
|
||||
#endif /* _VALUE_FACTORY_H_ */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue