mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			338 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include "common.h"
 | |
| 
 | |
| class user_propagator_created_maximisation : public z3::user_propagator_base {
 | |
| 
 | |
| 
 | |
|     std::unordered_map<z3::expr, z3::expr_vector> argToFcts;
 | |
|     std::unordered_map<z3::expr, z3::expr_vector> fctToArgs;
 | |
| 
 | |
|     std::unordered_map<z3::expr, unsigned> currentModel;
 | |
|     z3::expr_vector fixedValues;
 | |
|     std::vector<unsigned> 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<z3::expr_vector> &conflicts, const z3::expr &fct, const z3::expr_vector &args, const std::vector<unsigned> &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<unsigned> &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<unsigned> 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<z3::expr_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<z3::expr_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<unsigned> 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<z3::expr_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<unsigned> 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<z3::expr_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<z3::expr_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));
 | |
|     }
 | |
| }; |