#include "Debug/Tracer.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Problem.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/Renaming.hpp"
#include "SAT/CadicalInterfacing.hpp"
#include "SAT/MinisatInterfacing.hpp"
#include "Lib/Environment.hpp"
#include "Lib/Timer.hpp"
#include "Lib/List.hpp"
#include "Lib/Stack.hpp"
#include "Lib/System.hpp"
#include "Lib/DHSet.hpp"
#include "Lib/ArrayMap.hpp"
#include "Shell/UIHelper.hpp"
#include "Shell/Statistics.hpp"
#include "Shell/GeneralSplitting.hpp"
#include "Shell/Shuffling.hpp"
#include "FiniteModelMultiSorted.hpp"
#include "ClauseFlattening.hpp"
#include "SortInference.hpp"
#include "DefinitionIntroduction.hpp"
#include "FunctionRelationshipInference.hpp"
#include "CliqueFinder.hpp"
#include "Monotonicity.hpp"
#include "FiniteModelBuilder.hpp"
#define VTRACE_FMB 0
#define VTRACE_DOMAINS 0
#define LOG(X)
namespace FMB
{
using namespace std;
FiniteModelBuilder::FiniteModelBuilder(Problem& prb, const Options& opt)
: MainLoop(prb, opt), _sortedSignature(0), _groundClauses(0), _clauses(0),
_isAppropriate(true)
{
Property& prop = *prb.getProperty();
LOG(prop.hasInterpretedOperations());
LOG(prop.hasProp(Property::PR_HAS_INTEGERS));
LOG(prop.hasProp(Property::PR_HAS_REALS));
LOG(prop.hasProp(Property::PR_HAS_RATS));
LOG(prop.hasProp(Property::PR_HAS_DT_CONSTRUCTORS));
LOG(prop.hasProp(Property::PR_HAS_CDT_CONSTRUCTORS));
LOG(prop.knownInfiniteDomain());
if (prop.hasInterpretedOperations()
|| prop.hasProp(Property::PR_HAS_INTEGERS)
|| prop.hasProp(Property::PR_HAS_REALS)
|| prop.hasProp(Property::PR_HAS_RATS)
|| prop.knownInfiniteDomain() || env.getMainProblem()->hasInterpretedOperations()) {
if(outputAllowed()) {
addCommentSignForSZS(std::cout);
std::cout << "WARNING: trying to run FMB on interpreted or otherwise provably infinite-domain problem!" << endl;
}
_isAppropriate = false;
_dsaEnumerator = 0; return;
}
if (prb.hadIncompleteTransformation() ||
opt.sineSelection() != Options::SineSelection::OFF) {
_isAppropriate = false;
_dsaEnumerator = 0; return;
}
_startModelSize = opt.fmbStartSize();
_symmetryRatio = opt.fmbSymmetryRatio();
switch(opt.fmbEnumerationStrategy()) {
case Options::FMBEnumerationStrategy::SBMEAM:
_dsaEnumerator = new HackyDSAE(opt.keepSbeamGenerators());
_xmass = false;
break;
#if VZ3
case Options::FMBEnumerationStrategy::SMT:
_dsaEnumerator = new SmtBasedDSAE();
_xmass = false;
break;
#endif
case Options::FMBEnumerationStrategy::CONTOUR:
_dsaEnumerator = 0;
_xmass = true;
_sizeWeightRatio = opt.fmbSizeWeightRatio();
break;
default:
ASSERTION_VIOLATION;
}
}
FiniteModelBuilder::~FiniteModelBuilder()
{
if(_dsaEnumerator){
delete _dsaEnumerator;
}
}
bool FiniteModelBuilder::reset(){
static const unsigned VAR_MAX = MinisatInterfacingNewSimp::VAR_MAX;
unsigned offsets=1;
for(unsigned f=0; f<env.signature->functions();f++){
if(del_f[f]) continue;
f_offsets[f]=offsets;
#if VTRACE_FMB
cout << "offset for " << f << " is " << offsets << " (arity is " << env.signature->functionArity(f) << ") " << endl;
#endif
auto const& f_signature = _sortedSignature->functionSignatures[f];
ASS(f_signature.size() == env.signature->functionArity(f)+1);
unsigned add = _sortModelSizes[f_signature[0]];
for(unsigned i=1;i<f_signature.size();i++){
unsigned n_add = add * _sortModelSizes[f_signature[i]];
if (n_add < add) { return false;
}
add = n_add;
}
if(VAR_MAX - add < offsets){
return false;
}
offsets += add;
}
for(unsigned p=1; p<env.signature->predicates();p++){
if(del_p[p]) continue;
p_offsets[p]=offsets;
#if VTRACE_FMB
cout << "offset for " << p << " is " << offsets << " for " << env.signature->predicateName(p) << endl;
#endif
auto const& p_signature = _sortedSignature->predicateSignatures[p];
ASS(p_signature.size()==env.signature->predicateArity(p));
unsigned add=1;
for(unsigned i=0;i<p_signature.size();i++){
unsigned n_add = add * _sortModelSizes[p_signature[i]];
if (n_add < add) { return false;
}
add = n_add;
}
if(VAR_MAX - add < offsets){
return false;
}
offsets += add;
}
#if VTRACE_FMB
cout << "Maximum offset is " << offsets << endl;
#endif
if (_xmass) {
marker_offsets.ensure(_distinctSortSizes.size());
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
unsigned add = _distinctSortSizes[i];
marker_offsets[i] = offsets;
if(VAR_MAX - add < offsets){
return false;
}
offsets += add;
}
} else {
unsigned add = _distinctSortSizes.size();
totalityMarker_offset = offsets;
if(VAR_MAX - add < offsets){
return false;
}
offsets += add;
instancesMarker_offset = offsets;
if(VAR_MAX - add < offsets){
return false;
}
offsets += add;
}
if (env.options->satSolver() == Options::SatSolver::MINISAT) {
if(env.options->fmbUseSimplifyingSolver())
_solver = new MinisatInterfacingNewSimp;
else
_solver = new MinisatInterfacing;
}
else if (env.options->satSolver() == Options::SatSolver::CADICAL) {
_solver = new CadicalInterfacing;
} else {
USER_ERROR("Finite model builder can only use minisat or cadical as SAT solvers.");
}
_curMaxVar = offsets-1;
_solver->ensureVarCount(_curMaxVar);
createSymmetryOrdering();
return true;
}
struct FMBSymmetryFunctionComparator
{
static bool compare(unsigned f1, unsigned f2)
{
unsigned c1 = env.signature->getFunction(f1)->usageCnt();
unsigned c2 = env.signature->getFunction(f2)->usageCnt();
return c2 < c1;
}
};
void FiniteModelBuilder::createSymmetryOrdering()
{
_sortedGroundedTerms.ensure(_sortedSignature->sorts);
for(unsigned s=0;s<_sortedSignature->sorts;s++){
unsigned size = _sortModelSizes[s];
_sortedGroundedTerms[s].reset();
for(unsigned c=0;c<_sortedSignature->sortedConstants[s].length();c++){
GroundedTerm g;
g.f = _sortedSignature->sortedConstants[s][c];
g.grounding.ensure(0); _sortedGroundedTerms[s].push(g);
}
bool arg_first = false;
switch(env.options->fmbSymmetryWidgetOrders()){
case Options::FMBWidgetOrders::FUNCTION_FIRST:
{
for(unsigned f=0;f<_sortedSignature->sortedFunctions[s].length();f++){
for(unsigned m=1;m<=size;m++){
GroundedTerm g;
g.f =_sortedSignature->sortedFunctions[s][f];
unsigned arity = env.signature->functionArity(g.f);
unsigned gfsrt = _sortedSignature->functionSignatures[g.f][arity];
if(_sortedSignature->sortBounds[gfsrt] < size) continue;
g.grounding.ensure(arity);
bool outOfBounds = false;
for(unsigned i=0;i<arity;i++){
unsigned srtx = _sortedSignature->functionSignatures[g.f][i];
g.grounding[i] = min(m,_sortModelSizes[srtx]);
if(_sortedSignature->sortBounds[srtx] < g.grounding[i])
outOfBounds=true;
}
if(outOfBounds) continue;
_sortedGroundedTerms[s].push(g);
}
}
break;
}
case Options::FMBWidgetOrders::ARGUMENT_FIRST:
arg_first=true;
case Options::FMBWidgetOrders::DIAGONAL:
{
for(unsigned m=1;m<=size;m++){
for(unsigned f=0;f<_sortedSignature->sortedFunctions[s].length();f++){
GroundedTerm g;
g.f =_sortedSignature->sortedFunctions[s][f];
unsigned arity = env.signature->functionArity(g.f);
unsigned gfsrt = _sortedSignature->functionSignatures[g.f][arity];
if(_sortedSignature->sortBounds[gfsrt] < size) continue;
unsigned groundWith = arg_first ? m : 1+((m+f)%(size));
g.grounding.ensure(arity);
bool outOfBounds = false;
for(unsigned i=0;i<arity;i++){
unsigned srtx = _sortedSignature->functionSignatures[g.f][i];
g.grounding[i] = min(groundWith,_sortModelSizes[srtx]);
if(_sortedSignature->sortBounds[srtx] < g.grounding[i])
outOfBounds=true;
}
if(outOfBounds) continue;
_sortedGroundedTerms[s].push(g);
}
}
}
}
}
}
void FiniteModelBuilder::init()
{
if(!_isAppropriate) return;
if(!_prb.units()) return;
env.statistics->phase = ExecutionPhase::FMB_PREPROCESSING;
DHSet<std::pair<unsigned,unsigned>> vampire_sort_constraints_nonstrict;
DHSet<std::pair<unsigned,unsigned>> vampire_sort_constraints_strict;
if(env.options->fmbDetectSortBounds()){
FunctionRelationshipInference inf;
inf.findFunctionRelationships(
_prb.clauseIterator(),
vampire_sort_constraints_nonstrict,
vampire_sort_constraints_strict);
}
ClauseList* clist = 0;
if(env.options->fmbAdjustSorts() == Options::FMBAdjustSorts::PREDICATE){
DArray<bool> deleted_functions(env.signature->functions());
for(unsigned f=0;f<env.signature->functions();f++){
deleted_functions[f] = env.signature->getFunction(f)->usageCnt()==0;
}
ClauseList::pushFromIterator(_prb.clauseIterator(),clist);
Monotonicity::addSortPredicates(true,clist,deleted_functions,_monotonic_vampire_sorts,_sortPredicates);
}
if(env.options->fmbAdjustSorts() == Options::FMBAdjustSorts::FUNCTION){
ClauseList::pushFromIterator(_prb.clauseIterator(),clist);
Monotonicity::addSortFunctions(true,clist,_monotonic_vampire_sorts,_sortFunctions);
}
DefinitionIntroduction cit = DefinitionIntroduction(
(clist ? pvi(ClauseList::Iterator(clist)) : _prb.clauseIterator())
);
DArray<DHMap<unsigned,DHSet<unsigned>*>*> _distinctConstants;
_distinctConstants.ensure(env.signature->typeCons());
for(unsigned i=0;i<env.signature->typeCons();i++){ _distinctConstants[i]=0; }
while(cit.hasNext()){
Clause* c = cit.next();
if(c->length()==1 && c->varCnt()==0){
Literal* l = (*c)[0];
if(l->isEquality() && l->isNegative()){
TermList* left = l->nthArgument(0);
TermList* right = l->nthArgument(1);
if(left==right){
throw RefutationFoundException(c);
}
if(left->isTerm() && left->term()->arity()==0 &&
right->isTerm() && right->term()->arity()==0){
TermList srtT = SortHelper::getResultSort(left->term());
unsigned srt = srtT.term()->functor();
auto map = _distinctConstants[srt];
if(map==0){
map = new DHMap<unsigned,DHSet<unsigned>*>();
_distinctConstants[srt]=map;
}
unsigned lnum = left->term()->functor();
unsigned rnum = right->term()->functor();
{
DHSet<unsigned>* set;
if(!map->find(lnum,set)){
set = new DHSet<unsigned>();
map->insert(lnum,set);
}
set->insert(rnum);
}
{
DHSet<unsigned>* set;
if(!map->find(rnum,set)){
set = new DHSet<unsigned>();
map->insert(rnum,set);
}
set->insert(lnum);
}
}
}
}
#if VTRACE_FMB
#endif
c = ClauseFlattening::flatten(c);
#if VTRACE_FMB
#endif
ASS(c);
if(isRefutation(c)){
throw RefutationFoundException(c);
}
if(c->varCnt()==0){
#if VTRACE_FMB
#endif
ClauseList::push(c, _groundClauses);
}else{
#if VTRACE_FMB
#endif
ClauseList::push(c, _clauses);
}
}
if(!_clauses){
if(outputAllowed()){
cout << "% The problem is propositional so there are no sorts!" << endl;
}
}
GeneralSplitting splitter;
{
TIME_TRACE("fmb splitting");
splitter.apply(_clauses);
}
ClauseList::Iterator it(_clauses);
while(it.hasNext()){
Renaming n;
Clause* c = it.next();
for(unsigned i=0;i<c->length();i++){
Literal* l = (*c)[i];
n.normalizeVariables(l);
(*c)[i] = n.apply(l);
}
#if VTRACE_FMB
cout << "Normalized " << c->toString() << endl;
#endif
}
{
UnitList* units = 0; UnitList::pushFromIterator(IterTraits(ClauseList::Iterator(_groundClauses)).map([](Clause* c) { return (Unit*)c; }),units);
UnitList::pushFromIterator(IterTraits(ClauseList::Iterator(_clauses)).map([](Clause* c) { return (Unit*)c; }),units);
ScopedPtr<Property> dummy_property(Property::scan(units));
UnitList::destroy(units);
}
del_f.ensure(env.signature->functions());
del_p.ensure(env.signature->predicates());
for(unsigned f=0;f<env.signature->functions();f++){
del_f[f] = env.signature->getFunction(f)->usageCnt()==0;
#if VTRACE_FMB
if(del_f[f]) cout << "Mark " << env.signature->functionName(f) << " as deleted" << endl;
#endif
}
for(unsigned p=1;p<env.signature->predicates();p++){ del_p[p] = env.signature->getPredicate(p)->usageCnt()==0;
#if VTRACE_FMB
if(del_p[p]) {
cout << "Mark " << env.signature->predicateName(p) << " as deleted" << endl;
cout << " since (bool)_prb.getEliminatedPredicates().findPtr(p) = " << (bool)_prb.getEliminatedPredicates().findPtr(p) << endl;
cout << " since env.signature->getPredicate(p)->usageCnt() = " << env.signature->getPredicate(p)->usageCnt() << endl;
}
#endif
}
#if VTRACE_FMB
cout << "Performing Sort Inference" << endl;
#endif
{
TIME_TRACE("fmb sort inference");
SortInference inference(_clauses,del_f,del_p,_distinct_sort_constraints,_monotonic_vampire_sorts);
inference.doInference();
_sortedSignature = inference.getSignature();
ASS(_sortedSignature);
#if VTRACE_FMB
cout << "Done sort inference" << endl;
#endif
{
DHSet<std::pair<unsigned,unsigned>>::Iterator it(vampire_sort_constraints_nonstrict);
while(it.hasNext()){
std::pair<unsigned,unsigned> vconstraint = it.next();
ASS(_sortedSignature->vampireToDistinctParent.find(vconstraint.first));
ASS(_sortedSignature->vampireToDistinctParent.find(vconstraint.second));
unsigned s1 = _sortedSignature->vampireToDistinctParent.get(vconstraint.first);
unsigned s2 = _sortedSignature->vampireToDistinctParent.get(vconstraint.second);
_distinct_sort_constraints.push(make_pair(s1,s2));
}
}
{
DHSet<std::pair<unsigned,unsigned>>::Iterator it(vampire_sort_constraints_strict);
while(it.hasNext()){
std::pair<unsigned,unsigned> vconstraint = it.next();
ASS(_sortedSignature->vampireToDistinctParent.find(vconstraint.first));
ASS(_sortedSignature->vampireToDistinctParent.find(vconstraint.second));
unsigned s1 = _sortedSignature->vampireToDistinctParent.get(vconstraint.first);
unsigned s2 = _sortedSignature->vampireToDistinctParent.get(vconstraint.second);
_strict_distinct_sort_constraints.push(make_pair(s1,s2));
}
}
#if VTRACE_FMB
cout << "Finding Min and Max Sort Sizes" << endl;
#endif
_distinctSortMaxs.ensure(_sortedSignature->distinctSorts);
_distinctSortMins.ensure(_sortedSignature->distinctSorts);
for(unsigned s=0;s<_sortedSignature->distinctSorts;s++){
_distinctSortMaxs[s]=UINT_MAX;
_distinctSortMins[s]=1;
}
DArray<unsigned> bfromSI(_sortedSignature->distinctSorts);
DArray<unsigned> dConstants(_sortedSignature->distinctSorts);
DArray<unsigned> dFunctions(_sortedSignature->distinctSorts);
for(unsigned s=0;s<_sortedSignature->distinctSorts;s++){
bfromSI[s]=0;
dConstants[s]=0;
dFunctions[s]=0;
}
for(unsigned s=0;s<_sortedSignature->sorts;s++){
unsigned bound = _sortedSignature->sortBounds[s];
unsigned parent = _sortedSignature->parents[s];
if(bound > bfromSI[parent]){ bfromSI[parent]=bound; }
dConstants[parent] += (_sortedSignature->sortedConstants[s]).size();
dFunctions[parent] += (_sortedSignature->sortedFunctions[s]).size();
}
for(unsigned s=0;s<_sortedSignature->distinctSorts;s++){
_distinctSortMaxs[s] = min(_distinctSortMaxs[s],bfromSI[s]);
}
for(unsigned s=0;s<_sortedSignature->distinctSorts;s++){
bool epr = env.getMainProblem()->getProperty()->category()==Property::EPR
|| dFunctions[s]==0;
if(epr){
unsigned c = dConstants[s];
if(c==0) continue; if(_distinctSortMaxs[s]==UINT_MAX || c > _distinctSortMaxs[s]){
_distinctSortMaxs[s]=c;
}
}
}
for(unsigned s=0;s<env.signature->typeCons();s++){
if((env.getMainProblem()->getProperty()->usesSort(s) || env.signature->isNonDefaultCon(s)) && _sortedSignature->vampireToDistinct.find(s)){
Stack<unsigned>* dmembers = _sortedSignature->vampireToDistinct.get(s);
ASS(dmembers);
if(dmembers->size() > 1){
unsigned parent = _sortedSignature->vampireToDistinctParent.get(s);
Stack<unsigned>::Iterator children(*dmembers);
while(children.hasNext()){
unsigned child = children.next();
if(child==parent) continue;
_distinctSortMaxs[parent] = max(_distinctSortMaxs[parent],_distinctSortMaxs[child]);
}
}
}
}
for(unsigned s=0;s<env.signature->typeCons();s++){
if(_distinctConstants[s]!=0){
ASS(_sortedSignature->vampireToDistinct.find(s));
auto map = _distinctConstants[s];
unsigned max = CliqueFinder::findMaxCliqueSize(map);
Stack<unsigned>* dss = _sortedSignature->vampireToDistinct.get(s);
Stack<unsigned>::Iterator ds(*dss);
while(ds.hasNext()){
_distinctSortMins[ds.next()]=max;
}
#if VTRACE_FMB
cout << "Setting min for " << env.signature->typeConName(s) << " to " << max << endl;
#endif
}
}
#if VTRACE_FMB
cout << "Optionally doing Symmetry Ordering precomputation" << endl;
#endif
if(env.options->fmbSymmetryOrderSymbols() != Options::FMBSymbolOrders::PREPROCESSED_USAGE){
for(unsigned f=0;f<env.signature->functions();f++){
env.signature->getFunction(f)->resetUsageCnt();
}
{
ClauseIterator cit = pvi(ClauseList::Iterator(_clauses));
while(cit.hasNext()){
Clause* c = cit.next();
for(unsigned i=0;i<c->length();i++){
Literal* l = (*c)[i];
if(l->isEquality() && !l->isTwoVarEquality()){
ASS(!l->nthArgument(0)->isVar());
ASS(l->nthArgument(1)->isVar());
Term* t = l->nthArgument(0)->term();
unsigned f = t->functor();
env.signature->getFunction(f)->incUsageCnt();
}
}
}
}
}
if(env.options->fmbSymmetryOrderSymbols() != Options::FMBSymbolOrders::OCCURRENCE){
for(unsigned s=0;s<_sortedSignature->sorts;s++){
Stack<unsigned> sortedConstants = _sortedSignature->sortedConstants[s];
Stack<unsigned> sortedFunctions = _sortedSignature->sortedFunctions[s];
sort(sortedConstants.begin(),sortedConstants.end(), FMBSymmetryFunctionComparator::compare);
sort(sortedFunctions.begin(),sortedFunctions.end(), FMBSymmetryFunctionComparator::compare);
}
}
}
#if VTRACE_FMB
cout << "Now Find Minimum Sort Bounds" << endl;
#endif
del_f.expand(env.signature->functions());
f_offsets.ensure(env.signature->functions());
p_offsets.ensure(env.signature->predicates());
_distinctSortConstantCount.ensure(_sortedSignature->distinctSorts);
_fminbound.ensure(env.signature->functions());
for(unsigned f=0;f<env.signature->functions();f++){
if(del_f[f]) continue;
if(env.signature->functionArity(f)==0){
TermList vsrtT = env.signature->getFunction(f)->fnType()->result();
if(!vsrtT.isBoolSort()){
unsigned vsrt = vsrtT.term()->functor();
ASS(_sortedSignature->vampireToDistinctParent.find(vsrt));
unsigned dsrt = _sortedSignature->vampireToDistinctParent.get(vsrt);
_distinctSortConstantCount[dsrt]++;
}
}
if(f >= _sortedSignature->functionSignatures.size()){
_fminbound[f]=UINT_MAX;
continue;
}
const DArray<unsigned>& fsig = _sortedSignature->functionSignatures[f];
unsigned min = _sortedSignature->sortBounds[fsig[0]];
for(unsigned i=1;i<fsig.size();i++){
unsigned sz = _sortedSignature->sortBounds[fsig[i]];
if(sz<min) min = sz;
}
_fminbound[f]=min;
}
#if VTRACE_FMB
cout << "Set up Clause Signatures" << endl;
#endif
{
ClauseList::Iterator cit(_clauses);
while(cit.hasNext()){
Clause* c = cit.next();
#if VTRACE_FMB
cout << "CLAUSE " << c->toString() << endl;
#endif
DArray<unsigned>* csig = new DArray<unsigned>(c->varCnt());
DArray<bool> csig_set(c->varCnt());
for(unsigned i=0;i<c->varCnt();i++) csig_set[i]=false;
static Stack<Literal*> twoVarEqualities;
twoVarEqualities.reset();
for(unsigned i=0;i<c->length();i++){
Literal* lit = (*c)[i];
if(lit->isEquality()){
if(lit->isTwoVarEquality()){
twoVarEqualities.push(lit);
continue;
}
ASS(lit->nthArgument(0)->isTerm());
ASS(lit->nthArgument(1)->isVar());
Term* t = lit->nthArgument(0)->term();
ASS(!del_f[t->functor()]);
const DArray<unsigned>& fsg = _sortedSignature->functionSignatures[t->functor()];
ASS_REP(fsg.size() == env.signature->functionArity(t->functor())+1, fsg.size());
unsigned var = lit->nthArgument(1)->var();
unsigned ret = fsg[env.signature->functionArity(t->functor())];
if(csig_set[var]){ ASS_EQ((*csig)[var],ret); }
else{
(*csig)[var]=ret;
csig_set[var]=true;
}
for(unsigned j=0;j<t->arity();j++){
ASS(t->nthArgument(j)->isVar());
unsigned asrt = fsg[j];
unsigned avar = (t->nthArgument(j))->var();
ASS(avar < csig->size());
if(!csig_set[var]){ ASS((*csig)[avar]==asrt); }
else{
(*csig)[avar]=asrt;
csig_set[avar]=true;
}
}
}
else{
ASS_EQ(lit->arity(),env.signature->predicateArity(lit->functor()));
for(unsigned j=0;j<lit->arity();j++){
ASS(lit->nthArgument(j)->isVar());
unsigned asrt = _sortedSignature->predicateSignatures[lit->functor()][j];
unsigned avar = (lit->nthArgument(j))->var();
if(csig_set[avar]){ ASS((*csig)[avar]==asrt); }
else{
(*csig)[avar]=asrt;
csig_set[avar]=true;
}
}
}
}
Stack<Literal*>::Iterator tvit(twoVarEqualities);
while(tvit.hasNext()){
Literal* lit = tvit.next();
ASS(lit->isTwoVarEquality());
unsigned var1 = lit->nthArgument(0)->var();
unsigned var2 = lit->nthArgument(1)->var();
if(csig_set[var1]){
if(csig_set[var2]){
if((*csig)[var1] != (*csig)[var2]){
TermList litSort = lit->twoVarEqSort();
unsigned litSortU = litSort.term()->functor();
unsigned dsort = _sortedSignature->vampireToDistinctParent.get(litSortU);
unsigned sort = _sortedSignature->varEqSorts[dsort];
ASS((*csig)[var1] == sort || (*csig)[var2] == sort);
if((*csig)[var1] == sort){ (*csig)[var1] = (*csig)[var2]; }
else{ (*csig)[var2] = (*csig)[var1]; }
}
}
else{
(*csig)[var2] = (*csig)[var1];
csig_set[var2]=true;
}
}
else if(csig_set[var2]){
(*csig)[var1] = (*csig)[var2];
csig_set[var1]=true;
}
else{
TermList litSort = lit->twoVarEqSort();
unsigned litSortU = litSort.term()->functor();
unsigned dsort = _sortedSignature->vampireToDistinctParent.get(litSortU);
unsigned sort = _sortedSignature->varEqSorts[dsort];
(*csig)[var1] = sort;
(*csig)[var2] = sort;
csig_set[var1]=true;
csig_set[var2]=true;
}
}
#if VDEBUG
for(unsigned i=0;i<csig->size();i++){
ASS_REP(csig_set[i],c->toString());
}
#endif
_clauseVariableSorts.insert(c,csig);
}
}
}
void FiniteModelBuilder::addGroundClauses()
{
if(!_groundClauses) return;
ClauseList::Iterator cit(_groundClauses);
static const DArray<unsigned> emptyGrounding(0);
while(cit.hasNext()){
Clause* c = cit.next();
ASS(c);
#if VTRACE_FMB
cout << "Ground clause " << c->toString() << endl;
#endif
static SATLiteralStack satClauseLits;
satClauseLits.reset();
for(unsigned i=0;i<c->length();i++){
unsigned f = (*c)[i]->functor();
SATLiteral slit = getSATLiteral(f,emptyGrounding,(*c)[i]->polarity(),false);
satClauseLits.push(slit);
}
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
}
}
unsigned FiniteModelBuilder::estimateInstanceCount()
{
unsigned res = 0;
ClauseList::Iterator cit(_clauses);
while(cit.hasNext()){
unsigned instances = 1;
Clause* c = cit.next();
unsigned vars = c->varCnt();
const DArray<unsigned>* varSorts = _clauseVariableSorts.get(c) ;
if(!varSorts){
continue;
}
for(unsigned var=0;var<vars;var++){
unsigned srt = (*varSorts)[var];
instances *= min(_distinctSortSizes[_sortedSignature->parents[srt]],_sortedSignature->sortBounds[srt]);
}
res += instances;
}
return res;
}
void FiniteModelBuilder::addNewInstances()
{
ClauseList::Iterator cit(_clauses);
while(cit.hasNext()){
Clause* c = cit.next();
ASS(c);
#if VTRACE_FMB
cout << "Instances of " << c->toString() << endl;
#endif
unsigned vars = c->varCnt();
const DArray<unsigned>* varSorts = _clauseVariableSorts.get(c) ;
static DArray<unsigned> maxVarSize;
maxVarSize.ensure(vars);
if(!varSorts){
continue;
}
ASS(varSorts);
static ArrayMap<unsigned> varDistinctSortsMaxes(_distinctSortSizes.size());
if (!_xmass) {
varDistinctSortsMaxes.reset();
}
for(unsigned var=0;var<vars;var++) {
unsigned srt = (*varSorts)[var];
maxVarSize[var] = min(_sortModelSizes[srt],_sortedSignature->sortBounds[srt]);
if (!_xmass) {
unsigned dsort = _sortedSignature->parents[srt];
if (!_sortedSignature->monotonicSorts[dsort]) { varDistinctSortsMaxes.set(dsort,1);
}
}
}
static DArray<unsigned> grounding;
grounding.ensure(vars);
for(unsigned i=0;i<vars;i++) grounding[i]=1;
grounding[vars-1]=0;
instanceLabel:
for(unsigned var=vars-1;var+1!=0;var--){
if(grounding[var]==maxVarSize[var]){
grounding[var]=1;
}
else{
grounding[var]++;
static SATLiteralStack satClauseLits;
satClauseLits.reset();
if (_xmass) {
varDistinctSortsMaxes.reset();
for(unsigned var=0;var<vars;var++) {
unsigned srt = (*varSorts)[var];
unsigned dsr = _sortedSignature->parents[srt];
if (_sortedSignature->monotonicSorts[dsr]) {
continue;
}
unsigned prev = varDistinctSortsMaxes.get(dsr,0);
unsigned cur = grounding[var];
varDistinctSortsMaxes.set(dsr,max(cur,prev));
}
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
unsigned val = varDistinctSortsMaxes.get(i,0);
if (val > 1) {
satClauseLits.push(SATLiteral(marker_offsets[i]+val-2,0));
}
}
} else {
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
if (varDistinctSortsMaxes.get(i,0)) {
satClauseLits.push(SATLiteral(instancesMarker_offset+i,0));
}
}
}
for(unsigned lindex=0;lindex<c->length();lindex++){
Literal* lit = (*c)[lindex];
if(lit->isTwoVarEquality()){
bool equal = grounding[lit->nthArgument(0)->var()] == grounding[lit->nthArgument(1)->var()];
if((lit->isPositive() && equal) || (!lit->isPositive() && !equal)){
goto instanceLabel;
}
if((lit->isPositive() && !equal) || (!lit->isPositive() && equal)){
continue;
}
}
if(lit->isEquality()){
ASS(lit->nthArgument(0)->isTerm());
ASS(lit->nthArgument(1)->isVar());
Term* t = lit->nthArgument(0)->term();
unsigned functor = t->functor();
unsigned arity = t->arity();
static DArray<unsigned> use;
use.ensure(arity+1);
for(unsigned j=0;j<arity;j++){
ASS(t->nthArgument(j)->isVar());
use[j] = grounding[t->nthArgument(j)->var()];
}
use[arity]=grounding[lit->nthArgument(1)->var()];
satClauseLits.push(getSATLiteral(functor,use,lit->polarity(),true));
}else{
unsigned functor = lit->functor();
unsigned arity = lit->arity();
static DArray<unsigned> use;
use.ensure(arity);
for(unsigned j=0;j<arity;j++){
ASS(lit->nthArgument(j)->isVar());
use[j] = grounding[lit->nthArgument(j)->var()];
}
satClauseLits.push(getSATLiteral(functor,use,lit->polarity(),false));
}
}
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
goto instanceLabel;
}
}
}
}
unsigned FiniteModelBuilder::estimateFunctionalDefCount()
{
unsigned res = 0;
for(unsigned f=0;f<env.signature->functions();f++){
unsigned instances = 1;
if(del_f[f]) continue;
unsigned arity = env.signature->functionArity(f);
const DArray<unsigned>& f_signature = _sortedSignature->functionSignatures[f];
unsigned returnSrt = f_signature[arity];
instances *= min(_sortedSignature->sortBounds[returnSrt],_distinctSortSizes[_sortedSignature->parents[returnSrt]]);
instances *= min(_sortedSignature->sortBounds[returnSrt],_distinctSortSizes[_sortedSignature->parents[returnSrt]]);
for(unsigned var=2;var<arity+2;var++){
unsigned srt = f_signature[var-2]; instances *= min(_sortedSignature->sortBounds[srt],_distinctSortSizes[_sortedSignature->parents[srt]]);
}
res += instances / 2;
}
return res;
}
void FiniteModelBuilder::addNewFunctionalDefs()
{
for(unsigned f=0;f<env.signature->functions();f++){
if(del_f[f]) continue;
unsigned arity = env.signature->functionArity(f);
#if VTRACE_FMB
cout << "Adding func defs for " << env.signature->functionName(f) << endl;
#endif
const DArray<unsigned>& f_signature = _sortedSignature->functionSignatures[f];
static DArray<unsigned> maxVarSize;
maxVarSize.ensure(arity+2);
unsigned returnSrt = f_signature[arity];
maxVarSize[0] = maxVarSize[1] = min(_sortedSignature->sortBounds[returnSrt],_sortModelSizes[returnSrt]);
for(unsigned var=2;var<arity+2;var++){
unsigned srt = f_signature[var-2]; maxVarSize[var] = min(_sortedSignature->sortBounds[srt],_sortModelSizes[srt]);
}
static DArray<unsigned> grounding;
grounding.ensure(arity+2);
for(unsigned var=0;var<arity+2;var++){ grounding[var]=1; }
grounding[arity+1]=0;
newFuncLabel:
for(unsigned var=arity+1;var+1!=0;var--){
if(grounding[var]==maxVarSize[var]){
grounding[var]=1;
}
else{
grounding[var]++;
if(grounding[0]>=grounding[1]){
goto newFuncLabel;
}
static SATLiteralStack satClauseLits;
satClauseLits.reset();
static DArray<unsigned> use;
use.ensure(arity+1);
for(unsigned k=0;k<arity;k++) use[k]=grounding[k+2];
use[arity]=grounding[0];
satClauseLits.push(getSATLiteral(f,use,false,true));
use[arity]=grounding[1];
satClauseLits.push(getSATLiteral(f,use,false,true));
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
goto newFuncLabel;
}
}
}
}
void FiniteModelBuilder::addNewSymmetryOrderingAxioms(unsigned size,
Stack<GroundedTerm>& groundedTerms)
{
if(groundedTerms.length() < size) return;
GroundedTerm gt = groundedTerms[size-1];
unsigned arity = env.signature->functionArity(gt.f);
static DArray<unsigned> grounding;
grounding.ensure(arity+1);
for(unsigned i=0;i<arity;i++) grounding[i] = gt.grounding[i];
static SATLiteralStack satClauseLits;
satClauseLits.reset();
for(unsigned i=1;i<=size;i++){
grounding[arity]=i;
SATLiteral sl = getSATLiteral(gt.f,grounding,true,true);
satClauseLits.push(sl);
}
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
}
void FiniteModelBuilder::addNewSymmetryCanonicityAxioms(unsigned size,
Stack<GroundedTerm>& groundedTerms,
unsigned maxSize)
{
if(size<=1) return;
unsigned w = _symmetryRatio * maxSize;
if(w > groundedTerms.length()){
w = groundedTerms.length();
}
for(unsigned i=1;i<w;i++){
static SATLiteralStack satClauseLits;
satClauseLits.reset();
GroundedTerm gti = groundedTerms[i];
unsigned arityi = env.signature->functionArity(gti.f);
if(arityi>0) return;
static DArray<unsigned> grounding_i;
grounding_i.ensure(arityi+1);
for(unsigned a=0;a<arityi;a++){ grounding_i[a]=gti.grounding[a];}
grounding_i[arityi]=size;
satClauseLits.push(getSATLiteral(gti.f,grounding_i,false,true));
for(unsigned j=0;j<i;j++){
GroundedTerm gtj = groundedTerms[j];
unsigned arityj = env.signature->functionArity(gtj.f);
static DArray<unsigned> grounding_j;
grounding_j.ensure(arityj+1);
for(unsigned a=0;a<arityj;a++){ grounding_j[a]=gtj.grounding[a];}
grounding_j[arityj]=size-1;
satClauseLits.push(getSATLiteral(gtj.f,grounding_j,true,true));
}
addSATClause(SATClause::fromStack(satClauseLits));
}
}
void FiniteModelBuilder::addUseModelSize(unsigned size)
{
return;
}
void FiniteModelBuilder::addNewTotalityDefs()
{
if (_xmass) {
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
for (unsigned j = 0; j < _distinctSortSizes[i]-1; j++) {
static SATLiteralStack satClauseLits;
satClauseLits.reset();
satClauseLits.push(SATLiteral(marker_offsets[i]+j,1));
satClauseLits.push(SATLiteral(marker_offsets[i]+j+1,0));
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
}
}
}
for(unsigned f=0;f<env.signature->functions();f++){
if(del_f[f]) continue;
unsigned arity = env.signature->functionArity(f);
#if VTRACE_FMB
cout << "Adding total defs for " << env.signature->functionName(f) << endl;
#endif
const DArray<unsigned>& f_signature = _sortedSignature->functionSignatures[f];
if(arity==0){
unsigned srt = f_signature[0];
unsigned dsrt = _sortedSignature->parents[srt];
unsigned maxSize = min(_sortedSignature->sortBounds[srt],_sortModelSizes[srt]);
for (unsigned i = (!_xmass || (_sortedSignature->monotonicSorts[dsrt])) ? maxSize : 1; i <= maxSize; i++) { static SATLiteralStack satClauseLits;
satClauseLits.reset();
for(unsigned constant=1;constant<=i;constant++){
static DArray<unsigned> use(1);
use[0]=constant;
SATLiteral slit = getSATLiteral(f,use,true,true);
satClauseLits.push(slit);
}
if (_xmass) {
unsigned marker_idx = (i == maxSize) ? _distinctSortSizes[dsrt]-1 : i-1; satClauseLits.push(SATLiteral(marker_offsets[dsrt] + marker_idx,1));
} else {
satClauseLits.push(SATLiteral(totalityMarker_offset+dsrt,0));
}
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
}
continue;
}
static DArray<unsigned> maxVarSize;
maxVarSize.ensure(arity);
for(unsigned var=0;var<arity;var++){
unsigned srt = f_signature[var];
maxVarSize[var] = min(_sortedSignature->sortBounds[srt],_sortModelSizes[srt]);
}
unsigned retSrt = f_signature[arity];
unsigned dRetSrt = _sortedSignature->parents[retSrt];
unsigned maxRtSrtSize = min(_sortedSignature->sortBounds[retSrt],_sortModelSizes[retSrt]);
static DArray<unsigned> grounding;
grounding.ensure(arity);
for(unsigned var=0;var<arity;var++){ grounding[var]=1; }
grounding[arity-1]=0;
newTotalLabel:
for(unsigned var=arity-1;var+1!=0;var--){
if(grounding[var]==maxVarSize[var]){
grounding[var]=1;
}
else{
grounding[var]++;
for (unsigned i = (!_xmass || (_sortedSignature->monotonicSorts[dRetSrt])) ? maxRtSrtSize : 1; i <= maxRtSrtSize; i++) {
static SATLiteralStack satClauseLits;
satClauseLits.reset();
for(unsigned constant=1;constant<=i;constant++) {
static DArray<unsigned> use;
use.ensure(arity+1);
for(unsigned k=0;k<arity;k++) use[k]=grounding[k];
use[arity]=constant;
satClauseLits.push(getSATLiteral(f,use,true,true));
}
if (_xmass) {
unsigned marker_idx = (i == maxRtSrtSize) ? _distinctSortSizes[dRetSrt]-1 : i-1; satClauseLits.push(SATLiteral(SATLiteral(marker_offsets[dRetSrt]+marker_idx,1)));
} else {
satClauseLits.push(SATLiteral(totalityMarker_offset+dRetSrt,0));
}
SATClause* satCl = SATClause::fromStack(satClauseLits);
addSATClause(satCl);
}
goto newTotalLabel;
}
}
}
}
SATLiteral FiniteModelBuilder::getSATLiteral(unsigned f, const DArray<unsigned>& grounding,
bool polarity,bool isFunction)
{
ASS(f>0 || isFunction);
DEBUG_CODE(
unsigned arity = isFunction ? env.signature->functionArity(f) : env.signature->predicateArity(f)
);
ASS((isFunction && arity==grounding.size()-1) || (!isFunction && arity==grounding.size()));
unsigned offset = isFunction ? f_offsets[f] : p_offsets[f];
DArray<unsigned>& signature = isFunction ?
_sortedSignature->functionSignatures[f] :
_sortedSignature->predicateSignatures[f];
unsigned var = offset;
unsigned mult=1;
for(unsigned i=0;i<grounding.size();i++){
var += mult*(grounding[i]-1);
unsigned srt = signature[i];
mult *= _sortModelSizes[srt];
}
return SATLiteral(var,polarity);
}
void FiniteModelBuilder::addSATClause(SATClause* cl)
{
cl = SATClause::removeDuplicateLiterals(cl);
if(!cl){ return; }
#if VTRACE_FMB
cout << "ADDING " << cl->toString() << endl; #endif
_clausesToBeAdded.push(cl);
}
MainLoopResult FiniteModelBuilder::runImpl()
{
if(!_isAppropriate){
return MainLoopResult(TerminationReason::INAPPROPRIATE);
}
if(!_prb.units()){
return MainLoopResult(TerminationReason::SATISFIABLE);
}
env.statistics->phase = ExecutionPhase::FMB_CONSTRAINT_GEN;
if(outputAllowed()){
bool doPrinting = false;
#if VTRACE_FMB
doPrinting = true;
#endif
std::string min_res = "[";
std::string max_res = "[";
for(unsigned s=0;s<_sortedSignature->distinctSorts;s++){
if(_distinctSortMaxs[s]==UINT_MAX){
max_res+="max";
}else{
max_res+=Lib::Int::toString(_distinctSortMaxs[s]);
doPrinting=true;
}
if(_distinctSortMins[s]!=1){ doPrinting=true;}
min_res+=Lib::Int::toString(_distinctSortMins[s]);
if(s+1 < _sortedSignature->distinctSorts){ max_res+=","; min_res+=",";}
}
if(doPrinting){
cout << "% Detected minimum model sizes of " << min_res << "]" << endl;
cout << "% Detected maximum model sizes of " << max_res << "]" << endl;
}
}
_sortModelSizes.ensure(_sortedSignature->sorts);
_distinctSortSizes.ensure(_sortedSignature->distinctSorts);
for(unsigned i=0;i<_distinctSortSizes.size();i++){
_distinctSortSizes[i]=max(_startModelSize,_distinctSortMins[i]);
if (_startModelSize > _distinctSortMaxs[i]) {
if(outputAllowed()){
cout << "% fmb_start_size (= " << _startModelSize << ") larger than a detected sort maximum size!" << endl;
}
return MainLoopResult(TerminationReason::REFUTATION_NOT_FOUND);
}
}
for(unsigned s=0;s<_sortedSignature->sorts;s++) {
_sortModelSizes[s] = _distinctSortSizes[_sortedSignature->parents[s]];
}
if (!_xmass) {
if (!_dsaEnumerator->init(_startModelSize,_distinctSortSizes,_distinct_sort_constraints,_strict_distinct_sort_constraints)) {
goto gave_up;
}
}
if (reset()) {
while(true){
if(outputAllowed()) {
cout << "% TRYING " << "[";
for(unsigned i=0;i<_distinctSortSizes.size();i++){
cout << _distinctSortSizes[i];
if(i+1 < _distinctSortSizes.size()) cout << ",";
}
cout << "]" << endl;
}
{
TIME_TRACE("fmb constraint creation");
#if VTRACE_FMB
cout << "GROUND" << endl;
#endif
addGroundClauses();
#if VTRACE_FMB
cout << "INSTANCES" << endl;
#endif
addNewInstances();
#if VTRACE_FMB
cout << "FUNC DEFS" << endl;
#endif
addNewFunctionalDefs();
#if VTRACE_FMB
cout << "SYM DEFS" << endl;
#endif
addNewSymmetryAxioms();
#if VTRACE_FMB
cout << "TOTAL DEFS" << endl;
#endif
addNewTotalityDefs();
}
#if VTRACE_FMB
cout << "SOLVING" << endl;
#endif
Status satResult = Status::UNKNOWN;
{
if (_opt.randomTraversals()) {
TIME_TRACE(TimeTrace::SHUFFLING);
Shuffling::shuffleArray(_clausesToBeAdded,_clausesToBeAdded.size());
}
TIME_TRACE("fmb sat solving");
_solver->addClausesIter(pvi(SATClauseStack::ConstIterator(_clausesToBeAdded)));
env.statistics->phase = ExecutionPhase::FMB_SOLVING;
static SATLiteralStack assumptions(_distinctSortSizes.size());
assumptions.reset();
if (_xmass) {
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
assumptions.push(SATLiteral(marker_offsets[i]+_distinctSortSizes[i]-1,0));
}
} else {
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
assumptions.push(SATLiteral(totalityMarker_offset+i,1));
}
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
assumptions.push(SATLiteral(instancesMarker_offset+i,1));
}
}
if (_opt.randomTraversals()) {
_solver->randomizeForNextAssignment(_curMaxVar);
}
satResult = _solver->solveUnderAssumptions(assumptions);
env.statistics->phase = ExecutionPhase::FMB_CONSTRAINT_GEN;
}
if(satResult == Status::SATISFIABLE){
if (_xmass) {
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
unsigned j = 0;
for (; j < _distinctSortSizes[i]; j++) {
if (_solver->trueInAssignment(SATLiteral(marker_offsets[i]+j,0))) {
break;
}
}
ASS_L(j,_distinctSortSizes[i]);
#if VTRACE_DOMAINS
cout << "dom " << i << " has final size " << (j+1) << endl;
#endif
_distinctSortSizes[i] = j+1;
}
}
onModelFound();
return MainLoopResult(TerminationReason::SATISFIABLE);
}
unsigned clauseSetSize = _clausesToBeAdded.size();
unsigned weight = clauseSetSize;
SATClauseStack::Iterator it(_clausesToBeAdded);
while (it.hasNext()) {
it.next()->destroy();
}
_clausesToBeAdded.reset();
{
SATLiteralStack failed = _solver->failedAssumptions();
if (_xmass) {
unsigned domToGrow = UINT_MAX;
unsigned domsWeight = UINT_MAX;
static unsigned alternator = 0;
alternator++;
for (unsigned i = 0; i < failed.size(); i++) {
unsigned var = failed[i].var();
unsigned srt = which_sort(var);
if (_distinctSortSizes[srt] == _distinctSortMaxs[srt]) {
continue;
}
unsigned weight = 0;
if (alternator % (_sizeWeightRatio+1) != 0) {
_distinctSortSizes[srt]++;
weight = estimateInstanceCount();
_distinctSortSizes[srt]--;
} else {
weight = _distinctSortSizes[srt];
}
#if VTRACE_DOMAINS
cout << "dom "<<srt<<" of weight "<< weight << " could grow." << endl;
#endif
if (weight < domsWeight) {
domToGrow = srt;
domsWeight = weight;
}
}
if (domsWeight < UINT_MAX) {
ASS_L(domToGrow,UINT_MAX);
#if VTRACE_DOMAINS
cout << "chosen "<<domToGrow<< " of weight " << domsWeight << endl;
#endif
_distinctSortSizes[domToGrow]++;
{ bool updated;
do {
updated = false;
Stack<std::pair<unsigned,unsigned>>::Iterator it1(_distinct_sort_constraints);
while (it1.hasNext()) {
std::pair<unsigned,unsigned> constr = it1.next();
if (_distinctSortSizes[constr.first] < _distinctSortSizes[constr.second]) {
_distinctSortSizes[constr.first] = _distinctSortSizes[constr.second];
updated = true;
}
}
Stack<std::pair<unsigned,unsigned>>::Iterator it2(_strict_distinct_sort_constraints);
while (it1.hasNext()) {
std::pair<unsigned,unsigned> constr = it1.next();
if (_distinctSortSizes[constr.first] <= _distinctSortSizes[constr.second]) {
_distinctSortSizes[constr.first] = _distinctSortSizes[constr.second]+1;
updated = true;
}
}
} while (updated);
}
for(unsigned s=0;s<_sortedSignature->sorts;s++) {
_sortModelSizes[s] = _distinctSortSizes[_sortedSignature->parents[s]];
}
} else {
if (_startModelSize <= 1) {
return MainLoopResult(TerminationReason::REFUTATION,
Clause::empty(NonspecificInferenceMany(InferenceRule::MODEL_NOT_FOUND,_prb.units())));
} else {
if(outputAllowed()) {
addCommentSignForSZS(cout);
cout << "Cannot enumerate next child to try in an incomplete setup" <<endl;
}
goto gave_up;
}
}
} else { static Constraint_Generator_Vals nogood;
nogood.ensure(_distinctSortSizes.size());
for (unsigned i = 0; i < _distinctSortSizes.size(); i++) {
nogood[i] = make_pair(STAR,_distinctSortSizes[i]);
}
for (unsigned i = 0; i < failed.size(); i++) {
unsigned var = failed[i].var();
ASS_GE(var,totalityMarker_offset);
if (var < instancesMarker_offset) { unsigned dsort = var-totalityMarker_offset;
if (_sortedSignature->monotonicSorts[dsort]) {
nogood[dsort].first = LEQ;
} else {
nogood[dsort].first = EQ;
}
} else if (nogood[var-instancesMarker_offset].first == STAR) { ASS(!_sortedSignature->monotonicSorts[var-instancesMarker_offset]);
nogood[var-instancesMarker_offset].first = GEQ;
}
}
#if VTRACE_DOMAINS
cout << "Learned a nogood: ";
output_cg(nogood);
cout << " of weight " << weight << endl;
#endif
_dsaEnumerator->learnNogood(nogood,weight);
if (!_dsaEnumerator->increaseModelSizes(_distinctSortSizes,_distinctSortMaxs)) {
if (_dsaEnumerator->isFmbComplete(_distinctSortSizes.size())) {
return MainLoopResult(TerminationReason::REFUTATION,
Clause::empty(NonspecificInferenceMany(InferenceRule::MODEL_NOT_FOUND,_prb.units())));
} else {
if(outputAllowed()) {
addCommentSignForSZS(cout);
cout << "Cannot enumerate next child to try in an incomplete setup" <<endl;
}
goto gave_up;
}
}
for(unsigned s=0;s<_sortedSignature->sorts;s++) {
_sortModelSizes[s] = _distinctSortSizes[_sortedSignature->parents[s]];
}
}
}
if(!reset()){
break;
}
}
}
if(outputAllowed()){
addCommentSignForSZS(cout);
cout << "Cannot represent all propositional literals internally" <<endl;
}
gave_up:
return MainLoopResult(TerminationReason::REFUTATION_NOT_FOUND);
}
void FiniteModelBuilder::onModelFound()
{
if(_opt.proof()==Options::Proof::OFF){
return;
}
Timer::disableLimitEnforcement();
reportSpiderStatus('-');
if(outputAllowed()){
cout << "% Finite Model Found!" << endl;
}
if(szsOutputMode()) {
std::cout << "% SZS status "<<( UIHelper::haveConjecture() ? "CounterSatisfiable" : "Satisfiable" )
<< " for " << _opt.problemName() << endl << flush;
UIHelper::satisfiableStatusWasAlreadyOutput = true;
}
DArray<unsigned> vampireSortSizes;
vampireSortSizes.ensure(env.signature->typeCons());
for(unsigned vSort=0;vSort<env.signature->typeCons();vSort++){
unsigned size = 1;
if(env.signature->isInterpretedNonDefault(vSort) && !env.signature->isBoolCon(vSort)){ size=0;}
unsigned dsort;
if(_sortedSignature->vampireToDistinctParent.find(vSort,dsort)){
size = _distinctSortSizes[dsort];
}
vampireSortSizes[vSort] = size;
}
FiniteModelMultiSorted model(vampireSortSizes.clone());
for(unsigned f=0;f<env.signature->functions();f++){
if(del_f[f]) continue;
Signature::Symbol* sym = env.signature->getFunction(f);
unsigned arity = env.signature->functionArity(f);
static DArray<unsigned> maxVarSizeBig;
maxVarSizeBig.ensure(arity);
OperatorType* tp = sym->fnType();
ASS_EQ(tp->numTypeArguments(),0) for(unsigned var=0;var<arity;var++){
unsigned vamp_srt = tp->arg(var).term()->functor();
maxVarSizeBig[var] = vampireSortSizes[vamp_srt];
}
static DArray<unsigned> args;
args.ensure(arity);
for(unsigned i=0;i<arity;i++){
args[i]=1;
}
static DArray<unsigned> maxVarSizeSml;
maxVarSizeSml.ensure(arity+1);
const DArray<unsigned>& f_signature = _sortedSignature->functionSignatures[f];
for(unsigned var=0;var<=arity;var++){
unsigned srt = f_signature[var];
maxVarSizeSml[var] = min(_sortedSignature->sortBounds[srt],_sortModelSizes[srt]);
}
static DArray<unsigned> grounding;
grounding.ensure(arity+1);
for(;;) {
DEBUG_CODE(bool found=false;)
for(unsigned c=1;c<=maxVarSizeSml[arity];c++){
for(unsigned i=0;i<arity;i++) {
grounding[i] = (args[i] <= maxVarSizeSml[i]) ? args[i] : 1;
}
grounding[arity]=c;
SATLiteral slit = getSATLiteral(f,grounding,true,true);
if(_solver->trueInAssignment(slit)){
ASS(!found);
DEBUG_CODE(found=true;)
model.addFunctionDefinition(f,args,c);
RELEASE_CODE(break;)
}
}
ASS(found)
unsigned i;
for(i=0;i<arity;i++) {
args[i]++;
if(args[i] <= maxVarSizeBig[i]){
break;
}
args[i]=1;
}
if (i == arity) {
break;
}
}
}
for(unsigned p=1;p<env.signature->predicates();p++){
if(del_p[p]) continue;
Signature::Symbol* sym = env.signature->getPredicate(p);
unsigned arity = env.signature->predicateArity(p);
static DArray<unsigned> maxVarSizeBig;
maxVarSizeBig.ensure(arity);
OperatorType* tp = sym->fnType();
ASS_EQ(tp->numTypeArguments(),0) for(unsigned var=0;var<arity;var++){
unsigned vamp_srt = tp->arg(var).term()->functor();
maxVarSizeBig[var] = vampireSortSizes[vamp_srt];
}
static DArray<unsigned> args;
args.ensure(arity);
for(unsigned i=0;i<arity;i++){
args[i]=1;
}
static DArray<unsigned> maxVarSizeSml;
maxVarSizeSml.ensure(arity);
const DArray<unsigned>& p_signature = _sortedSignature->predicateSignatures[p];
for(unsigned var=0;var<arity;var++){
unsigned srt = p_signature[var];
maxVarSizeSml[var] = min(_sortedSignature->sortBounds[srt],_sortModelSizes[srt]);
}
static DArray<unsigned> grounding;
grounding.ensure(arity);
static DArray<signed char> sort_extension_modes;
sort_extension_modes.ensure(arity);
for(unsigned i=0;i<arity;i++) {
unsigned vamp_srt = tp->arg(i).term()->functor();
DArray<signed char>* monot_info;
if (_monotonic_vampire_sorts.find(vamp_srt,monot_info)) {
sort_extension_modes[i] = (p<monot_info->size()) ? (*monot_info)[p] : 0;
} else {
sort_extension_modes[i] = 0;
}
}
for(;;) {
signed char extension_mode = 0; for(unsigned i=0;i<arity;i++) {
if (args[i] <= maxVarSizeSml[i]) {
grounding[i] = args[i];
} else {
grounding[i] = 1;
extension_mode = sort_extension_modes[i];
}
}
bool res;
if (extension_mode == 1) {
res = true;
} else if (extension_mode == -1) {
res = false;
} else {
SATLiteral slit = getSATLiteral(p,grounding,true,false);
res=_solver->trueInAssignment(slit);
}
model.addPredicateDefinition(p,args,res);
unsigned i;
for(i=0;i<arity;i++) {
args[i]++;
if(args[i] <= maxVarSizeBig[i]){
break;
}
args[i]=1;
}
if (i == arity) {
break;
}
}
}
model.eliminateSortFunctionsAndPredicates(_sortFunctions,_sortPredicates);
model.restoreEliminatedDefinitions(env.getMainProblem());
env.statistics->model = model.toString();
}
void FiniteModelBuilder::HackyDSAE::learnNogood(Constraint_Generator_Vals& nogood, unsigned weight)
{
Constraint_Generator* constraint_p = new Constraint_Generator(nogood,weight);
_constraints_generators.insert(constraint_p);
if (weight > _maxWeightSoFar) {
_maxWeightSoFar = weight;
}
}
bool FiniteModelBuilder::HackyDSAE::checkConstriant(DArray<unsigned>& newSortSizes, Constraint_Generator_Vals& constraint)
{
for (unsigned j = 0; j < newSortSizes.size(); j++) {
pair<ConstraintSign,unsigned>& cc = constraint[j];
if (cc.first == EQ && cc.second != newSortSizes[j]) {
return false;
}
if (cc.first == GEQ && cc.second > newSortSizes[j]) {
return false;
}
if (cc.first == LEQ && cc.second < newSortSizes[j]) {
return false;
}
}
#if VTRACE_DOMAINS
cout << " Ruled out by "; output_cg(constraint); cout << endl;
#endif
return true;
}
bool FiniteModelBuilder::HackyDSAE::increaseModelSizes(DArray<unsigned>& newSortSizes, DArray<unsigned>& sortMaxes)
{
while (!_constraints_generators.isEmpty()) {
Constraint_Generator* generator_p = _constraints_generators.top();
Constraint_Generator_Vals& generator = generator_p->_vals;
#if VTRACE_DOMAINS
cout << "Picking generator: ";
FiniteModelBuilder::output_cg(generator);
cout << endl;
#endif
for (unsigned i = 0; i< newSortSizes.size(); i++) {
newSortSizes[i] = generator[i].second;
}
for (unsigned i = 0; i< newSortSizes.size(); i++) {
newSortSizes[i] += 1;
if (newSortSizes[i] > sortMaxes[i]) {
goto next_candidate;
}
#if VTRACE_DOMAINS
cout << " Testing increment on " << i << endl;
#endif
{
auto it = _constraints_generators.iter();
while (it.hasNext()) {
if (checkConstriant(newSortSizes,it.next()->_vals)) {
goto next_candidate;
}
}
}
if (_keepOldGenerators ) {
for (unsigned n = 0; n < _old_generators.size(); n++) {
if (checkConstriant(newSortSizes,_old_generators[n]->_vals)) {
Constraint_Generator* gen_p = new Constraint_Generator(newSortSizes.size(), ++_maxWeightSoFar);
Constraint_Generator_Vals& gen = gen_p->_vals;
for (unsigned j = 0; j < newSortSizes.size(); j++) {
gen[j] = make_pair(EQ,newSortSizes[j]);
}
_constraints_generators.insert(gen_p);
goto next_candidate;
}
}
}
{
Stack<std::pair<unsigned,unsigned>>::Iterator it1(*_distinct_sort_constraints);
while (it1.hasNext()) {
std::pair<unsigned,unsigned> constr = it1.next();
if (newSortSizes[constr.first] < newSortSizes[constr.second]) {
#if VTRACE_DOMAINS
cout << " Ruled out by _distinct_sort_constraints " << constr.first << " >= " << constr.second << endl;
#endif
Constraint_Generator* gen_p = new Constraint_Generator(newSortSizes.size(), ++_maxWeightSoFar );
Constraint_Generator_Vals& gen = gen_p->_vals;
for (unsigned j = 0; j < newSortSizes.size(); j++) {
gen[j] = make_pair(STAR,newSortSizes[j]);
}
gen[constr.first].first = EQ;
gen[constr.second].first = GEQ;
_constraints_generators.insert(gen_p);
goto next_candidate;
}
}
Stack<std::pair<unsigned,unsigned>>::Iterator it2(*_strict_distinct_sort_constraints);
while (it2.hasNext()) {
std::pair<unsigned,unsigned> constr = it2.next();
if (newSortSizes[constr.first] <= newSortSizes[constr.second]) {
Constraint_Generator* gen_p = new Constraint_Generator(newSortSizes.size(), ++_maxWeightSoFar );
Constraint_Generator_Vals& gen = gen_p->_vals;
for (unsigned j = 0; j < newSortSizes.size(); j++) {
gen[j] = make_pair(STAR,newSortSizes[j]);
}
gen[constr.first].first = EQ;
gen[constr.second].first = GEQ;
_constraints_generators.insert(gen_p);
goto next_candidate;
}
}
}
return true;
next_candidate:
newSortSizes[i] -= 1;
}
if (_keepOldGenerators) {
_old_generators.push(_constraints_generators.pop()); } else {
delete _constraints_generators.pop();
#if VTRACE_DOMAINS
cout << "Deleted" << endl;
#endif
}
}
return false;
}
#if VZ3
bool FiniteModelBuilder::SmtBasedDSAE::init(unsigned _startModelSize, DArray<unsigned>& _distinctSortSizes,
Stack<std::pair<unsigned,unsigned>>& _distinct_sort_constraints, Stack<std::pair<unsigned,unsigned>>& _strict_distinct_sort_constraints)
{
_skippedSomeSizes = (_startModelSize > 1);
try {
z3::expr zero = _context.int_val(_startModelSize-1);
_sizeConstants.ensure(_distinctSortSizes.size());
for(unsigned i=0;i<_sizeConstants.size();i++) {
_sizeConstants[i] = new z3::expr(_context);
*_sizeConstants[i] = _context.int_const((std::string("s")+Int::toString(i)).c_str());
_smtSolver.add(*_sizeConstants[i] > zero);
}
_lastWeight = _distinctSortSizes.size()*_startModelSize;
Stack<std::pair<unsigned,unsigned>>::Iterator it1(_distinct_sort_constraints);
while (it1.hasNext()) {
std::pair<unsigned,unsigned> constr = it1.next();
_smtSolver.add(*_sizeConstants[constr.first] >= *_sizeConstants[constr.second]);
}
Stack<std::pair<unsigned,unsigned>>::Iterator it2(_strict_distinct_sort_constraints);
while (it2.hasNext()) {
std::pair<unsigned,unsigned> constr = it2.next();
_smtSolver.add(*_sizeConstants[constr.first] > *_sizeConstants[constr.second]);
}
if (_strict_distinct_sort_constraints.size() > 0) {
if (_smtSolver.check() == z3::check_result::unsat) {
if(outputAllowed()){
cout << "Problem does not have a finite model." <<endl;
}
return false;
}
}
} catch (std::bad_alloc& _) {
reportZ3OutOfMemory();
}
return true;
}
void FiniteModelBuilder::SmtBasedDSAE::learnNogood(Constraint_Generator_Vals& nogood, unsigned weight)
{
try {
z3::expr z3clause = _context.bool_val(false);
for (unsigned i = 0; i < nogood.size(); i++) {
switch(nogood[i].first) {
case EQ:
z3clause = z3clause || (*_sizeConstants[i] != _context.int_val(nogood[i].second));
break;
case LEQ:
z3clause = z3clause || (*_sizeConstants[i] > _context.int_val(nogood[i].second));
break;
case GEQ:
z3clause = z3clause || (*_sizeConstants[i] < _context.int_val(nogood[i].second));
break;
default:
;
}
}
_smtSolver.add(z3clause);
} catch (std::bad_alloc& _) {
reportZ3OutOfMemory();
}
}
unsigned FiniteModelBuilder::SmtBasedDSAE::loadSizesFromSmt(DArray<unsigned>& szs)
{
unsigned weight = 0;
z3::model model = _smtSolver.get_model();
for (unsigned i = 0; i < szs.size(); i++) {
int val;
Z3_get_numeral_int(_context,model.eval(*_sizeConstants[i]),&val);
szs[i] = (unsigned)val;
weight += val;
}
return weight;
}
void FiniteModelBuilder::SmtBasedDSAE::reportZ3OutOfMemory()
{
reportSpiderStatus('m');
std::cout << "Z3 ran out of memory" << endl;
if(env.statistics) {
env.statistics->print(std::cout);
}
Debug::Tracer::printStack();
System::terminateImmediately(1);
}
bool FiniteModelBuilder::SmtBasedDSAE::increaseModelSizes(DArray<unsigned>& newSortSizes, DArray<unsigned>& sortMaxes)
{
try {
TIME_TRACE("smt search for next domain size assignment");
z3::check_result result = _smtSolver.check();
if (result == z3::check_result::unsat) {
return false;
}
ASS_EQ(result,z3::check_result::sat);
unsigned weight = loadSizesFromSmt(newSortSizes);
if (weight == _lastWeight) {
return true;
}
while (true) {
_smtSolver.push();
z3::expr sum = _context.int_val(0);
for (unsigned i = 0; i < newSortSizes.size(); i++) {
sum = sum + *_sizeConstants[i];
}
_smtSolver.add(sum == _context.int_val(_lastWeight));
if (_smtSolver.check() == z3::check_result::sat) {
loadSizesFromSmt(newSortSizes);
_smtSolver.pop(1);
return true;
} else {
_smtSolver.pop(1);
_lastWeight++;
}
}
} catch (std::bad_alloc& _) {
reportZ3OutOfMemory();
}
return true; }
#endif
}