z3-z3-4.13.0.examples.userPropagator.user_propagator_created_maximisation.h Maven / Gradle / Ivy
The newest version!
#pragma once
#include "common.h"
class user_propagator_created_maximisation : public z3::user_propagator_base {
std::unordered_map argToFcts;
std::unordered_map fctToArgs;
std::unordered_map currentModel;
z3::expr_vector fixedValues;
std::vector fixedCnt;
user_propagator_created_maximisation* childPropagator = nullptr;
user_propagator_created_maximisation* parentPropagator = nullptr;
int board;
int nesting; // Just for logging (0 ... main solver; 1 ... sub-solver)
public:
user_propagator_created_maximisation(z3::context &c, user_propagator_created_maximisation* parentPropagator, unsigned board, int nesting) :
z3::user_propagator_base(c), fixedValues(c), parentPropagator(parentPropagator), board(board), nesting(nesting) {
this->register_fixed();
this->register_final();
this->register_created();
}
user_propagator_created_maximisation(z3::solver *s, unsigned board) :
z3::user_propagator_base(s), fixedValues(s->ctx()), board(board), nesting(0) {
this->register_fixed();
this->register_final();
this->register_created();
}
~user_propagator_created_maximisation() {
delete childPropagator;
}
void final() override {
WriteLine("Final (" + to_string(nesting) + ")");
}
void push() override {
WriteLine("Push (" + to_string(nesting) + ")");
fixedCnt.push_back((unsigned) fixedValues.size());
}
void pop(unsigned num_scopes) override {
WriteLine("Pop (" + to_string(nesting) + ")");
for (unsigned i = 0; i < num_scopes; i++) {
unsigned lastCnt = fixedCnt.back();
fixedCnt.pop_back();
for (auto j = fixedValues.size(); j > lastCnt; j--) {
currentModel.erase(fixedValues[j - 1]);
}
fixedValues.resize(lastCnt);
}
}
void checkValidPlacement(std::vector &conflicts, const z3::expr &fct, const z3::expr_vector &args, const std::vector &argValues, int pos) {
unsigned queenId = pos;
unsigned queenPos = argValues[pos];
z3::expr queenPosExpr = args[pos];
if (queenPos >= board) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicts.push_back(conflicting);
return;
}
for (unsigned otherId = 0; otherId < argValues.size(); otherId++) {
if (otherId == pos)
continue;
unsigned otherPos = argValues[otherId];
z3::expr otherPosExpr = args[otherId];
if (otherPos == (unsigned)-1)
continue; // We apparently do not have this value
if (queenPos == otherPos) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicting.push_back(otherPosExpr);
conflicts.push_back(conflicting);
}
int diffY = abs((int) queenId - (int) otherId);
int diffX = abs((int) queenPos - (int) otherPos);
if (diffX == diffY) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicting.push_back(otherPosExpr);
conflicts.push_back(conflicting);
}
}
}
unsigned getValues(const z3::expr &fct, std::vector &argValues) const {
z3::expr_vector args = fctToArgs.at(fct);
unsigned fixed = 0;
for (const z3::expr &arg: args) {
if (currentModel.contains(arg)) {
argValues.push_back(currentModel.at(arg));
fixed++;
}
else
argValues.push_back((unsigned) -1); // no value so far
}
return fixed;
}
user_propagator_base *fresh(z3::context &ctx) override {
WriteLine("Fresh context");
childPropagator = new user_propagator_created_maximisation(ctx, this, board, nesting + 1);
return childPropagator;
}
void fixed(const z3::expr &expr, const z3::expr &value) override {
// Could be optimized!
WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string());
unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint());
currentModel[expr] = v;
fixedValues.push_back(expr);
z3::expr_vector effectedFcts(ctx());
bool fixedFct = fctToArgs.contains(expr);
if (fixedFct) {
// fixed the value of a function
effectedFcts.push_back(expr);
}
else {
// fixed the value of a function's argument
effectedFcts = argToFcts.at(expr);
}
for (const z3::expr& fct : effectedFcts) {
if (!currentModel.contains(fct))
// we do not know yet whether to expect a valid or invalid placement
continue;
std::vector values;
unsigned fixedArgsCnt = getValues(fct, values);
bool fctValue = currentModel[fct];
z3::expr_vector args = fctToArgs.at(fct);
if (!fctValue) {
// expect invalid placement ...
if (fixedArgsCnt != board)
// we expect an invalid placement, but not all queen positions have been placed yet
return;
std::vector conflicts;
for (unsigned i = 0; i < args.size(); i++) {
if (values[i] != (unsigned)-1)
checkValidPlacement(conflicts, expr, args, values, i);
}
if (conflicts.empty()) {
// ... but we got a valid one
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
for (const z3::expr &arg: args) {
if (!arg.is_numeral())
conflicting.push_back(arg);
}
this->conflict(conflicting);
}
else {
// ... and everything is fine; we have at least one conflict
}
}
else {
// expect valid placement ...
std::vector conflicts;
if (fixedFct){
for (unsigned i = 0; i < args.size(); i++) {
if (values[i] != (unsigned)-1) // check all set queens
checkValidPlacement(conflicts, expr, args, values, i);
}
}
else {
for (unsigned i = 0; i < args.size(); i++) {
if (z3::eq(args[i], expr)) // only check newly fixed values
checkValidPlacement(conflicts, fct, args, values, i);
}
}
if (conflicts.size() > 0) {
// ... but we got an invalid one
for (const z3::expr_vector &conflicting: conflicts)
this->conflict(conflicting);
}
else {
// ... and everything is fine; no conflict
}
}
}
}
// void fixed(const z3::expr &expr, const z3::expr &value) override {
// WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string());
// unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint());
// currentModel[expr] = v;
// fixedValues.push_back(expr);
//
// if (fctToArgs.contains(expr)) {
// // fixed the value of a function
//
// std::vector values;
// unsigned fixedArgsCnt = getValues(expr, values);
//
// if (!v && fixedArgsCnt != board)
// // we expect an invalid placement, but not all queen positions have been placed yet
// return;
//
// z3::expr_vector args = fctToArgs.at(expr);
//
// std::vector conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (values[i] != (unsigned)-1)
// checkValidPlacement(conflicts, expr, args, values, i);
// }
// if (v) {
// //we expected a valid queen placement
// if (conflicts.size() > 0) {
// // ... but we got an invalid one
// for (const z3::expr_vector &conflicting: conflicts)
// this->conflict(conflicting);
// }
// else {
// // everything fine; no conflict
// }
// }
// else {
// // we expect an invalid queen placement
// if (conflicts.empty()) {
// // ... but we got a valid one
// z3::expr_vector conflicting(ctx());
// conflicting.push_back(expr);
// for (const z3::expr &arg: args) {
// if (!arg.is_numeral())
// conflicting.push_back(arg);
// }
// this->conflict(conflicting);
// }
// else {
// // everything fine; we have at least one conflict
// }
// }
// }
// else {
// // fixed the value of a function argument
//
// z3::expr_vector effectedFcts = argToFcts.at(expr);
//
// for (const z3::expr& fct : effectedFcts) {
// if (!currentModel.contains(fct))
// // we do not know yet whether to expect a valid or invalid placement
// continue;
//
// std::vector values;
// unsigned fixedArgsCnt = getValues(fct, values);
// bool fctValue = currentModel[fct];
// z3::expr_vector args = fctToArgs.at(fct);
//
// if (!fctValue) {
// // expect invalid placement
// if (fixedArgsCnt != board)
// // we expect an invalid placement, but not all queen positions have been placed yet
// return;
// std::vector conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (values[i] != (unsigned)-1)
// checkValidPlacement(conflicts, expr, args, values, i);
// }
//
// if (conflicts.empty()) {
// // ... but we got a valid one
// z3::expr_vector conflicting(ctx());
// conflicting.push_back(fct);
// for (const z3::expr &arg: args) {
// if (!arg.is_numeral())
// conflicting.push_back(arg);
// }
// this->conflict(conflicting);
// }
// else {
// // everything fine; we have at least one conflict
// }
// }
// else {
// // expect valid placement
// std::vector conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (z3::eq(args[i], expr)) // only check newly fixed values
// checkValidPlacement(conflicts, fct, args, values, i);
// }
// if (conflicts.size() > 0) {
// // ... but we got an invalid one
// for (const z3::expr_vector &conflicting: conflicts)
// this->conflict(conflicting);
// }
// else {
// // everything fine; no conflict
// }
// }
// }
// }
// }
void created(const z3::expr &func) override {
WriteLine("Created (" + to_string(nesting) + "): " + func.to_string());
z3::expr_vector args = func.args();
for (unsigned i = 0; i < args.size(); i++) {
z3::expr arg = args[i];
if (!arg.is_numeral()) {
WriteLine("Registered " + arg.to_string());
this->add(arg);
}
else {
currentModel[arg] = arg.get_numeral_uint();
// Skip registering as argument is a fixed BV;
}
argToFcts.try_emplace(arg, ctx()).first->second.push_back(func);
}
fctToArgs.emplace(std::make_pair(func, args));
}
};