mirror of
https://github.com/Z3Prover/z3
synced 2025-10-07 08:21:56 +00:00
merge with master
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
b915f78281
62 changed files with 12564 additions and 167 deletions
|
@ -31,6 +31,8 @@ void smt_params::updt_local_params(params_ref const & _p) {
|
|||
m_restart_strategy = static_cast<restart_strategy>(p.restart_strategy());
|
||||
m_restart_factor = p.restart_factor();
|
||||
m_case_split_strategy = static_cast<case_split_strategy>(p.case_split());
|
||||
m_theory_case_split = p.theory_case_split();
|
||||
m_theory_aware_branching = p.theory_aware_branching();
|
||||
m_delay_units = p.delay_units();
|
||||
m_delay_units_threshold = p.delay_units_threshold();
|
||||
m_preprocess = _p.get_bool("preprocess", true); // hidden parameter
|
||||
|
@ -39,6 +41,7 @@ void smt_params::updt_local_params(params_ref const & _p) {
|
|||
m_max_conflicts = p.max_conflicts();
|
||||
m_core_validate = p.core_validate();
|
||||
m_logic = _p.get_sym("logic", m_logic);
|
||||
m_string_solver = p.string_solver();
|
||||
model_params mp(_p);
|
||||
m_model_compact = mp.compact();
|
||||
if (_p.get_bool("arith.greatest_error_pivot", false))
|
||||
|
@ -155,4 +158,4 @@ void smt_params::display(std::ostream & out) const {
|
|||
DISPLAY_PARAM(m_check_at_labels);
|
||||
DISPLAY_PARAM(m_dump_goal_as_smt);
|
||||
DISPLAY_PARAM(m_auto_config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ Revision History:
|
|||
#include"theory_arith_params.h"
|
||||
#include"theory_array_params.h"
|
||||
#include"theory_bv_params.h"
|
||||
#include"theory_str_params.h"
|
||||
#include"theory_pb_params.h"
|
||||
#include"theory_datatype_params.h"
|
||||
#include"preprocessor_params.h"
|
||||
|
@ -66,7 +67,8 @@ enum case_split_strategy {
|
|||
CS_ACTIVITY_WITH_CACHE, // case split based on activity and cache the activity
|
||||
CS_RELEVANCY, // case split based on relevancy
|
||||
CS_RELEVANCY_ACTIVITY, // case split based on relevancy and activity
|
||||
CS_RELEVANCY_GOAL // based on relevancy and the current goal
|
||||
CS_RELEVANCY_GOAL, // based on relevancy and the current goal
|
||||
CS_ACTIVITY_THEORY_AWARE_BRANCHING // activity-based case split, but theory solvers can manipulate activity
|
||||
};
|
||||
|
||||
struct smt_params : public preprocessor_params,
|
||||
|
@ -75,6 +77,7 @@ struct smt_params : public preprocessor_params,
|
|||
public theory_arith_params,
|
||||
public theory_array_params,
|
||||
public theory_bv_params,
|
||||
public theory_str_params,
|
||||
public theory_pb_params,
|
||||
public theory_datatype_params {
|
||||
bool m_display_proof;
|
||||
|
@ -109,6 +112,8 @@ struct smt_params : public preprocessor_params,
|
|||
case_split_strategy m_case_split_strategy;
|
||||
unsigned m_rel_case_split_order;
|
||||
bool m_lookahead_diseq;
|
||||
bool m_theory_case_split;
|
||||
bool m_theory_aware_branching;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
@ -212,6 +217,13 @@ struct smt_params : public preprocessor_params,
|
|||
bool m_dump_goal_as_smt;
|
||||
bool m_auto_config;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Solver selection
|
||||
//
|
||||
// -----------------------------------
|
||||
symbol m_string_solver;
|
||||
|
||||
smt_params(params_ref const & p = params_ref()):
|
||||
m_display_proof(false),
|
||||
m_display_dot_proof(false),
|
||||
|
@ -239,6 +251,8 @@ struct smt_params : public preprocessor_params,
|
|||
m_case_split_strategy(CS_ACTIVITY_DELAY_NEW),
|
||||
m_rel_case_split_order(0),
|
||||
m_lookahead_diseq(false),
|
||||
m_theory_case_split(false),
|
||||
m_theory_aware_branching(false),
|
||||
m_delay_units(false),
|
||||
m_delay_units_threshold(32),
|
||||
m_theory_resolve(false),
|
||||
|
@ -280,7 +294,8 @@ struct smt_params : public preprocessor_params,
|
|||
m_at_labels_cex(false),
|
||||
m_check_at_labels(false),
|
||||
m_dump_goal_as_smt(false),
|
||||
m_auto_config(true) {
|
||||
m_auto_config(true),
|
||||
m_string_solver(symbol("auto")){
|
||||
updt_local_params(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ def_module_params(module_name='smt',
|
|||
('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'),
|
||||
('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'),
|
||||
('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'),
|
||||
('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal'),
|
||||
('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal, 6 - activity-based case split with theory-aware branching activity'),
|
||||
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
|
||||
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'),
|
||||
('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
|
||||
|
@ -61,7 +61,21 @@ def_module_params(module_name='smt',
|
|||
('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'),
|
||||
('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'),
|
||||
('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'),
|
||||
('theory_case_split', BOOL, False, 'Allow the context to use heuristics involving theory case splits, which are a set of literals of which exactly one can be assigned True. If this option is false, the context will generate extra axioms to enforce this instead.'),
|
||||
('string_solver', SYMBOL, 'seq', 'solver for string/sequence theories. options are: \'z3str3\' (specialized string solver), \'seq\' (sequence solver), \'auto\' (use static features to choose best solver)'),
|
||||
('core.validate', BOOL, False, 'validate unsat core produced by SMT context'),
|
||||
('str.strong_arrangements', BOOL, True, 'assert equivalences instead of implications when generating string arrangement axioms'),
|
||||
('str.aggressive_length_testing', BOOL, False, 'prioritize testing concrete length values over generating more options'),
|
||||
('str.aggressive_value_testing', BOOL, False, 'prioritize testing concrete string constant values over generating more options'),
|
||||
('str.aggressive_unroll_testing', BOOL, True, 'prioritize testing concrete regex unroll counts over generating more options'),
|
||||
('str.fast_length_tester_cache', BOOL, False, 'cache length tester constants instead of regenerating them'),
|
||||
('str.fast_value_tester_cache', BOOL, True, 'cache value tester constants instead of regenerating them'),
|
||||
('str.string_constant_cache', BOOL, True, 'cache all generated string constants generated from anywhere in theory_str'),
|
||||
('str.use_binary_search', BOOL, False, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'),
|
||||
('str.binary_search_start', UINT, 64, 'initial upper bound for theory_str binary search'),
|
||||
('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'),
|
||||
('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'),
|
||||
('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'),
|
||||
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'),
|
||||
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'),
|
||||
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'),
|
||||
|
|
34
src/smt/params/theory_str_params.cpp
Normal file
34
src/smt/params/theory_str_params.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*++
|
||||
Module Name:
|
||||
|
||||
theory_str_params.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Parameters for string theory plugin
|
||||
|
||||
Author:
|
||||
|
||||
Murphy Berzish (mtrberzi) 2016-12-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"theory_str_params.h"
|
||||
#include"smt_params_helper.hpp"
|
||||
|
||||
void theory_str_params::updt_params(params_ref const & _p) {
|
||||
smt_params_helper p(_p);
|
||||
m_StrongArrangements = p.str_strong_arrangements();
|
||||
m_AggressiveLengthTesting = p.str_aggressive_length_testing();
|
||||
m_AggressiveValueTesting = p.str_aggressive_value_testing();
|
||||
m_AggressiveUnrollTesting = p.str_aggressive_unroll_testing();
|
||||
m_UseFastLengthTesterCache = p.str_fast_length_tester_cache();
|
||||
m_UseFastValueTesterCache = p.str_fast_value_tester_cache();
|
||||
m_StringConstantCache = p.str_string_constant_cache();
|
||||
m_FiniteOverlapModels = p.str_finite_overlap_models();
|
||||
m_UseBinarySearch = p.str_use_binary_search();
|
||||
m_BinarySearchInitialUpperBound = p.str_binary_search_start();
|
||||
m_OverlapTheoryAwarePriority = p.str_overlap_priority();
|
||||
}
|
102
src/smt/params/theory_str_params.h
Normal file
102
src/smt/params/theory_str_params.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*++
|
||||
Module Name:
|
||||
|
||||
theory_str_params.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Parameters for string theory plugin
|
||||
|
||||
Author:
|
||||
|
||||
Murphy Berzish (mtrberzi) 2016-12-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef THEORY_STR_PARAMS_H
|
||||
#define THEORY_STR_PARAMS_H
|
||||
|
||||
#include"params.h"
|
||||
|
||||
struct theory_str_params {
|
||||
/*
|
||||
* If AssertStrongerArrangements is set to true,
|
||||
* the implications that would normally be asserted during arrangement generation
|
||||
* will instead be asserted as equivalences.
|
||||
* This is a stronger version of the standard axiom.
|
||||
* The Z3str2 axioms can be simulated by setting this to false.
|
||||
*/
|
||||
bool m_StrongArrangements;
|
||||
|
||||
/*
|
||||
* If AggressiveLengthTesting is true, we manipulate the phase of length tester equalities
|
||||
* to prioritize trying concrete length options over choosing the "more" option.
|
||||
*/
|
||||
bool m_AggressiveLengthTesting;
|
||||
|
||||
/*
|
||||
* Similarly, if AggressiveValueTesting is true, we manipulate the phase of value tester equalities
|
||||
* to prioritize trying concrete value options over choosing the "more" option.
|
||||
*/
|
||||
bool m_AggressiveValueTesting;
|
||||
|
||||
/*
|
||||
* If AggressiveUnrollTesting is true, we manipulate the phase of regex unroll tester equalities
|
||||
* to prioritize trying concrete unroll counts over choosing the "more" option.
|
||||
*/
|
||||
bool m_AggressiveUnrollTesting;
|
||||
|
||||
/*
|
||||
* If UseFastLengthTesterCache is set to true,
|
||||
* length tester terms will not be generated from scratch each time they are needed,
|
||||
* but will be saved in a map and looked up.
|
||||
*/
|
||||
bool m_UseFastLengthTesterCache;
|
||||
|
||||
/*
|
||||
* If UseFastValueTesterCache is set to true,
|
||||
* value tester terms will not be generated from scratch each time they are needed,
|
||||
* but will be saved in a map and looked up.
|
||||
*/
|
||||
bool m_UseFastValueTesterCache;
|
||||
|
||||
/*
|
||||
* If StringConstantCache is set to true,
|
||||
* all string constants in theory_str generated from anywhere will be cached and saved.
|
||||
*/
|
||||
bool m_StringConstantCache;
|
||||
|
||||
/*
|
||||
* If FiniteOverlapModels is set to true,
|
||||
* arrangements that result in overlapping variables will generate a small number of models
|
||||
* to test instead of completely giving up on the case.
|
||||
*/
|
||||
bool m_FiniteOverlapModels;
|
||||
|
||||
bool m_UseBinarySearch;
|
||||
unsigned m_BinarySearchInitialUpperBound;
|
||||
|
||||
double m_OverlapTheoryAwarePriority;
|
||||
|
||||
theory_str_params(params_ref const & p = params_ref()):
|
||||
m_StrongArrangements(true),
|
||||
m_AggressiveLengthTesting(false),
|
||||
m_AggressiveValueTesting(false),
|
||||
m_AggressiveUnrollTesting(true),
|
||||
m_UseFastLengthTesterCache(false),
|
||||
m_UseFastValueTesterCache(true),
|
||||
m_StringConstantCache(true),
|
||||
m_FiniteOverlapModels(false),
|
||||
m_UseBinarySearch(false),
|
||||
m_BinarySearchInitialUpperBound(64),
|
||||
m_OverlapTheoryAwarePriority(-0.1)
|
||||
{
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
};
|
||||
|
||||
#endif /* THEORY_STR_PARAMS_H */
|
|
@ -22,9 +22,13 @@ Revision History:
|
|||
#include"stopwatch.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ast_pp.h"
|
||||
#include"map.h"
|
||||
#include"hashtable.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
typedef map<bool_var, double, int_hash, default_eq<bool_var> > theory_var_priority_map;
|
||||
|
||||
struct bool_var_act_lt {
|
||||
svector<double> const & m_activity;
|
||||
bool_var_act_lt(svector<double> const & a):m_activity(a) {}
|
||||
|
@ -35,6 +39,27 @@ namespace smt {
|
|||
|
||||
typedef heap<bool_var_act_lt> bool_var_act_queue;
|
||||
|
||||
struct theory_aware_act_lt {
|
||||
svector<double> const & m_activity;
|
||||
theory_var_priority_map const & m_theory_var_priority;
|
||||
theory_aware_act_lt(svector<double> const & act, theory_var_priority_map const & a):m_activity(act),m_theory_var_priority(a) {}
|
||||
bool operator()(bool_var v1, bool_var v2) const {
|
||||
double p_v1, p_v2;
|
||||
if (!m_theory_var_priority.find(v1, p_v1)) {
|
||||
p_v1 = 0.0;
|
||||
}
|
||||
if (!m_theory_var_priority.find(v2, p_v2)) {
|
||||
p_v2 = 0.0;
|
||||
}
|
||||
// add clause activity
|
||||
p_v1 += m_activity[v1];
|
||||
p_v2 += m_activity[v2];
|
||||
return p_v1 > p_v2;
|
||||
}
|
||||
};
|
||||
|
||||
typedef heap<theory_aware_act_lt> theory_aware_act_queue;
|
||||
|
||||
/**
|
||||
\brief Case split queue based on activity and random splits.
|
||||
*/
|
||||
|
@ -1086,16 +1111,130 @@ namespace smt {
|
|||
m_params.m_qi_eager_threshold += start_gen;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class theory_aware_branching_queue : public case_split_queue {
|
||||
protected:
|
||||
context & m_context;
|
||||
smt_params & m_params;
|
||||
theory_var_priority_map m_theory_var_priority;
|
||||
theory_aware_act_queue m_queue;
|
||||
|
||||
int_hashtable<int_hash, default_eq<bool_var> > m_theory_vars;
|
||||
map<bool_var, lbool, int_hash, default_eq<bool_var> > m_theory_var_phase;
|
||||
public:
|
||||
theory_aware_branching_queue(context & ctx, smt_params & p):
|
||||
m_context(ctx),
|
||||
m_params(p),
|
||||
m_theory_var_priority(),
|
||||
m_queue(1024, theory_aware_act_lt(ctx.get_activity_vector(), m_theory_var_priority)) {
|
||||
}
|
||||
|
||||
virtual void activity_increased_eh(bool_var v) {
|
||||
if (m_queue.contains(v))
|
||||
m_queue.decreased(v);
|
||||
}
|
||||
|
||||
virtual void mk_var_eh(bool_var v) {
|
||||
m_queue.reserve(v+1);
|
||||
m_queue.insert(v);
|
||||
}
|
||||
|
||||
virtual void del_var_eh(bool_var v) {
|
||||
if (m_queue.contains(v))
|
||||
m_queue.erase(v);
|
||||
}
|
||||
|
||||
virtual void unassign_var_eh(bool_var v) {
|
||||
if (!m_queue.contains(v))
|
||||
m_queue.insert(v);
|
||||
}
|
||||
|
||||
virtual void relevant_eh(expr * n) {}
|
||||
|
||||
virtual void init_search_eh() {}
|
||||
|
||||
virtual void end_search_eh() {}
|
||||
|
||||
virtual void reset() {
|
||||
m_queue.reset();
|
||||
}
|
||||
|
||||
virtual void push_scope() {}
|
||||
|
||||
virtual void pop_scope(unsigned num_scopes) {}
|
||||
|
||||
virtual void next_case_split(bool_var & next, lbool & phase) {
|
||||
int threshold = static_cast<int>(m_params.m_random_var_freq * random_gen::max_value());
|
||||
SASSERT(threshold >= 0);
|
||||
if (m_context.get_random_value() < threshold) {
|
||||
SASSERT(m_context.get_num_b_internalized() > 0);
|
||||
next = m_context.get_random_value() % m_context.get_num_b_internalized();
|
||||
TRACE("random_split", tout << "next: " << next << " get_assignment(next): " << m_context.get_assignment(next) << "\n";);
|
||||
if (m_context.get_assignment(next) == l_undef)
|
||||
return;
|
||||
}
|
||||
|
||||
while (!m_queue.empty()) {
|
||||
next = m_queue.erase_min();
|
||||
if (m_context.get_assignment(next) == l_undef)
|
||||
return;
|
||||
}
|
||||
|
||||
next = null_bool_var;
|
||||
if (m_theory_vars.contains(next)) {
|
||||
if (!m_theory_var_phase.find(next, phase)) {
|
||||
phase = l_undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void add_theory_aware_branching_info(bool_var v, double priority, lbool phase) {
|
||||
TRACE("theory_aware_branching", tout << "Add theory-aware branching information for l#" << v << ": priority=" << priority << std::endl;);
|
||||
m_theory_vars.insert(v);
|
||||
m_theory_var_phase.insert(v, phase);
|
||||
m_theory_var_priority.insert(v, priority);
|
||||
if (m_queue.contains(v)) {
|
||||
if (priority > 0.0) {
|
||||
m_queue.decreased(v);
|
||||
} else {
|
||||
m_queue.increased(v);
|
||||
}
|
||||
}
|
||||
// m_theory_queue.reserve(v+1);
|
||||
// m_theory_queue.insert(v);
|
||||
}
|
||||
|
||||
virtual void display(std::ostream & out) {
|
||||
bool first = true;
|
||||
bool_var_act_queue::const_iterator it = m_queue.begin();
|
||||
bool_var_act_queue::const_iterator end = m_queue.end();
|
||||
for (; it != end ; ++it) {
|
||||
unsigned v = *it;
|
||||
if (m_context.get_assignment(v) == l_undef) {
|
||||
if (first) {
|
||||
out << "remaining case-splits:\n";
|
||||
first = false;
|
||||
}
|
||||
out << "#" << m_context.bool_var2expr(v)->get_id() << " ";
|
||||
}
|
||||
}
|
||||
if (!first)
|
||||
out << "\n";
|
||||
|
||||
}
|
||||
|
||||
virtual ~theory_aware_branching_queue() {};
|
||||
};
|
||||
|
||||
|
||||
case_split_queue * mk_case_split_queue(context & ctx, smt_params & p) {
|
||||
if (p.m_relevancy_lvl < 2 && (p.m_case_split_strategy == CS_RELEVANCY || p.m_case_split_strategy == CS_RELEVANCY_ACTIVITY ||
|
||||
p.m_case_split_strategy == CS_RELEVANCY_GOAL)) {
|
||||
p.m_case_split_strategy == CS_RELEVANCY_GOAL)) {
|
||||
warning_msg("relevancy must be enabled to use option CASE_SPLIT=3, 4 or 5");
|
||||
p.m_case_split_strategy = CS_ACTIVITY;
|
||||
}
|
||||
if (p.m_auto_config && (p.m_case_split_strategy == CS_RELEVANCY || p.m_case_split_strategy == CS_RELEVANCY_ACTIVITY ||
|
||||
p.m_case_split_strategy == CS_RELEVANCY_GOAL)) {
|
||||
p.m_case_split_strategy == CS_RELEVANCY_GOAL)) {
|
||||
warning_msg("auto configuration (option AUTO_CONFIG) must be disabled to use option CASE_SPLIT=3, 4 or 5");
|
||||
p.m_case_split_strategy = CS_ACTIVITY;
|
||||
}
|
||||
|
@ -1110,6 +1249,8 @@ namespace smt {
|
|||
return alloc(rel_act_case_split_queue, ctx, p);
|
||||
case CS_RELEVANCY_GOAL:
|
||||
return alloc(rel_goal_case_split_queue, ctx, p);
|
||||
case CS_ACTIVITY_THEORY_AWARE_BRANCHING:
|
||||
return alloc(theory_aware_branching_queue, ctx, p);
|
||||
default:
|
||||
return alloc(act_case_split_queue, ctx, p);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace smt {
|
|||
virtual void next_case_split(bool_var & next, lbool & phase) = 0;
|
||||
virtual void display(std::ostream & out) = 0;
|
||||
virtual ~case_split_queue() {}
|
||||
|
||||
// theory-aware branching hint
|
||||
virtual void add_theory_aware_branching_info(bool_var v, double priority, lbool phase) {}
|
||||
};
|
||||
|
||||
case_split_queue * mk_case_split_queue(context & ctx, smt_params & p);
|
||||
|
|
|
@ -1768,6 +1768,8 @@ namespace smt {
|
|||
unsigned qhead = m_qhead;
|
||||
if (!bcp())
|
||||
return false;
|
||||
if (!propagate_th_case_split(qhead))
|
||||
return false;
|
||||
if (get_cancel_flag()) {
|
||||
m_qhead = qhead;
|
||||
return true;
|
||||
|
@ -2455,8 +2457,9 @@ namespace smt {
|
|||
|
||||
ptr_vector<theory>::iterator it = m_theory_set.begin();
|
||||
ptr_vector<theory>::iterator end = m_theory_set.end();
|
||||
for (; it != end; ++it)
|
||||
for (; it != end; ++it) {
|
||||
(*it)->pop_scope_eh(num_scopes);
|
||||
}
|
||||
|
||||
del_justifications(m_justifications, s.m_justifications_lim);
|
||||
|
||||
|
@ -2969,6 +2972,115 @@ namespace smt {
|
|||
assert_expr_core(e, pr);
|
||||
}
|
||||
|
||||
class case_split_insert_trail : public trail<context> {
|
||||
literal l;
|
||||
public:
|
||||
case_split_insert_trail(literal l):
|
||||
l(l) {
|
||||
}
|
||||
virtual void undo(context & ctx) {
|
||||
ctx.undo_th_case_split(l);
|
||||
}
|
||||
};
|
||||
|
||||
void context::mk_th_case_split(unsigned num_lits, literal * lits) {
|
||||
TRACE("theory_case_split", display_literals_verbose(tout << "theory case split: ", num_lits, lits); tout << std::endl;);
|
||||
// If we don't use the theory case split heuristic,
|
||||
// for each pair of literals (l1, l2) we add the clause (~l1 OR ~l2)
|
||||
// to enforce the condition that at most one literal can be assigned 'true'.
|
||||
if (!m_fparams.m_theory_case_split) {
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
for (unsigned j = i+1; j < num_lits; ++j) {
|
||||
literal l1 = lits[i];
|
||||
literal l2 = lits[j];
|
||||
mk_clause(~l1, ~l2, (justification*) 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
literal_vector new_case_split;
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
literal l = lits[i];
|
||||
SASSERT(!m_all_th_case_split_literals.contains(l.index()));
|
||||
m_all_th_case_split_literals.insert(l.index());
|
||||
push_trail(case_split_insert_trail(l));
|
||||
new_case_split.push_back(l);
|
||||
}
|
||||
m_th_case_split_sets.push_back(new_case_split);
|
||||
push_trail(push_back_vector<context, vector<literal_vector> >(m_th_case_split_sets));
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
literal l = lits[i];
|
||||
if (!m_literal2casesplitsets.contains(l.index())) {
|
||||
m_literal2casesplitsets.insert(l.index(), vector<literal_vector>());
|
||||
}
|
||||
m_literal2casesplitsets[l.index()].push_back(new_case_split);
|
||||
}
|
||||
TRACE("theory_case_split", tout << "tracking case split literal set { ";
|
||||
for (unsigned i = 0; i < num_lits; ++i) {
|
||||
tout << lits[i].index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void context::add_theory_aware_branching_info(bool_var v, double priority, lbool phase) {
|
||||
m_case_split_queue->add_theory_aware_branching_info(v, priority, phase);
|
||||
}
|
||||
|
||||
void context::undo_th_case_split(literal l) {
|
||||
m_all_th_case_split_literals.remove(l.index());
|
||||
if (m_literal2casesplitsets.contains(l.index())) {
|
||||
if (!m_literal2casesplitsets[l.index()].empty()) {
|
||||
m_literal2casesplitsets[l.index()].pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool context::propagate_th_case_split(unsigned qhead) {
|
||||
if (m_all_th_case_split_literals.empty())
|
||||
return true;
|
||||
|
||||
// iterate over all literals assigned since the last time this method was called,
|
||||
// not counting any literals that get assigned by this method
|
||||
// this relies on bcp() to give us its old m_qhead and therefore
|
||||
// bcp() should always be called before this method
|
||||
|
||||
unsigned assigned_literal_end = m_assigned_literals.size();
|
||||
for (; qhead < assigned_literal_end; ++qhead) {
|
||||
literal l = m_assigned_literals[qhead];
|
||||
TRACE("theory_case_split", tout << "check literal " << l.index() << std::endl; display_literal_verbose(tout, l); tout << std::endl;);
|
||||
// check if this literal participates in any theory case split
|
||||
if (!m_all_th_case_split_literals.contains(l.index())) {
|
||||
continue;
|
||||
}
|
||||
TRACE("theory_case_split", tout << "assigned literal " << l.index() << " is a theory case split literal" << std::endl;);
|
||||
// now find the sets of literals which contain l
|
||||
vector<literal_vector> const& case_split_sets = m_literal2casesplitsets[l.index()];
|
||||
for (vector<literal_vector>::const_iterator it = case_split_sets.begin(); it != case_split_sets.end(); ++it) {
|
||||
literal_vector case_split_set = *it;
|
||||
TRACE("theory_case_split", tout << "found case split set { ";
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
tout << set_it->index() << " ";
|
||||
}
|
||||
tout << "}" << std::endl;);
|
||||
for(literal_vector::iterator set_it = case_split_set.begin(); set_it != case_split_set.end(); ++set_it) {
|
||||
literal l2 = *set_it;
|
||||
if (l2 != l) {
|
||||
b_justification js(l);
|
||||
TRACE("theory_case_split", tout << "case split literal "; l2.display(tout, m_manager, m_bool_var2expr.c_ptr()););
|
||||
assign(~l2, js);
|
||||
if (inconsistent()) {
|
||||
TRACE("theory_case_split", tout << "conflict detected!" << std::endl;);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we get here without detecting a conflict, we're fine
|
||||
return true;
|
||||
}
|
||||
|
||||
bool context::reduce_assertions() {
|
||||
if (!m_asserted_formulas.inconsistent()) {
|
||||
SASSERT(at_base_level());
|
||||
|
@ -3012,11 +3124,18 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool is_valid_assumption(ast_manager & m, expr * assumption) {
|
||||
expr* arg;
|
||||
if (!m.is_bool(assumption))
|
||||
return false;
|
||||
if (is_uninterp_const(assumption))
|
||||
return true;
|
||||
if (m.is_not(assumption) && is_uninterp_const(to_app(assumption)->get_arg(0)))
|
||||
if (m.is_not(assumption, arg) && is_uninterp_const(arg))
|
||||
return true;
|
||||
if (!is_app(assumption))
|
||||
return false;
|
||||
if (to_app(assumption)->get_num_args() == 0)
|
||||
return true;
|
||||
if (m.is_not(assumption, arg) && is_app(arg) && to_app(arg)->get_num_args() == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -226,6 +226,15 @@ namespace smt {
|
|||
literal2assumption m_literal2assumption; // maps an expression associated with a literal to the original assumption
|
||||
expr_ref_vector m_unsat_core;
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Theory case split
|
||||
//
|
||||
// -----------------------------------
|
||||
uint_set m_all_th_case_split_literals;
|
||||
vector<literal_vector> m_th_case_split_sets;
|
||||
u_map< vector<literal_vector> > m_literal2casesplitsets; // returns the case split literal sets that a literal participates in
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Accessors
|
||||
|
@ -827,6 +836,29 @@ namespace smt {
|
|||
|
||||
void mk_th_axiom(theory_id tid, literal l1, literal l2, literal l3, unsigned num_params = 0, parameter * params = 0);
|
||||
|
||||
/*
|
||||
* Provide a hint to the core solver that the specified literals form a "theory case split".
|
||||
* The core solver will enforce the condition that exactly one of these literals can be
|
||||
* assigned 'true' at any time.
|
||||
* We assume that the theory solver has already asserted the disjunction of these literals
|
||||
* or some other axiom that means at least one of them must be assigned 'true'.
|
||||
*/
|
||||
void mk_th_case_split(unsigned num_lits, literal * lits);
|
||||
|
||||
|
||||
/*
|
||||
* Provide a hint to the branching heuristic about the priority of a "theory-aware literal".
|
||||
* Literals marked in this way will always be branched on before unmarked literals,
|
||||
* starting with the literal having the highest priority.
|
||||
*/
|
||||
void add_theory_aware_branching_info(bool_var v, double priority, lbool phase);
|
||||
|
||||
public:
|
||||
|
||||
// helper function for trail
|
||||
void undo_th_case_split(literal l);
|
||||
|
||||
bool propagate_th_case_split(unsigned qhead);
|
||||
|
||||
bool_var mk_bool_var(expr * n);
|
||||
|
||||
|
|
|
@ -405,7 +405,6 @@ namespace smt {
|
|||
bool context::validate_justification(bool_var v, bool_var_data const& d, b_justification const& j) {
|
||||
if (j.get_kind() == b_justification::CLAUSE && v != true_bool_var) {
|
||||
clause* cls = j.get_clause();
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
literal l = cls->get_literal(0);
|
||||
if (l.var() != v) {
|
||||
l = cls->get_literal(1);
|
||||
|
|
|
@ -33,6 +33,7 @@ Revision History:
|
|||
#include"theory_seq.h"
|
||||
#include"theory_pb.h"
|
||||
#include"theory_fpa.h"
|
||||
#include"theory_str.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -120,6 +121,8 @@ namespace smt {
|
|||
setup_QF_FP();
|
||||
else if (m_logic == "QF_FPBV" || m_logic == "QF_BVFP")
|
||||
setup_QF_FPBV();
|
||||
else if (m_logic == "QF_S")
|
||||
setup_QF_S();
|
||||
else
|
||||
setup_unknown();
|
||||
}
|
||||
|
@ -161,6 +164,8 @@ namespace smt {
|
|||
setup_QF_BVRE();
|
||||
else if (m_logic == "QF_AUFLIA")
|
||||
setup_QF_AUFLIA(st);
|
||||
else if (m_logic == "QF_S")
|
||||
setup_QF_S();
|
||||
else if (m_logic == "AUFLIA")
|
||||
setup_AUFLIA(st);
|
||||
else if (m_logic == "AUFLIRA")
|
||||
|
@ -201,7 +206,7 @@ namespace smt {
|
|||
void setup::setup_QF_BVRE() {
|
||||
setup_QF_BV();
|
||||
setup_QF_LIA();
|
||||
setup_seq();
|
||||
m_context.register_plugin(alloc(theory_seq, m_manager));
|
||||
}
|
||||
|
||||
void setup::setup_QF_UF(static_features const & st) {
|
||||
|
@ -700,6 +705,11 @@ namespace smt {
|
|||
m_context.register_plugin(alloc(smt::theory_fpa, m_manager));
|
||||
}
|
||||
|
||||
void setup::setup_QF_S() {
|
||||
m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
|
||||
m_context.register_plugin(alloc(smt::theory_str, m_manager, m_params));
|
||||
}
|
||||
|
||||
bool is_arith(static_features const & st) {
|
||||
return st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0;
|
||||
}
|
||||
|
@ -814,8 +824,25 @@ namespace smt {
|
|||
m_context.register_plugin(mk_theory_dl(m_manager));
|
||||
}
|
||||
|
||||
void setup::setup_seq() {
|
||||
m_context.register_plugin(alloc(theory_seq, m_manager));
|
||||
void setup::setup_seq_str(static_features const & st) {
|
||||
// check params for what to do here when it's ambiguous
|
||||
if (m_params.m_string_solver == "z3str3") {
|
||||
setup_str();
|
||||
}
|
||||
else if (m_params.m_string_solver == "seq") {
|
||||
setup_seq();
|
||||
}
|
||||
else if (m_params.m_string_solver == "auto") {
|
||||
if (st.m_has_seq_non_str) {
|
||||
setup_seq();
|
||||
}
|
||||
else {
|
||||
setup_str();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw default_exception("invalid parameter for smt.string_solver, valid options are 'z3str3', 'seq', 'auto'");
|
||||
}
|
||||
}
|
||||
|
||||
void setup::setup_card() {
|
||||
|
@ -827,13 +854,25 @@ namespace smt {
|
|||
m_context.register_plugin(alloc(theory_fpa, m_manager));
|
||||
}
|
||||
|
||||
void setup::setup_str() {
|
||||
setup_arith();
|
||||
m_context.register_plugin(alloc(theory_str, m_manager, m_params));
|
||||
}
|
||||
|
||||
void setup::setup_seq() {
|
||||
m_context.register_plugin(alloc(smt::theory_seq, m_manager));
|
||||
}
|
||||
|
||||
void setup::setup_unknown() {
|
||||
static_features st(m_manager);
|
||||
st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas());
|
||||
|
||||
setup_arith();
|
||||
setup_arrays();
|
||||
setup_bv();
|
||||
setup_datatypes();
|
||||
setup_dl();
|
||||
setup_seq();
|
||||
setup_seq_str(st);
|
||||
setup_card();
|
||||
setup_fpa();
|
||||
}
|
||||
|
@ -848,7 +887,7 @@ namespace smt {
|
|||
setup_datatypes();
|
||||
setup_bv();
|
||||
setup_dl();
|
||||
setup_seq();
|
||||
setup_seq_str(st);
|
||||
setup_card();
|
||||
setup_fpa();
|
||||
return;
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace smt {
|
|||
void setup_QF_AUFLIA(static_features const & st);
|
||||
void setup_QF_FP();
|
||||
void setup_QF_FPBV();
|
||||
void setup_QF_S();
|
||||
void setup_LRA();
|
||||
void setup_AUFLIA(bool simple_array = true);
|
||||
void setup_AUFLIA(static_features const & st);
|
||||
|
@ -93,11 +94,13 @@ namespace smt {
|
|||
void setup_bv();
|
||||
void setup_arith();
|
||||
void setup_dl();
|
||||
void setup_seq_str(static_features const & st);
|
||||
void setup_seq();
|
||||
void setup_card();
|
||||
void setup_i_arith();
|
||||
void setup_mi_arith();
|
||||
void setup_fpa();
|
||||
void setup_str();
|
||||
|
||||
public:
|
||||
setup(context & c, smt_params & params);
|
||||
|
|
|
@ -186,13 +186,13 @@ namespace smt {
|
|||
}
|
||||
|
||||
/**
|
||||
\brief This method is called from smt_context when an unsat core is generated.
|
||||
\brief This method is called from the smt_context when an unsat core is generated.
|
||||
The theory may change the answer to UNKNOWN by returning l_undef from this method.
|
||||
*/
|
||||
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core) {
|
||||
return l_false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief This method is invoked before the search starts.
|
||||
*/
|
||||
|
|
|
@ -505,7 +505,7 @@ namespace smt {
|
|||
struct var_value_eq {
|
||||
theory_arith & m_th;
|
||||
var_value_eq(theory_arith & th):m_th(th) {}
|
||||
bool operator()(theory_var v1, theory_var v2) const { return m_th.get_value(v1) == m_th.get_value(v2) && m_th.is_int(v1) == m_th.is_int(v2); }
|
||||
bool operator()(theory_var v1, theory_var v2) const { return m_th.get_value(v1) == m_th.get_value(v2) && m_th.is_int_src(v1) == m_th.is_int_src(v2); }
|
||||
};
|
||||
|
||||
typedef int_hashtable<var_value_hash, var_value_eq> var_value_table;
|
||||
|
@ -552,6 +552,7 @@ namespace smt {
|
|||
bool is_int(theory_var v) const { return m_data[v].m_is_int; }
|
||||
bool is_int_src(theory_var v) const { return m_util.is_int(var2expr(v)); }
|
||||
bool is_real(theory_var v) const { return !is_int(v); }
|
||||
bool is_real_src(theory_var v) const { return !is_int_src(v); }
|
||||
bool get_implied_old_value(theory_var v, inf_numeral & r) const;
|
||||
inf_numeral const & get_implied_value(theory_var v) const;
|
||||
inf_numeral const & get_quasi_base_value(theory_var v) const { return get_implied_value(v); }
|
||||
|
|
|
@ -2201,16 +2201,19 @@ namespace smt {
|
|||
int num = get_num_vars();
|
||||
for (theory_var v = 0; v < num; v++) {
|
||||
enode * n = get_enode(v);
|
||||
TRACE("func_interp_bug", tout << "#" << n->get_owner_id() << " -> " << m_value[v] << "\n";);
|
||||
if (!is_relevant_and_shared(n))
|
||||
TRACE("func_interp_bug", tout << mk_pp(n->get_owner(), get_manager()) << " -> " << m_value[v] << " root #" << n->get_root()->get_owner_id() << " " << is_relevant_and_shared(n) << "\n";);
|
||||
if (!is_relevant_and_shared(n)) {
|
||||
continue;
|
||||
}
|
||||
theory_var other = null_theory_var;
|
||||
other = m_var_value_table.insert_if_not_there(v);
|
||||
if (other == v)
|
||||
if (other == v) {
|
||||
continue;
|
||||
}
|
||||
enode * n2 = get_enode(other);
|
||||
if (n->get_root() == n2->get_root())
|
||||
if (n->get_root() == n2->get_root()) {
|
||||
continue;
|
||||
}
|
||||
TRACE("func_interp_bug", tout << "adding to assume_eq queue #" << n->get_owner_id() << " #" << n2->get_owner_id() << "\n";);
|
||||
m_assume_eq_candidates.push_back(std::make_pair(other, v));
|
||||
result = true;
|
||||
|
|
|
@ -465,7 +465,7 @@ namespace smt {
|
|||
TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n";
|
||||
tout << s_ante << "\n" << s_conseq << "\n";);
|
||||
|
||||
literal lits[2] = {l_ante, l_conseq};
|
||||
// literal lits[2] = {l_ante, l_conseq};
|
||||
mk_clause(l_ante, l_conseq, 0, 0);
|
||||
if (ctx.relevancy()) {
|
||||
if (l_ante == false_literal) {
|
||||
|
|
|
@ -444,7 +444,7 @@ namespace smt {
|
|||
m_asserted_bounds.push_back(new_bound);
|
||||
// copy justification to new bound
|
||||
dependency2new_bound(dep, *new_bound);
|
||||
TRACE("buggy_bound", new_bound->display(*this, tout); tout << "\n";);
|
||||
TRACE("non_linear", new_bound->display(*this, tout); tout << "\n";);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,8 +457,19 @@ namespace smt {
|
|||
bool r = false;
|
||||
if (!i.minus_infinity()) {
|
||||
inf_numeral new_lower(i.get_lower_value());
|
||||
if (i.is_lower_open())
|
||||
new_lower += get_epsilon(v);
|
||||
if (i.is_lower_open()) {
|
||||
if (is_int(v)) {
|
||||
if (new_lower.is_int()) {
|
||||
new_lower += rational::one();
|
||||
}
|
||||
else {
|
||||
new_lower = ceil(new_lower.get_rational());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_lower += get_epsilon(v);
|
||||
}
|
||||
}
|
||||
bound * old_lower = lower(v);
|
||||
if (old_lower == 0 || new_lower > old_lower->get_value()) {
|
||||
TRACE("non_linear", tout << "NEW lower bound for v" << v << " " << new_lower << "\n";
|
||||
|
@ -469,8 +480,19 @@ namespace smt {
|
|||
}
|
||||
if (!i.plus_infinity()) {
|
||||
inf_numeral new_upper(i.get_upper_value());
|
||||
if (i.is_upper_open())
|
||||
new_upper -= get_epsilon(v);
|
||||
if (i.is_upper_open()) {
|
||||
if (is_int(v)) {
|
||||
if (new_upper.is_int()) {
|
||||
new_upper -= rational::one();
|
||||
}
|
||||
else {
|
||||
new_upper = floor(new_upper.get_rational());
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_upper -= get_epsilon(v);
|
||||
}
|
||||
}
|
||||
bound * old_upper = upper(v);
|
||||
if (old_upper == 0 || new_upper < old_upper->get_value()) {
|
||||
TRACE("non_linear", tout << "NEW upper bound for v" << v << " " << new_upper << "\n";
|
||||
|
@ -819,6 +841,7 @@ namespace smt {
|
|||
if (is_fixed(_var))
|
||||
r *= lower_bound(_var).get_rational();
|
||||
}
|
||||
TRACE("arith", tout << mk_pp(m, get_manager()) << " " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -896,7 +919,7 @@ namespace smt {
|
|||
|
||||
// Assert the equality
|
||||
// (= (* x_1 ... x_n) k)
|
||||
TRACE("non_linear", tout << "all variables are fixed.\n";);
|
||||
TRACE("non_linear", tout << "all variables are fixed, and bound is: " << k << "\n";);
|
||||
new_lower = alloc(derived_bound, v, inf_numeral(k), B_LOWER);
|
||||
new_upper = alloc(derived_bound, v, inf_numeral(k), B_UPPER);
|
||||
}
|
||||
|
@ -953,7 +976,8 @@ namespace smt {
|
|||
new_upper->m_eqs.append(new_lower->m_eqs);
|
||||
|
||||
TRACE("non_linear",
|
||||
tout << "lower: " << new_lower << " upper: " << new_upper << "\n";
|
||||
new_lower->display(*this, tout << "lower: "); tout << "\n";
|
||||
new_upper->display(*this, tout << "upper: "); tout << "\n";
|
||||
for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) {
|
||||
ctx.display_detailed_literal(tout, new_upper->m_lits[j]);
|
||||
tout << " ";
|
||||
|
|
|
@ -762,6 +762,21 @@ namespace smt {
|
|||
TRACE("bv", tout << mk_pp(cond, get_manager()) << "\n"; tout << l << "\n";); \
|
||||
}
|
||||
|
||||
void theory_bv::internalize_sub(app *n) {
|
||||
SASSERT(!get_context().e_internalized(n));
|
||||
SASSERT(n->get_num_args() == 2);
|
||||
process_args(n);
|
||||
ast_manager & m = get_manager();
|
||||
enode * e = mk_enode(n);
|
||||
expr_ref_vector arg1_bits(m), arg2_bits(m), bits(m);
|
||||
get_arg_bits(e, 0, arg1_bits);
|
||||
get_arg_bits(e, 1, arg2_bits);
|
||||
SASSERT(arg1_bits.size() == arg2_bits.size());
|
||||
expr_ref carry(m);
|
||||
m_bb.mk_subtracter(arg1_bits.size(), arg1_bits.c_ptr(), arg2_bits.c_ptr(), bits, carry);
|
||||
init_bits(e, bits);
|
||||
}
|
||||
|
||||
MK_UNARY(internalize_not, mk_not);
|
||||
MK_UNARY(internalize_redand, mk_redand);
|
||||
MK_UNARY(internalize_redor, mk_redor);
|
||||
|
@ -848,6 +863,7 @@ namespace smt {
|
|||
switch (term->get_decl_kind()) {
|
||||
case OP_BV_NUM: internalize_num(term); return true;
|
||||
case OP_BADD: internalize_add(term); return true;
|
||||
case OP_BSUB: internalize_sub(term); return true;
|
||||
case OP_BMUL: internalize_mul(term); return true;
|
||||
case OP_BSDIV_I: internalize_sdiv(term); return true;
|
||||
case OP_BUDIV_I: internalize_udiv(term); return true;
|
||||
|
|
|
@ -172,6 +172,7 @@ namespace smt {
|
|||
bool get_fixed_value(theory_var v, numeral & result) const;
|
||||
void internalize_num(app * n);
|
||||
void internalize_add(app * n);
|
||||
void internalize_sub(app * n);
|
||||
void internalize_mul(app * n);
|
||||
void internalize_udiv(app * n);
|
||||
void internalize_sdiv(app * n);
|
||||
|
|
|
@ -3874,8 +3874,8 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
|
|||
}
|
||||
else if (n1 != n2 && m_util.is_re(n1->get_owner())) {
|
||||
warning_msg("equality between regular expressions is not yet supported");
|
||||
eautomaton* a1 = get_automaton(n1->get_owner());
|
||||
eautomaton* a2 = get_automaton(n2->get_owner());
|
||||
// eautomaton* a1 = get_automaton(n1->get_owner());
|
||||
// eautomaton* a2 = get_automaton(n2->get_owner());
|
||||
// eautomaton* b1 = mk_difference(*a1, *a2);
|
||||
// eautomaton* b2 = mk_difference(*a2, *a1);
|
||||
// eautomaton* c = mk_union(*b1, *b2);
|
||||
|
|
10574
src/smt/theory_str.cpp
Normal file
10574
src/smt/theory_str.cpp
Normal file
File diff suppressed because it is too large
Load diff
653
src/smt/theory_str.h
Normal file
653
src/smt/theory_str.h
Normal file
|
@ -0,0 +1,653 @@
|
|||
/*++
|
||||
Module Name:
|
||||
|
||||
theory_str.h
|
||||
|
||||
Abstract:
|
||||
|
||||
String Theory Plugin
|
||||
|
||||
Author:
|
||||
|
||||
Murphy Berzish and Yunhui Zheng
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _THEORY_STR_H_
|
||||
#define _THEORY_STR_H_
|
||||
|
||||
#include"smt_theory.h"
|
||||
#include"theory_str_params.h"
|
||||
#include"trail.h"
|
||||
#include"th_rewriter.h"
|
||||
#include"value_factory.h"
|
||||
#include"smt_model_generator.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include<set>
|
||||
#include<stack>
|
||||
#include<vector>
|
||||
#include<map>
|
||||
#include"seq_decl_plugin.h"
|
||||
#include"union_find.h"
|
||||
|
||||
namespace smt {
|
||||
|
||||
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
|
||||
|
||||
class str_value_factory : public value_factory {
|
||||
seq_util u;
|
||||
symbol_set m_strings;
|
||||
std::string delim;
|
||||
unsigned m_next;
|
||||
public:
|
||||
str_value_factory(ast_manager & m, family_id fid) :
|
||||
value_factory(m, fid),
|
||||
u(m), delim("!"), m_next(0) {}
|
||||
virtual ~str_value_factory() {}
|
||||
virtual expr * get_some_value(sort * s) {
|
||||
return u.str.mk_string(symbol("some value"));
|
||||
}
|
||||
virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) {
|
||||
v1 = u.str.mk_string(symbol("value 1"));
|
||||
v2 = u.str.mk_string(symbol("value 2"));
|
||||
return true;
|
||||
}
|
||||
virtual expr * get_fresh_value(sort * s) {
|
||||
if (u.is_string(s)) {
|
||||
while (true) {
|
||||
std::ostringstream strm;
|
||||
strm << delim << std::hex << (m_next++) << std::dec << delim;
|
||||
symbol sym(strm.str().c_str());
|
||||
if (m_strings.contains(sym)) continue;
|
||||
m_strings.insert(sym);
|
||||
return u.str.mk_string(sym);
|
||||
}
|
||||
}
|
||||
sort* seq = 0;
|
||||
if (u.is_re(s, seq)) {
|
||||
expr* v0 = get_fresh_value(seq);
|
||||
return u.re.mk_to_re(v0);
|
||||
}
|
||||
TRACE("t_str", tout << "unexpected sort in get_fresh_value(): " << mk_pp(s, m_manager) << std::endl;);
|
||||
UNREACHABLE(); return NULL;
|
||||
}
|
||||
virtual void register_value(expr * n) { /* Ignore */ }
|
||||
};
|
||||
|
||||
// rather than modify obj_pair_map I inherit from it and add my own helper methods
|
||||
class theory_str_contain_pair_bool_map_t : public obj_pair_map<expr, expr, expr*> {
|
||||
public:
|
||||
expr * operator[](std::pair<expr*, expr*> key) const {
|
||||
expr * value;
|
||||
bool found = this->find(key.first, key.second, value);
|
||||
if (found) {
|
||||
return value;
|
||||
} else {
|
||||
TRACE("t_str", tout << "WARNING: lookup miss in contain_pair_bool_map!" << std::endl;);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(std::pair<expr*, expr*> key) const {
|
||||
expr * unused;
|
||||
return this->find(key.first, key.second, unused);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ctx>
|
||||
class binary_search_trail : public trail<Ctx> {
|
||||
obj_map<expr, ptr_vector<expr> > & target;
|
||||
expr * entry;
|
||||
public:
|
||||
binary_search_trail(obj_map<expr, ptr_vector<expr> > & target, expr * entry) :
|
||||
target(target), entry(entry) {}
|
||||
virtual ~binary_search_trail() {}
|
||||
virtual void undo(Ctx & ctx) {
|
||||
TRACE("t_str_binary_search", tout << "in binary_search_trail::undo()" << std::endl;);
|
||||
if (target.contains(entry)) {
|
||||
if (!target[entry].empty()) {
|
||||
target[entry].pop_back();
|
||||
} else {
|
||||
TRACE("t_str_binary_search", tout << "WARNING: attempt to remove length tester from an empty stack" << std::endl;);
|
||||
}
|
||||
} else {
|
||||
TRACE("t_str_binary_search", tout << "WARNING: attempt to access length tester map via invalid key" << std::endl;);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class nfa {
|
||||
protected:
|
||||
bool m_valid;
|
||||
unsigned m_next_id;
|
||||
|
||||
unsigned next_id() {
|
||||
unsigned retval = m_next_id;
|
||||
++m_next_id;
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned m_start_state;
|
||||
unsigned m_end_state;
|
||||
|
||||
std::map<unsigned, std::map<char, unsigned> > transition_map;
|
||||
std::map<unsigned, std::set<unsigned> > epsilon_map;
|
||||
|
||||
void make_transition(unsigned start, char symbol, unsigned end) {
|
||||
transition_map[start][symbol] = end;
|
||||
}
|
||||
|
||||
void make_epsilon_move(unsigned start, unsigned end) {
|
||||
epsilon_map[start].insert(end);
|
||||
}
|
||||
|
||||
// Convert a regular expression to an e-NFA using Thompson's construction
|
||||
void convert_re(expr * e, unsigned & start, unsigned & end, seq_util & u);
|
||||
|
||||
public:
|
||||
nfa(seq_util & u, expr * e)
|
||||
: m_valid(true), m_next_id(0), m_start_state(0), m_end_state(0) {
|
||||
convert_re(e, m_start_state, m_end_state, u);
|
||||
}
|
||||
|
||||
nfa() : m_valid(false), m_next_id(0), m_start_state(0), m_end_state(0) {}
|
||||
|
||||
bool is_valid() const {
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
void epsilon_closure(unsigned start, std::set<unsigned> & closure);
|
||||
|
||||
bool matches(zstring input);
|
||||
};
|
||||
|
||||
class theory_str : public theory {
|
||||
struct T_cut
|
||||
{
|
||||
int level;
|
||||
std::map<expr*, int> vars;
|
||||
|
||||
T_cut() {
|
||||
level = -100;
|
||||
}
|
||||
};
|
||||
|
||||
typedef trail_stack<theory_str> th_trail_stack;
|
||||
typedef union_find<theory_str> th_union_find;
|
||||
|
||||
typedef map<rational, expr*, obj_hash<rational>, default_eq<rational> > rational_map;
|
||||
struct zstring_hash_proc {
|
||||
unsigned operator()(zstring const & s) const {
|
||||
return string_hash(s.encode().c_str(), static_cast<unsigned>(s.length()), 17);
|
||||
}
|
||||
};
|
||||
typedef map<zstring, expr*, zstring_hash_proc, default_eq<zstring> > string_map;
|
||||
|
||||
protected:
|
||||
theory_str_params const & m_params;
|
||||
|
||||
/*
|
||||
* Setting EagerStringConstantLengthAssertions to true allows some methods,
|
||||
* in particular internalize_term(), to add
|
||||
* length assertions about relevant string constants.
|
||||
* Note that currently this should always be set to 'true', or else *no* length assertions
|
||||
* will be made about string constants.
|
||||
*/
|
||||
bool opt_EagerStringConstantLengthAssertions;
|
||||
|
||||
/*
|
||||
* If VerifyFinalCheckProgress is set to true, continuing after final check is invoked
|
||||
* without asserting any new axioms is considered a bug and will throw an exception.
|
||||
*/
|
||||
bool opt_VerifyFinalCheckProgress;
|
||||
|
||||
/*
|
||||
* This constant controls how eagerly we expand unrolls in unbounded regex membership tests.
|
||||
*/
|
||||
int opt_LCMUnrollStep;
|
||||
|
||||
/*
|
||||
* If NoQuickReturn_IntegerTheory is set to true,
|
||||
* integer theory integration checks that assert axioms
|
||||
* will not return from the function after asserting their axioms.
|
||||
* The default behaviour of Z3str2 is to set this to 'false'. This may be incorrect.
|
||||
*/
|
||||
bool opt_NoQuickReturn_IntegerTheory;
|
||||
|
||||
/*
|
||||
* If DisableIntegerTheoryIntegration is set to true,
|
||||
* ALL calls to the integer theory integration methods
|
||||
* (get_value, get_len_value, lower_bound, upper_bound)
|
||||
* will ignore what the arithmetic solver believes about length terms,
|
||||
* and will return no information.
|
||||
*
|
||||
* This reduces performance significantly, but can be useful to enable
|
||||
* if it is suspected that string-integer integration, or the arithmetic solver itself,
|
||||
* might have a bug.
|
||||
*
|
||||
* The default behaviour of Z3str2 is to set this to 'false'.
|
||||
*/
|
||||
bool opt_DisableIntegerTheoryIntegration;
|
||||
|
||||
/*
|
||||
* If DeferEQCConsistencyCheck is set to true,
|
||||
* expensive calls to new_eq_check() will be deferred until final check,
|
||||
* at which time the consistency of *all* string equivalence classes will be validated.
|
||||
*/
|
||||
bool opt_DeferEQCConsistencyCheck;
|
||||
|
||||
/*
|
||||
* If CheckVariableScope is set to true,
|
||||
* pop_scope_eh() and final_check_eh() will run extra checks
|
||||
* to determine whether the current assignment
|
||||
* contains references to any internal variables that are no longer in scope.
|
||||
*/
|
||||
bool opt_CheckVariableScope;
|
||||
|
||||
/*
|
||||
* If ConcatOverlapAvoid is set to true,
|
||||
* the check to simplify Concat = Concat in handle_equality() will
|
||||
* avoid simplifying wrt. pairs of Concat terms that will immediately
|
||||
* result in an overlap. (false = Z3str2 behaviour)
|
||||
*/
|
||||
bool opt_ConcatOverlapAvoid;
|
||||
|
||||
bool search_started;
|
||||
arith_util m_autil;
|
||||
seq_util u;
|
||||
int sLevel;
|
||||
|
||||
bool finalCheckProgressIndicator;
|
||||
|
||||
expr_ref_vector m_trail; // trail for generated terms
|
||||
|
||||
str_value_factory * m_factory;
|
||||
|
||||
// terms we couldn't go through set_up_axioms() with because they weren't internalized
|
||||
expr_ref_vector m_delayed_axiom_setup_terms;
|
||||
|
||||
ptr_vector<enode> m_basicstr_axiom_todo;
|
||||
svector<std::pair<enode*,enode*> > m_str_eq_todo;
|
||||
ptr_vector<enode> m_concat_axiom_todo;
|
||||
ptr_vector<enode> m_string_constant_length_todo;
|
||||
ptr_vector<enode> m_concat_eval_todo;
|
||||
|
||||
// enode lists for library-aware/high-level string terms (e.g. substr, contains)
|
||||
ptr_vector<enode> m_library_aware_axiom_todo;
|
||||
|
||||
// hashtable of all exprs for which we've already set up term-specific axioms --
|
||||
// this prevents infinite recursive descent with respect to axioms that
|
||||
// include an occurrence of the term for which axioms are being generated
|
||||
obj_hashtable<expr> axiomatized_terms;
|
||||
|
||||
int tmpStringVarCount;
|
||||
int tmpXorVarCount;
|
||||
int tmpLenTestVarCount;
|
||||
int tmpValTestVarCount;
|
||||
std::map<std::pair<expr*, expr*>, std::map<int, expr*> > varForBreakConcat;
|
||||
|
||||
bool avoidLoopCut;
|
||||
bool loopDetected;
|
||||
obj_map<expr, std::stack<T_cut*> > cut_var_map;
|
||||
expr_ref m_theoryStrOverlapAssumption_term;
|
||||
|
||||
obj_hashtable<expr> variable_set;
|
||||
obj_hashtable<expr> internal_variable_set;
|
||||
obj_hashtable<expr> regex_variable_set;
|
||||
std::map<int, std::set<expr*> > internal_variable_scope_levels;
|
||||
|
||||
obj_hashtable<expr> internal_lenTest_vars;
|
||||
obj_hashtable<expr> internal_valTest_vars;
|
||||
obj_hashtable<expr> internal_unrollTest_vars;
|
||||
|
||||
obj_hashtable<expr> input_var_in_len;
|
||||
|
||||
obj_map<expr, unsigned int> fvar_len_count_map;
|
||||
std::map<expr*, ptr_vector<expr> > fvar_lenTester_map;
|
||||
obj_map<expr, expr*> lenTester_fvar_map;
|
||||
|
||||
std::map<expr*, std::map<int, svector<std::pair<int, expr*> > > > fvar_valueTester_map;
|
||||
std::map<expr*, expr*> valueTester_fvar_map;
|
||||
|
||||
std::map<expr*, int_vector> val_range_map;
|
||||
|
||||
// This can't be an expr_ref_vector because the constructor is wrong,
|
||||
// we would need to modify the allocator so we pass in ast_manager
|
||||
std::map<expr*, std::map<std::set<expr*>, ptr_vector<expr> > > unroll_tries_map;
|
||||
std::map<expr*, expr*> unroll_var_map;
|
||||
std::map<std::pair<expr*, expr*>, expr*> concat_eq_unroll_ast_map;
|
||||
|
||||
expr_ref_vector contains_map;
|
||||
|
||||
theory_str_contain_pair_bool_map_t contain_pair_bool_map;
|
||||
//obj_map<expr, obj_pair_set<expr, expr> > contain_pair_idx_map;
|
||||
std::map<expr*, std::set<std::pair<expr*, expr*> > > contain_pair_idx_map;
|
||||
|
||||
std::map<std::pair<expr*, zstring>, expr*> regex_in_bool_map;
|
||||
std::map<expr*, std::set<zstring> > regex_in_var_reg_str_map;
|
||||
|
||||
std::map<expr*, nfa> regex_nfa_cache; // Regex term --> NFA
|
||||
|
||||
char * char_set;
|
||||
std::map<char, int> charSetLookupTable;
|
||||
int charSetSize;
|
||||
|
||||
obj_pair_map<expr, expr, expr*> concat_astNode_map;
|
||||
|
||||
// all (str.to-int) and (int.to-str) terms
|
||||
expr_ref_vector string_int_conversion_terms;
|
||||
obj_hashtable<expr> string_int_axioms;
|
||||
|
||||
// used when opt_FastLengthTesterCache is true
|
||||
rational_map lengthTesterCache;
|
||||
// used when opt_FastValueTesterCache is true
|
||||
string_map valueTesterCache;
|
||||
|
||||
string_map stringConstantCache;
|
||||
unsigned long totalCacheAccessCount;
|
||||
unsigned long cacheHitCount;
|
||||
unsigned long cacheMissCount;
|
||||
|
||||
// cache mapping each string S to Length(S)
|
||||
obj_map<expr, app*> length_ast_map;
|
||||
|
||||
th_union_find m_find;
|
||||
th_trail_stack m_trail_stack;
|
||||
theory_var get_var(expr * n) const;
|
||||
expr * get_eqc_next(expr * n);
|
||||
app * get_ast(theory_var i);
|
||||
|
||||
// binary search heuristic data
|
||||
struct binary_search_info {
|
||||
rational lowerBound;
|
||||
rational midPoint;
|
||||
rational upperBound;
|
||||
rational windowSize;
|
||||
|
||||
binary_search_info() : lowerBound(rational::zero()), midPoint(rational::zero()),
|
||||
upperBound(rational::zero()), windowSize(rational::zero()) {}
|
||||
binary_search_info(rational lower, rational mid, rational upper, rational windowSize) :
|
||||
lowerBound(lower), midPoint(mid), upperBound(upper), windowSize(windowSize) {}
|
||||
|
||||
void calculate_midpoint() {
|
||||
midPoint = floor(lowerBound + ((upperBound - lowerBound) / rational(2)) );
|
||||
}
|
||||
};
|
||||
// maps a free string var to a stack of active length testers.
|
||||
// can use binary_search_trail to record changes to this object
|
||||
obj_map<expr, ptr_vector<expr> > binary_search_len_tester_stack;
|
||||
// maps a length tester var to the *active* search window
|
||||
obj_map<expr, binary_search_info> binary_search_len_tester_info;
|
||||
// maps a free string var to the first length tester to be (re)used
|
||||
obj_map<expr, expr*> binary_search_starting_len_tester;
|
||||
// maps a length tester to the next length tester to be (re)used if the split is "low"
|
||||
obj_map<expr, expr*> binary_search_next_var_low;
|
||||
// maps a length tester to the next length tester to be (re)used if the split is "high"
|
||||
obj_map<expr, expr*> binary_search_next_var_high;
|
||||
|
||||
// finite model finding data
|
||||
// maps a finite model tester var to a list of variables that will be tested
|
||||
obj_map<expr, ptr_vector<expr> > finite_model_test_varlists;
|
||||
protected:
|
||||
void assert_axiom(expr * e);
|
||||
void assert_implication(expr * premise, expr * conclusion);
|
||||
expr * rewrite_implication(expr * premise, expr * conclusion);
|
||||
|
||||
expr * mk_string(zstring const& str);
|
||||
expr * mk_string(const char * str);
|
||||
|
||||
app * mk_strlen(expr * e);
|
||||
expr * mk_concat(expr * n1, expr * n2);
|
||||
expr * mk_concat_const_str(expr * n1, expr * n2);
|
||||
app * mk_contains(expr * haystack, expr * needle);
|
||||
app * mk_indexof(expr * haystack, expr * needle);
|
||||
app * mk_fresh_const(char const* name, sort* s);
|
||||
|
||||
literal mk_literal(expr* _e);
|
||||
app * mk_int(int n);
|
||||
app * mk_int(rational & q);
|
||||
|
||||
void check_and_init_cut_var(expr * node);
|
||||
void add_cut_info_one_node(expr * baseNode, int slevel, expr * node);
|
||||
void add_cut_info_merge(expr * destNode, int slevel, expr * srcNode);
|
||||
bool has_self_cut(expr * n1, expr * n2);
|
||||
|
||||
// for ConcatOverlapAvoid
|
||||
bool will_result_in_overlap(expr * lhs, expr * rhs);
|
||||
|
||||
void track_variable_scope(expr * var);
|
||||
app * mk_str_var(std::string name);
|
||||
app * mk_int_var(std::string name);
|
||||
app * mk_nonempty_str_var();
|
||||
app * mk_internal_xor_var();
|
||||
expr * mk_internal_valTest_var(expr * node, int len, int vTries);
|
||||
app * mk_regex_rep_var();
|
||||
app * mk_unroll_bound_var();
|
||||
app * mk_unroll_test_var();
|
||||
void add_nonempty_constraint(expr * s);
|
||||
|
||||
void instantiate_concat_axiom(enode * cat);
|
||||
void try_eval_concat(enode * cat);
|
||||
void instantiate_basic_string_axioms(enode * str);
|
||||
void instantiate_str_eq_length_axiom(enode * lhs, enode * rhs);
|
||||
|
||||
void instantiate_axiom_CharAt(enode * e);
|
||||
void instantiate_axiom_prefixof(enode * e);
|
||||
void instantiate_axiom_suffixof(enode * e);
|
||||
void instantiate_axiom_Contains(enode * e);
|
||||
void instantiate_axiom_Indexof(enode * e);
|
||||
void instantiate_axiom_Indexof2(enode * e);
|
||||
void instantiate_axiom_LastIndexof(enode * e);
|
||||
void instantiate_axiom_Substr(enode * e);
|
||||
void instantiate_axiom_Replace(enode * e);
|
||||
void instantiate_axiom_str_to_int(enode * e);
|
||||
void instantiate_axiom_int_to_str(enode * e);
|
||||
|
||||
expr * mk_RegexIn(expr * str, expr * regexp);
|
||||
void instantiate_axiom_RegexIn(enode * e);
|
||||
app * mk_unroll(expr * n, expr * bound);
|
||||
|
||||
void process_unroll_eq_const_str(expr * unrollFunc, expr * constStr);
|
||||
void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr);
|
||||
void process_concat_eq_unroll(expr * concat, expr * unroll);
|
||||
|
||||
void set_up_axioms(expr * ex);
|
||||
void handle_equality(expr * lhs, expr * rhs);
|
||||
|
||||
app * mk_value_helper(app * n);
|
||||
expr * get_eqc_value(expr * n, bool & hasEqcValue);
|
||||
expr * z3str2_get_eqc_value(expr * n , bool & hasEqcValue);
|
||||
bool in_same_eqc(expr * n1, expr * n2);
|
||||
expr * collect_eq_nodes(expr * n, expr_ref_vector & eqcSet);
|
||||
|
||||
bool get_value(expr* e, rational& val) const;
|
||||
bool get_len_value(expr* e, rational& val);
|
||||
bool lower_bound(expr* _e, rational& lo);
|
||||
bool upper_bound(expr* _e, rational& hi);
|
||||
|
||||
bool can_two_nodes_eq(expr * n1, expr * n2);
|
||||
bool can_concat_eq_str(expr * concat, zstring& str);
|
||||
bool can_concat_eq_concat(expr * concat1, expr * concat2);
|
||||
bool check_concat_len_in_eqc(expr * concat);
|
||||
bool check_length_consistency(expr * n1, expr * n2);
|
||||
bool check_length_const_string(expr * n1, expr * constStr);
|
||||
bool check_length_eq_var_concat(expr * n1, expr * n2);
|
||||
bool check_length_concat_concat(expr * n1, expr * n2);
|
||||
bool check_length_concat_var(expr * concat, expr * var);
|
||||
bool check_length_var_var(expr * var1, expr * var2);
|
||||
void check_contain_in_new_eq(expr * n1, expr * n2);
|
||||
void check_contain_by_eqc_val(expr * varNode, expr * constNode);
|
||||
void check_contain_by_substr(expr * varNode, expr_ref_vector & willEqClass);
|
||||
void check_contain_by_eq_nodes(expr * n1, expr * n2);
|
||||
bool in_contain_idx_map(expr * n);
|
||||
void compute_contains(std::map<expr*, expr*> & varAliasMap,
|
||||
std::map<expr*, expr*> & concatAliasMap, std::map<expr*, expr *> & varConstMap,
|
||||
std::map<expr*, expr*> & concatConstMap, std::map<expr*, std::map<expr*, int> > & varEqConcatMap);
|
||||
expr * dealias_node(expr * node, std::map<expr*, expr*> & varAliasMap, std::map<expr*, expr*> & concatAliasMap);
|
||||
void get_grounded_concats(expr* node, std::map<expr*, expr*> & varAliasMap,
|
||||
std::map<expr*, expr*> & concatAliasMap, std::map<expr*, expr*> & varConstMap,
|
||||
std::map<expr*, expr*> & concatConstMap, std::map<expr*, std::map<expr*, int> > & varEqConcatMap,
|
||||
std::map<expr*, std::map<std::vector<expr*>, std::set<expr*> > > & groundedMap);
|
||||
void print_grounded_concat(expr * node, std::map<expr*, std::map<std::vector<expr*>, std::set<expr*> > > & groundedMap);
|
||||
void check_subsequence(expr* str, expr* strDeAlias, expr* subStr, expr* subStrDeAlias, expr* boolVar,
|
||||
std::map<expr*, std::map<std::vector<expr*>, std::set<expr*> > > & groundedMap);
|
||||
bool is_partial_in_grounded_concat(const std::vector<expr*> & strVec, const std::vector<expr*> & subStrVec);
|
||||
|
||||
void get_nodes_in_concat(expr * node, ptr_vector<expr> & nodeList);
|
||||
expr * simplify_concat(expr * node);
|
||||
|
||||
void simplify_parent(expr * nn, expr * eq_str);
|
||||
|
||||
void simplify_concat_equality(expr * lhs, expr * rhs);
|
||||
void solve_concat_eq_str(expr * concat, expr * str);
|
||||
|
||||
void infer_len_concat_equality(expr * nn1, expr * nn2);
|
||||
bool infer_len_concat(expr * n, rational & nLen);
|
||||
void infer_len_concat_arg(expr * n, rational len);
|
||||
|
||||
bool is_concat_eq_type1(expr * concatAst1, expr * concatAst2);
|
||||
bool is_concat_eq_type2(expr * concatAst1, expr * concatAst2);
|
||||
bool is_concat_eq_type3(expr * concatAst1, expr * concatAst2);
|
||||
bool is_concat_eq_type4(expr * concatAst1, expr * concatAst2);
|
||||
bool is_concat_eq_type5(expr * concatAst1, expr * concatAst2);
|
||||
bool is_concat_eq_type6(expr * concatAst1, expr * concatAst2);
|
||||
|
||||
void process_concat_eq_type1(expr * concatAst1, expr * concatAst2);
|
||||
void process_concat_eq_type2(expr * concatAst1, expr * concatAst2);
|
||||
void process_concat_eq_type3(expr * concatAst1, expr * concatAst2);
|
||||
void process_concat_eq_type4(expr * concatAst1, expr * concatAst2);
|
||||
void process_concat_eq_type5(expr * concatAst1, expr * concatAst2);
|
||||
void process_concat_eq_type6(expr * concatAst1, expr * concatAst2);
|
||||
|
||||
void print_cut_var(expr * node, std::ofstream & xout);
|
||||
|
||||
void generate_mutual_exclusion(expr_ref_vector & exprs);
|
||||
void add_theory_aware_branching_info(expr * term, double priority, lbool phase);
|
||||
|
||||
bool new_eq_check(expr * lhs, expr * rhs);
|
||||
void group_terms_by_eqc(expr * n, std::set<expr*> & concats, std::set<expr*> & vars, std::set<expr*> & consts);
|
||||
|
||||
int ctx_dep_analysis(std::map<expr*, int> & strVarMap, std::map<expr*, int> & freeVarMap,
|
||||
std::map<expr*, std::set<expr*> > & unrollGroupMap, std::map<expr*, std::map<expr*, int> > & var_eq_concat_map);
|
||||
void trace_ctx_dep(std::ofstream & tout,
|
||||
std::map<expr*, expr*> & aliasIndexMap,
|
||||
std::map<expr*, expr*> & var_eq_constStr_map,
|
||||
std::map<expr*, std::map<expr*, int> > & var_eq_concat_map,
|
||||
std::map<expr*, std::map<expr*, int> > & var_eq_unroll_map,
|
||||
std::map<expr*, expr*> & concat_eq_constStr_map,
|
||||
std::map<expr*, std::map<expr*, int> > & concat_eq_concat_map,
|
||||
std::map<expr*, std::set<expr*> > & unrollGroupMap);
|
||||
|
||||
void classify_ast_by_type(expr * node, std::map<expr*, int> & varMap,
|
||||
std::map<expr*, int> & concatMap, std::map<expr*, int> & unrollMap);
|
||||
void classify_ast_by_type_in_positive_context(std::map<expr*, int> & varMap,
|
||||
std::map<expr*, int> & concatMap, std::map<expr*, int> & unrollMap);
|
||||
|
||||
expr * mk_internal_lenTest_var(expr * node, int lTries);
|
||||
expr * gen_len_val_options_for_free_var(expr * freeVar, expr * lenTesterInCbEq, zstring lenTesterValue);
|
||||
void process_free_var(std::map<expr*, int> & freeVar_map);
|
||||
expr * gen_len_test_options(expr * freeVar, expr * indicator, int tries);
|
||||
expr * gen_free_var_options(expr * freeVar, expr * len_indicator,
|
||||
zstring len_valueStr, expr * valTesterInCbEq, zstring valTesterValueStr);
|
||||
expr * gen_val_options(expr * freeVar, expr * len_indicator, expr * val_indicator,
|
||||
zstring lenStr, int tries);
|
||||
void print_value_tester_list(svector<std::pair<int, expr*> > & testerList);
|
||||
bool get_next_val_encode(int_vector & base, int_vector & next);
|
||||
zstring gen_val_string(int len, int_vector & encoding);
|
||||
|
||||
// binary search heuristic
|
||||
expr * binary_search_length_test(expr * freeVar, expr * previousLenTester, zstring previousLenTesterValue);
|
||||
expr_ref binary_search_case_split(expr * freeVar, expr * tester, binary_search_info & bounds, literal_vector & case_split_lits);
|
||||
|
||||
bool free_var_attempt(expr * nn1, expr * nn2);
|
||||
void more_len_tests(expr * lenTester, zstring lenTesterValue);
|
||||
void more_value_tests(expr * valTester, zstring valTesterValue);
|
||||
|
||||
expr * get_alias_index_ast(std::map<expr*, expr*> & aliasIndexMap, expr * node);
|
||||
expr * getMostLeftNodeInConcat(expr * node);
|
||||
expr * getMostRightNodeInConcat(expr * node);
|
||||
void get_var_in_eqc(expr * n, std::set<expr*> & varSet);
|
||||
void get_concats_in_eqc(expr * n, std::set<expr*> & concats);
|
||||
void get_const_str_asts_in_node(expr * node, expr_ref_vector & constList);
|
||||
expr * eval_concat(expr * n1, expr * n2);
|
||||
|
||||
bool finalcheck_str2int(app * a);
|
||||
bool finalcheck_int2str(app * a);
|
||||
|
||||
// strRegex
|
||||
|
||||
void get_eqc_allUnroll(expr * n, expr * &constStr, std::set<expr*> & unrollFuncSet);
|
||||
void get_eqc_simpleUnroll(expr * n, expr * &constStr, std::set<expr*> & unrollFuncSet);
|
||||
void gen_assign_unroll_reg(std::set<expr*> & unrolls);
|
||||
expr * gen_assign_unroll_Str2Reg(expr * n, std::set<expr*> & unrolls);
|
||||
expr * gen_unroll_conditional_options(expr * var, std::set<expr*> & unrolls, zstring lcmStr);
|
||||
expr * gen_unroll_assign(expr * var, zstring lcmStr, expr * testerVar, int l, int h);
|
||||
void reduce_virtual_regex_in(expr * var, expr * regex, expr_ref_vector & items);
|
||||
void check_regex_in(expr * nn1, expr * nn2);
|
||||
zstring get_std_regex_str(expr * r);
|
||||
|
||||
void dump_assignments();
|
||||
void initialize_charset();
|
||||
|
||||
void check_variable_scope();
|
||||
void recursive_check_variable_scope(expr * ex);
|
||||
|
||||
void collect_var_concat(expr * node, std::set<expr*> & varSet, std::set<expr*> & concatSet);
|
||||
bool propagate_length(std::set<expr*> & varSet, std::set<expr*> & concatSet, std::map<expr*, int> & exprLenMap);
|
||||
void get_unique_non_concat_nodes(expr * node, std::set<expr*> & argSet);
|
||||
bool propagate_length_within_eqc(expr * var);
|
||||
|
||||
// TESTING
|
||||
void refresh_theory_var(expr * e);
|
||||
|
||||
expr_ref set_up_finite_model_test(expr * lhs, expr * rhs);
|
||||
void finite_model_test(expr * v, expr * c);
|
||||
|
||||
public:
|
||||
theory_str(ast_manager & m, theory_str_params const & params);
|
||||
virtual ~theory_str();
|
||||
|
||||
virtual char const * get_name() const { return "seq"; }
|
||||
virtual void display(std::ostream & out) const;
|
||||
|
||||
bool overlapping_variables_detected() const { return loopDetected; }
|
||||
|
||||
th_trail_stack& get_trail_stack() { return m_trail_stack; }
|
||||
void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2) {}
|
||||
void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { }
|
||||
void unmerge_eh(theory_var v1, theory_var v2) {}
|
||||
protected:
|
||||
virtual bool internalize_atom(app * atom, bool gate_ctx);
|
||||
virtual bool internalize_term(app * term);
|
||||
virtual enode* ensure_enode(expr* e);
|
||||
virtual theory_var mk_var(enode * n);
|
||||
|
||||
virtual void new_eq_eh(theory_var, theory_var);
|
||||
virtual void new_diseq_eh(theory_var, theory_var);
|
||||
|
||||
virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager(), m_params); }
|
||||
virtual void init_search_eh();
|
||||
virtual void add_theory_assumptions(expr_ref_vector & assumptions);
|
||||
virtual lbool validate_unsat_core(expr_ref_vector & unsat_core);
|
||||
virtual void relevant_eh(app * n);
|
||||
virtual void assign_eh(bool_var v, bool is_true);
|
||||
virtual void push_scope_eh();
|
||||
virtual void pop_scope_eh(unsigned num_scopes);
|
||||
virtual void reset_eh();
|
||||
|
||||
virtual bool can_propagate();
|
||||
virtual void propagate();
|
||||
|
||||
virtual final_check_status final_check_eh();
|
||||
virtual void attach_new_th_var(enode * n);
|
||||
|
||||
virtual void init_model(model_generator & m);
|
||||
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||
virtual void finalize_model(model_generator & mg);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _THEORY_STR_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue