potassco / clasp

⚙️ A conflict-driven nogood learning answer set solver

Home Page:https://potassco.org/clasp/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Literals added during propagator initialization are invalid until a clause referring to them is introduced.

rkaminsk opened this issue · comments

The following code produces an error:

lit = init.add_literal()
print(init.assignment.is_true(lit))

When a clause is added before, then there is no error:

lit = init.add_literal()
init.add_clause([lit, -lit])
print(init.assignment.is_true(lit))

It would be cool if the assignment could handle not yet added literals gracefully. In principle, all it would have to do is pretend that the literal is unassigned without actually adding it to the solver.

Here is something that should work (but does not adjust the unit tests). I don't open a pull request because you know better about the fine details.

EDIT: Unlike in my first edit, it seems like the add_watch method does not have to be modified because it adds the watches at the end of initialization anyway. But the size function in the code below becomes more complicated. With this code, even the unit tests are still running.

diff --git a/src/clingo.cpp b/src/clingo.cpp
index ca3c3a6..fdab1b0 100644
--- a/src/clingo.cpp
+++ b/src/clingo.cpp
@@ -52,11 +52,15 @@ ClingoAssignment::ClingoAssignment(const Solver& s)
 
 ClingoAssignment::Value_t ClingoAssignment::value(Lit_t lit)  const {
        POTASSCO_REQUIRE(ClingoAssignment::hasLit(lit), "Invalid literal");
-       switch (solver_->value(decodeVar(lit))) {
-               default: return Value_t::Free;
-               case value_true:  return lit >= 0 ? Value_t::True  : Value_t::False;
-               case value_false: return lit >= 0 ? Value_t::False : Value_t::True;
+       uint32_t var = decodeVar(lit);
+       if (solver_->validVar(var)) {
+               switch (solver_->value(var)) {
+                       default: return Value_t::Free;
+                       case value_true:  return lit >= 0 ? Value_t::True  : Value_t::False;
+                       case value_false: return lit >= 0 ? Value_t::False : Value_t::True;
+               }
        }
+       return Value_t::Free;
 }
 uint32_t ClingoAssignment::level(Lit_t lit)  const {
        return ClingoAssignment::value(lit) != Potassco::Value_t::Free
@@ -75,13 +79,13 @@ uint32_t ClingoAssignment::trailBegin(uint32_t dl) const {
        POTASSCO_REQUIRE(dl <= solver_->decisionLevel(), "Invalid decision level");
        return dl != 0 ? solver_->levelStart(dl) + trailOffset : 0;
 }
-uint32_t ClingoAssignment::size()            const { return solver_->assignment().numVars(); }
-uint32_t ClingoAssignment::unassigned()      const { return solver_->assignment().free(); }
+uint32_t ClingoAssignment::size()            const { return std::max(solver_->numProblemVars(), solver_->numVars()) + trailOffset; }
+uint32_t ClingoAssignment::unassigned()      const { return size() - trailSize(); }
 bool     ClingoAssignment::hasConflict()     const { return solver_->hasConflict(); }
 uint32_t ClingoAssignment::level()           const { return solver_->decisionLevel(); }
 uint32_t ClingoAssignment::rootLevel()       const { return solver_->rootLevel(); }
-bool     ClingoAssignment::hasLit(Lit_t lit) const { return solver_->validVar(decodeVar(lit)); }
-bool     ClingoAssignment::isTotal()         const { return solver_->numFreeVars() == 0u; }
+bool     ClingoAssignment::hasLit(Lit_t lit) const { return decodeVar(lit) < size(); }
+bool     ClingoAssignment::isTotal()         const { return unassigned() == 0; }
 uint32_t ClingoAssignment::trailSize()       const { return static_cast<uint32_t>(solver_->trail().size() + trailOffset); }
 /////////////////////////////////////////////////////////////////////////////////////////
 // ClingoPropagator::Control

@rkaminsk
Thanks 👍 I basically applied your fix and only added another unit test.

Thanks back.