1 //
2 // Copyright (c) 2006-2017 Benjamin Kaufmann
3 //
4 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 // IN THE SOFTWARE.
23 //
24
25 #ifndef CLASP_LOGIC_PROGRAM_TYPES_H_INCLUDED
26 #define CLASP_LOGIC_PROGRAM_TYPES_H_INCLUDED
27 #ifdef _MSC_VER
28 #pragma once
29 #endif
30 /*!
31 * \file
32 * \brief Basic types for working with a logic program.
33 */
34 #include <clasp/claspfwd.h>
35 #include <clasp/literal.h>
36 #include <potassco/rule_utils.h>
37 #include <functional>
38 namespace Potassco {
39 typedef Clasp::PodVector<Lit_t>::type LitVec;
40 typedef Clasp::PodVector<WeightLit_t>::type WLitVec;
41 }
42 namespace Clasp {
43 class ClauseCreator;
44 using Potassco::idMax;
45 namespace Asp {
46 typedef PodVector<PrgAtom*>::type AtomList;
47 typedef PodVector<PrgBody*>::type BodyList;
48 typedef PodVector<PrgDisj*>::type DisjList;
49 const ValueRep value_weak_true = 3; /**< true but no proof */
50 using Potassco::Atom_t;
51 using Potassco::Id_t;
52 /*!
53 * \addtogroup asp
54 */
55 //@{
56 //! A node of a program-dependency graph.
57 /*!
58 * A node represents a relevant part in a logic program. Each node
59 * has at least a literal and a value.
60 */
61 class PrgNode {
62 public:
63 //! Supported node types.
64 enum Type { Atom = 0u, Body = 1u, Disj = 2u };
65 static const uint32 noScc = (1u << 27)-1;
66 static const uint32 noNode = (1u << 28)-1;
67 static const uint32 noLit = 1;
68 //! Creates a new node that corresponds to a literal that is false.
69 explicit PrgNode(uint32 id, bool checkScc = true);
70 //! Is the node still relevant or removed() resp. eq()?
relevant()71 bool relevant() const { return eq_ == 0; }
72 //! Was the node removed?
removed()73 bool removed() const { return eq_ != 0 && id_ == noNode; }
74 //! Ignore the node during scc checking?
ignoreScc()75 bool ignoreScc()const { return noScc_ != 0; }
76 //! Returns true if this node is equivalent to some other node.
77 /*!
78 * If eq() is true, the node is no longer relevant and must not be used any further.
79 * The only sensible operation is to call id() in order to get the id of the node
80 * that is equivalent to this node.
81 */
eq()82 bool eq() const { return eq_ != 0 && id_ != noNode; }
seen()83 bool seen() const { return seen_ != 0; }
84 //! Returns true if node has an associated variable in a solver.
hasVar()85 bool hasVar() const { return litId_ != noLit; }
86 //! Returns the variable associated with this node or sentVar if no var is associated with this node.
var()87 Var var() const { return litId_ >> 1; }
88 //! Returns the literal associated with this node or a sentinel literal if no var is associated with this node.
literal()89 Literal literal() const { return Literal::fromId(litId_); }
90 //! Returns the value currently assigned to this node.
value()91 ValueRep value() const { return val_; }
92 //! Returns the current id of this node.
id()93 uint32 id() const { return id_; }
94 //! Returns the literal that must be true in order to fulfill the truth-value of this node.
trueLit()95 Literal trueLit() const {
96 return value() == value_free
97 ? lit_true()
98 : literal() ^ (value() == value_false);
99 }
100
101 /*!
102 * \name implementation functions
103 * Low-level implementation functions. Use with care and only if you
104 * know what you are doing!
105 */
106 //@{
setLiteral(Literal x)107 void setLiteral(Literal x) { litId_ = x.id(); }
clearLiteral(bool clVal)108 void clearLiteral(bool clVal){ litId_ = noLit; if (clVal) val_ = value_free; }
setValue(ValueRep v)109 void setValue(ValueRep v) { val_ = v; }
setEq(uint32 eqId)110 void setEq(uint32 eqId) { id_ = eqId; eq_ = 1; seen_ = 1; }
setIgnoreScc(bool b)111 void setIgnoreScc(bool b) { noScc_ = (uint32)b; }
markRemoved()112 void markRemoved() { if (!eq()) setEq(noNode); }
setSeen(bool b)113 void setSeen(bool b) { seen_ = uint32(b); }
resetId(uint32 id,bool seen)114 void resetId(uint32 id, bool seen) {
115 id_ = id;
116 eq_ = 0;
117 seen_ = (uint32)seen;
118 }
assignValueImpl(ValueRep v,bool noWeak)119 bool assignValueImpl(ValueRep v, bool noWeak) {
120 if (v == value_weak_true && noWeak) { v = value_true; }
121 if (value() == value_free || v == value() || (value() == value_weak_true && v == value_true)) {
122 setValue(v);
123 return true;
124 }
125 return v == value_weak_true && value() == value_true;
126 }
127 //@}
128 protected:
129 uint32 litId_ : 31; // literal-id in solver
130 uint32 noScc_ : 1; // ignore during scc checks?
131 uint32 id_ : 28; // own id/eq-id/root-id/ufs-id
132 uint32 val_ : 2; // assigned value
133 uint32 eq_ : 1; // removed or eq to some other node?
134 uint32 seen_ : 1; // marked as seen?
135 private:
136 PrgNode(const PrgNode&);
137 PrgNode& operator=(const PrgNode&);
138 };
139 typedef PrgNode::Type NodeType;
140 //! An edge of a program-dependency graph.
141 /*!
142 * Currently, clasp distinguishes four types of edges:
143 * - a Normal edge stipulates an implication between body and head,
144 * i.e. tableau-rules FTA and BFA for atoms.
145 * - a Choice edge only stipulates a support.
146 * - a Gamma edge is like a Normal edge that is only considered during
147 * nogood creation but ignored in the dependency graph.
148 * - a GammaChoice edge is like a Gamma edge but only stipulates a support.
149 * The head of a rule is either an atom or a disjunction.
150 */
151 struct PrgEdge {
152 //! Type of edge.
153 enum Type { Normal = 0, Gamma = 1, Choice = 2, GammaChoice = 3 };
noEdgePrgEdge154 static PrgEdge noEdge() { PrgEdge x; x.rep = UINT32_MAX; return x; }
155
156 template <class NT>
newEdgePrgEdge157 static PrgEdge newEdge(const NT& n, Type eType) {
158 // 28-bit node id, 2-bit node type, 2-bit edge type
159 PrgEdge x = { (n.id() << 4) | (static_cast<uint32>(n.nodeType()) << 2) | eType };
160 return x;
161 }
162 //! Returns the id of the adjacent node.
nodePrgEdge163 uint32 node() const { return rep >> 4; }
164 //! Returns the type of this edge.
typePrgEdge165 Type type() const { return Type(rep & 3u); }
166 //! Returns the type of adjacent node.
nodeTypePrgEdge167 NodeType nodeType() const { return NodeType((rep >> 2) & 3u); }
168 //! Returns true if edge has normal semantic (normal edge or gamma edge).
isNormalPrgEdge169 bool isNormal() const { return (rep & 2u) == 0; }
170 //! Returns true if edge has choice semantic.
isChoicePrgEdge171 bool isChoice() const { return (rep & 2u) != 0; }
172 //! Returns true if the edge is a gamma (aux normal) edge.
isGammaPrgEdge173 bool isGamma() const { return (rep & 1u) != 0; }
174 //! Returns true if the adjacent node is a body.
isBodyPrgEdge175 bool isBody() const { return nodeType() == PrgNode::Body; }
176 //! Returns true if the adjacant node is an atom.
isAtomPrgEdge177 bool isAtom() const { return nodeType() == PrgNode::Atom; }
178 //! Returns true if the adjacent node is a disjunction.
isDisjPrgEdge179 bool isDisj() const { return nodeType() == PrgNode::Disj; }
180 bool operator< (PrgEdge rhs) const { return rep < rhs.rep; }
181 bool operator==(PrgEdge rhs) const { return rep == rhs.rep; }
182 uint32 rep;
183 };
184
185 typedef PrgEdge::Type EdgeType;
186 typedef const PrgEdge* EdgeIterator;
187 typedef bk_lib::pod_vector<PrgEdge> EdgeVec;
isChoice(EdgeType t)188 inline bool isChoice(EdgeType t) { return t >= PrgEdge::Choice; }
189
190 using Potassco::Body_t;
191 using Potassco::Head_t;
192 using Potassco::WeightLitSpan;
193 typedef Potassco::Rule_t Rule;
194 //! A class for translating extended rules to normal rules.
195 class RuleTransform {
196 public:
197 //! Interface that must be implemented to get the result of a transformation.
198 struct ProgramAdapter {
199 virtual Atom_t newAtom() = 0;
200 virtual void addRule(const Rule& r) = 0;
~ProgramAdapterProgramAdapter201 protected: ~ProgramAdapter() {}
202 };
203 //! Supported transformation strategies.
204 enum Strategy { strategy_default, strategy_no_aux, strategy_allow_aux };
205 RuleTransform(ProgramAdapter& prg);
206 RuleTransform(LogicProgram& prg);
207 ~RuleTransform();
208 //! Transforms the given (extended) rule to a set of normal rules.
209 uint32 transform(const Rule& r, Strategy s = strategy_default);
210 private:
211 RuleTransform(const RuleTransform&);
212 RuleTransform& operator=(const RuleTransform&);
213 struct Impl;
214 Impl* impl_;
215 };
216
217 //! A set of flags used during rule simplification.
218 class AtomState {
219 public:
220 static const uint8 pos_flag = 0x1u; //!< In positive body of active rule
221 static const uint8 neg_flag = 0x2u; //!< In negative body of active rule
222 static const uint8 head_flag = 0x4u; //!< In normal head of active rule
223 static const uint8 choice_flag = 0x8u; //!< In choice head of active rule
224 static const uint8 disj_flag = 0x10u;//!< In disjunctive head of active rule
225 static const uint8 rule_mask = 0x1Fu;//!< In active rule
226 static const uint8 fact_flag = 0x20u;//!< Atom is a fact (sticky)
227 static const uint8 false_flag = 0x40u;//!< Atom is false (sticky)
228 static const uint8 simp_mask = 0x7fu;//!< In active rule or assigned
229 static const uint8 dom_flag = 0x80u;//!< Var of atom is a dom var (sticky)
AtomState()230 AtomState() {}
swap(AtomState & o)231 void swap(AtomState& o) { state_.swap(o.state_); }
232 //! Does t.node() appear in the head of the active rule?
inHead(PrgEdge t)233 bool inHead(PrgEdge t) const { return isSet(t.node(), headFlag(t)); }
inHead(Atom_t atom)234 bool inHead(Atom_t atom) const { return isSet(atom, head_flag); }
235 //! Does p appear in the body of the active rule?
inBody(Literal p)236 bool inBody(Literal p) const { return isSet(p.var(), pos_flag+p.sign()); }
isSet(Var v,uint8 f)237 bool isSet(Var v, uint8 f) const { return v < state_.size() && (state_[v] & f) != 0; }
isFact(Var v)238 bool isFact(Var v) const { return isSet(v, fact_flag); }
239 //! Mark v as a head of the active rule.
addToHead(Atom_t v)240 void addToHead(Atom_t v) { set(v, head_flag); }
addToHead(PrgEdge t)241 void addToHead(PrgEdge t) { set(t.node(), headFlag(t)); }
242 //! Mark p as a literal contained in the active rule.
addToBody(Literal p)243 void addToBody(Literal p) { set(p.var(), pos_flag+p.sign()); }
244
set(Var v,uint8 f)245 void set(Var v, uint8 f) { grow(v); state_[v] |= f; }
clear(Var v,uint8 f)246 void clear(Var v, uint8 f) { if (v < state_.size()) { state_[v] &= ~f; } }
clearRule(Var v)247 void clearRule(Var v) { clear(v, rule_mask); }
clearHead(PrgEdge t)248 void clearHead(PrgEdge t) { clear(t.node(), headFlag(t)); }
clearBody(Literal p)249 void clearBody(Literal p) { clear(p.var(), pos_flag+p.sign()); }
resize(uint32 sz)250 void resize(uint32 sz) { state_.resize(sz); }
251
252 template <class IT>
allMarked(IT first,IT last,uint8 f)253 bool allMarked(IT first, IT last, uint8 f) const {
254 for (; first != last; ++first) {
255 if (!isSet(*first, f)) return false;
256 }
257 return true;
258 }
inBody(const Literal * first,const Literal * last)259 bool inBody(const Literal* first, const Literal* last) const {
260 bool all = true;
261 for (; first != last && (all = inBody(*first)) == true; ++first) { ; }
262 return all;
263 }
264 private:
265 typedef PodVector<uint8>::type StateVec;
grow(Var v)266 void grow(Var v) { if (v >= state_.size()) { state_.resize(v+1); } }
headFlag(PrgEdge t)267 uint8 headFlag(PrgEdge t) const {
268 return t.isAtom() ? (head_flag << uint8(t.isChoice())) : disj_flag;
269 }
270 StateVec state_;
271 };
272
273 //! A head node of a program-dependency graph.
274 /*!
275 * A head node is either an atom or a disjunction
276 * and stores its possible supports.
277 */
278 class PrgHead : public PrgNode {
279 public:
280 enum Simplify { no_simplify = 0, force_simplify = 1 };
281 typedef EdgeIterator sup_iterator;
282
283 //! Is the head part of the (simplified) program?
inUpper()284 bool inUpper() const { return relevant() && upper_ != 0; }
285 //! Is this head an atom?
isAtom()286 bool isAtom() const { return isAtom_ != 0; }
287 //! Number of supports (rules) for this head.
supports()288 uint32 supports() const { return supports_.size(); }
supps_begin()289 sup_iterator supps_begin()const { return supports_.begin(); }
supps_end()290 sup_iterator supps_end() const { return supports_.end(); }
291 //! External atom (or defined in a later incremental step)?
frozen()292 bool frozen() const { return freeze_ != uint32(freeze_no); }
293 //! If frozen(), value to assume during solving.
freezeValue()294 ValueRep freezeValue()const { return static_cast<ValueRep>(freeze_ - uint32(freeze_ != 0)); }
295 //! If frozen(), literal to assume during solving.
assumption()296 Literal assumption() const { return freeze_ > uint32(freeze_free) ? literal() ^ (freeze_ == freeze_false) : lit_true(); }
297 //! Adds r as support edge for this node.
addSupport(PrgEdge r)298 void addSupport(PrgEdge r){ addSupport(r, force_simplify); }
299 void addSupport(PrgEdge r, Simplify s);
300 //! Removes r from the head's list of supports.
301 void removeSupport(PrgEdge r);
302 void clearSupports();
clearSupports(EdgeVec & to)303 void clearSupports(EdgeVec& to) { to.swap(supports_); clearSupports(); }
304 //! Removes any superfluous/irrelevant supports.
305 bool simplifySupports(LogicProgram& prg, bool strong, uint32* numDiffSupps = 0);
306 //! Assigns the value v to this head.
assignValue(ValueRep v)307 bool assignValue(ValueRep v) { return assignValueImpl(v, ignoreScc() && !frozen()); }
308 /*!
309 * \name implementation functions
310 * Low-level implementation functions. Use with care and only if you
311 * know what you are doing!
312 */
313 //@{
setInUpper(bool b)314 void setInUpper(bool b) { upper_ = (uint32)b; }
markDirty()315 void markDirty() { dirty_ = 1; }
316 void assignVar(LogicProgram& prg, PrgEdge it, bool allowEq = true);
nodeType()317 NodeType nodeType() const { return isAtom() ? PrgNode::Atom : PrgNode::Disj; }
318 //@}
319 protected:
320 enum FreezeState { freeze_no = 0u, freeze_free = 1u, freeze_true = 2u, freeze_false = 3u };
321 //! Creates a new node that corresponds to a literal that is false.
322 explicit PrgHead(uint32 id, NodeType t, uint32 data = 0, bool checkScc = true);
323 bool backpropagate(LogicProgram& prg, ValueRep val, bool bpFull);
324 EdgeVec supports_; // possible supports (body or disjunction)
325 uint32 data_ : 27; // number of atoms in disjunction or scc of atom
326 uint32 upper_ : 1; // in (simplified) program?
327 uint32 dirty_ : 1; // is list of supports dirty?
328 uint32 freeze_: 2; // incremental freeze state
329 uint32 isAtom_: 1; // is this head an atom?
330 };
331
332 //! An atom in a logic program.
333 /*!
334 * An atom stores the list of bodies depending on it.
335 * Furthermore, once strongly-connected components are identified,
336 * atoms store their SCC-number. All trivial SCCs are represented
337 * with the special SCC-number PrgNode::noScc.
338 */
339 class PrgAtom : public PrgHead {
340 public:
341 enum Dependency { dep_pos = 0, dep_neg = 1, dep_all = 2 };
342 typedef LitVec::const_iterator dep_iterator;
343 explicit PrgAtom(uint32 id, bool checkScc = true);
nodeType()344 NodeType nodeType() const { return PrgNode::Atom; }
345 //! Strongly connected component of this node.
scc()346 uint32 scc() const { return data_; }
347 //! If eq(), stores the literal that is eq to this atom.
348 Literal eqGoal(bool sign) const;
349 //! Returns true if atom belongs to a disjunctive head.
350 bool inDisj() const;
351 /*!
352 * \name forward dependencies (bodies containing this atom)
353 */
354 //@{
deps_begin()355 dep_iterator deps_begin() const { return deps_.begin(); }
deps_end()356 dep_iterator deps_end() const { return deps_.end(); }
357 bool hasDep(Dependency d) const;
358 void addDep(Id_t bodyId, bool pos);
359 void removeDep(Id_t bodyId, bool pos);
360 void clearDeps(Dependency d);
361 //@}
362
363 /*!
364 * \name implementation functions
365 * Low-level implementation functions. Use with care and only if you
366 * know what you are doing!
367 */
368 //@{
369 void setEqGoal(Literal x);
370 bool propagateValue(LogicProgram& prg, bool backprop);
371 bool addConstraints(const LogicProgram& prg, ClauseCreator& c);
setScc(uint32 scc)372 void setScc(uint32 scc) { data_ = scc; }
markFrozen(ValueRep v)373 void markFrozen(ValueRep v){ freeze_ = v + freeze_free; }
clearFrozen()374 void clearFrozen() { freeze_ = freeze_no; markDirty(); }
375 //@}
376 private:
377 LitVec deps_; // bodies depending on this atom
378 };
379
380 //! A (rule) body in a logic program.
381 class PrgBody : public PrgNode {
382 public:
383 typedef EdgeIterator head_iterator;
384 typedef const Literal* goal_iterator;
385
386 //! Creates a new body node and (optionally) connects it to its predecessors (i.e. atoms).
387 /*!
388 * \param prg The program in which the new body is used.
389 * \param id The id for the new body node.
390 * \param rule The rule for which a body node is to be created.
391 * \param pos Positive body size.
392 * \param addDeps If true, add an edge between each atom subgoal and the new node.
393 */
394 static PrgBody* create(LogicProgram& prg, uint32 id, const Rule& rule, uint32 pos, bool addDeps);
395 //! Destroys a body node created via create().
396 void destroy();
type()397 Body_t type() const { return Body_t(static_cast<Body_t>(type_)); }
398 //! Returns the number of atoms in the body.
size()399 uint32 size() const { return size_; }
noScc()400 bool noScc() const { return size() == 0 || goal(0).sign(); }
401 //! Returns the bound of this body, or size() if the body is a normal body.
bound()402 weight_t bound() const { if (type() == Body_t::Normal) return (weight_t)size(); else return hasWeights() ? sumData()->bound : aggData().bound; }
403 //! Returns the sum of the subgoals weights, or size() if the body is not a sum with weights.
sumW()404 weight_t sumW() const { return static_cast<weight_t>(!hasWeights() ? (weight_t)size() : sumData()->sumW); }
405 //! Returns the idx'th subgoal as a literal.
goal(uint32 idx)406 Literal goal(uint32 idx) const { assert(idx < size()); return *(goals_begin()+idx); }
407 //! Returns the weight of the idx'th subgoal.
weight(uint32 idx)408 weight_t weight(uint32 idx)const { assert(idx < size()); return !hasWeights() ? 1 : sumData()->weights[idx]; }
409 //! Returns true if the body node is supported.
410 /*!
411 * A normal body is supported, iff all of its positive subgoals are supported.
412 * A count/sum body is supported if the sum of the weights of the supported positive +
413 * the sum of the negative weights is >= lowerBound().
414 */
isSupported()415 bool isSupported() const { return unsupp_ <= 0; }
416 //! Returns true if this body defines any head.
hasHeads()417 bool hasHeads() const { return isSmallHead() ? head_ != 0 : !largeHead()->empty(); }
inRule()418 bool inRule() const { return hasHeads() || freeze_; }
419
heads_begin()420 head_iterator heads_begin() const { return isSmallHead() ? smallHead() : largeHead()->begin(); }
heads_end()421 head_iterator heads_end() const { return isSmallHead() ? smallHead()+head_ : largeHead()->end(); }
goals_begin()422 goal_iterator goals_begin() const { return const_cast<PrgBody*>(this)->goals_begin(); }
goals_end()423 goal_iterator goals_end() const { return goals_begin() + size(); }
424 //! Adds a rule edge between this body and the given head.
425 /*!
426 * \note
427 * The function also adds a corresponding back edge to the head.
428 * \note
429 * Adding a head invalidates the set property for the heads of this body.
430 * To restore it, call simplifyHeads()
431 */
432 void addHead(PrgHead* h, EdgeType t);
433 //! Simplifies the heads of this body and establishes set property.
434 /*!
435 * Removes superfluous heads and sets the body to false if for some atom a
436 * in the head of this body B, Ta -> FB. In that case, all heads atoms are removed, because
437 * a false body can't define any atom.
438 * If strong is true, removes head atoms that are not associated with a variable.
439 * \return
440 * setValue(value_false) if setting a head of this body to true would
441 * make the body false (i.e. the body is a selfblocker). Otherwise, true.
442 */
443 bool simplifyHeads(LogicProgram& prg, bool strong);
444 bool mergeHeads(LogicProgram& prg, PrgBody& heads, bool strong, bool simplify = true);
445 void removeHead(PrgHead* h, EdgeType t);
446 bool hasHead(PrgHead* h, EdgeType t) const;
447 //! Simplifies the body, i.e. its predecessors-lists.
448 /*!
449 * - removes true/false atoms from B+/B- resp.
450 * - removes/merges duplicate subgoals
451 * - checks whether body must be false (e.g. contains false/true atoms in B+/B- resp. or contains p and ~p)
452 *
453 * \pre prg.getBody(id()) == this
454 *
455 * \param[in] prg The program containing this body.
456 * \param[in] strong If true, treats atoms that have no variable associated as false.
457 * \param[out] eqId The id of a body in prg that is equivalent to this body.
458 *
459 * \return
460 * - true if simplification was successful
461 * - false if simplification detected a conflict
462 */
463 bool simplifyBody(LogicProgram& prg, bool strong, uint32* eqId = 0);
464 //! Calls simplifyBody() and/or simplifyHeads() if necessary.
465 bool simplify(LogicProgram& prg, bool strong, uint32* eqId = 0) {
466 return simplifyBody(prg, strong, eqId) && simplifyHeads(prg, strong);
467 }
468 bool toData(const LogicProgram& prg, Potassco::RuleBuilder& out) const;
469 //! Notifies the body node about the fact that its positive subgoal v is supported.
470 /*!
471 * \return true if the body is now also supported, false otherwise.
472 */
473 bool propagateSupported(Var /* v */);
474 //! Propagates the assignment of subgoal p.
475 bool propagateAssigned(LogicProgram& prg, Literal p, ValueRep v);
476 //! Propagates the assignment of a head.
477 bool propagateAssigned(LogicProgram& prg, PrgHead* h, EdgeType t);
478 //! Propagates the value of this body.
479 bool propagateValue(LogicProgram& prg, bool backprop);
480 bool propagateValue(LogicProgram& prg);
481 bool addConstraints(const LogicProgram& prg, ClauseCreator& c);
markDirty()482 void markDirty() { sBody_ = 1; }
markHeadsDirty()483 void markHeadsDirty() { sHead_ = 1; }
markFrozen()484 void markFrozen() { freeze_= 1; }
485 void clearHeads();
486 bool resetSupported();
487 void assignVar(LogicProgram& prg);
assignValue(ValueRep v)488 bool assignValue(ValueRep v) { return assignValueImpl(v, noScc()); }
489 uint32 scc(const LogicProgram& prg) const;
hasWeights()490 bool hasWeights() const { return type() == Body_t::Sum; }
clearRule(AtomState & rs)491 void clearRule(AtomState& rs) const {
492 for (head_iterator it = heads_begin(), end = heads_end(); it != end; ++it) {
493 rs.clearRule(it->node());
494 }
495 for (const Literal* it = goals_begin(), *end = it + size(); it != end; ++it) {
496 rs.clearRule(it->var());
497 }
498 }
nodeType()499 NodeType nodeType() const { return PrgNode::Body; }
500 private:
501 static const uint32 maxSize = (1u<<26)-1;
502 typedef unsigned char byte_t;
503 POTASSCO_WARNING_BEGIN_RELAXED
504 struct SumData {
505 enum { LIT_OFFSET = sizeof(void*)/sizeof(uint32) };
506 static SumData* create(uint32 size, weight_t bnd, weight_t ws);
507 void destroy();
508 weight_t bound;
509 weight_t sumW;
510 weight_t weights[0];
511 };
512 struct Agg {
513 union {
514 SumData* sum;
515 weight_t bound;
516 };
517 Literal lits[0];
518 };
519 struct Norm { Literal lits[0]; };
520 PrgBody(uint32 id, LogicProgram& prg, const Potassco::LitSpan& lits, uint32 pos, bool addDeps);
521 PrgBody(uint32 id, LogicProgram& prg, const Potassco::Sum_t& sum, bool hasWeights, uint32 pos, bool addDeps);
522 void init(Body_t t, uint32 sz);
523 ~PrgBody();
524 uint32 findLit(const LogicProgram& prg, Literal p) const;
525 bool normalize(const LogicProgram& prg, weight_t bound, weight_t sumW, weight_t reachW, uint32& hashOut);
526 void prepareSimplifyHeads(LogicProgram& prg, AtomState& rs);
527 bool simplifyHeadsImpl(LogicProgram& prg, PrgBody& target, AtomState& rs, bool strong);
528 bool superfluousHead(const LogicProgram& prg, const PrgHead* head, PrgEdge it, const AtomState& rs) const;
529 bool blockedHead(PrgEdge it, const AtomState& rs) const;
530 void addHead(PrgEdge h);
531 bool eraseHead(PrgEdge h);
isSmallHead()532 bool isSmallHead() const { return head_ != 3u; }
data()533 byte_t* data() const { return const_cast<unsigned char*>(static_cast<const unsigned char*>(data_)); }
smallHead()534 PrgEdge* smallHead() const { return const_cast<PrgEdge*>(headData_.sm); }
largeHead()535 EdgeVec* largeHead() const { return headData_.ext; }
sumData()536 SumData* sumData() const { return aggData().sum;}
aggData()537 Agg& aggData() const { return *reinterpret_cast<Agg*>(data()); }
goals_begin()538 Literal* goals_begin() { return type() == Body_t::Normal ? reinterpret_cast<Norm*>(data())->lits : aggData().lits; }
goals_end()539 Literal* goals_end() { return goals_begin() + size(); }
540
541 uint32 size_ : 25; // |B|
542 uint32 head_ : 2; // simple or extended head?
543 uint32 type_ : 2; // body type
544 uint32 sBody_ : 1; // simplify body?
545 uint32 sHead_ : 1; // simplify head?
546 uint32 freeze_ : 1; // keep body even if it does not occur in a rule?
547 weight_t unsupp_; // <= 0 -> body is supported
548 union Head {
549 PrgEdge sm[2];
550 EdgeVec* ext;
551 } headData_; // successors of this body
552 byte_t data_[0]; // empty or one of Agg|Norm
553 POTASSCO_WARNING_END_RELAXED
554 };
555 //! The head of a disjunctive rule.
556 class PrgDisj : public PrgHead {
557 public:
558 typedef const Var* atom_iterator;
559 //! Constructor for disjunctions.
560 static PrgDisj* create(uint32 id, const Potassco::AtomSpan& head);
561 //! Destroys a disjunction created via create().
562 void destroy();
563 void detach(LogicProgram& prg);
564 //! Number of atoms in disjunction.
size()565 uint32 size() const { return data_; }
begin()566 atom_iterator begin() const { return atoms_; }
end()567 atom_iterator end() const { return atoms_ + size(); }
568 //! Propagates the assignment of an atom in this disjunction.
569 bool propagateAssigned(LogicProgram& prg, PrgHead* at, EdgeType t);
570 private:
571 explicit PrgDisj(uint32 id, const Potassco::AtomSpan& head);
572 ~PrgDisj();
573 POTASSCO_WARNING_BEGIN_RELAXED
574 Var atoms_[0]; // atoms in disjunction
575 POTASSCO_WARNING_END_RELAXED
576 };
577
getMergeValue(const PrgNode * lhs,const PrgNode * rhs)578 inline ValueRep getMergeValue(const PrgNode* lhs, const PrgNode* rhs) {
579 return static_cast<ValueRep>(std::min(static_cast<ValueRep>(lhs->value()-1), static_cast<ValueRep>(rhs->value()-1)) + 1);
580 }
581
582 template <class NT>
mergeValue(NT * lhs,NT * rhs)583 bool mergeValue(NT* lhs, NT* rhs){
584 ValueRep mv = getMergeValue(lhs, rhs);
585 return (lhs->value() == mv || lhs->assignValue(mv))
586 && (rhs->value() == mv || rhs->assignValue(mv));
587 }
588
589 //! A class for computing strongly connected components of the positive atom-body dependency graph.
590 class SccChecker {
591 public:
592 SccChecker(LogicProgram& prg, AtomList& sccAtoms, uint32 startScc);
sccs()593 uint32 sccs() const { return sccs_; }
visit(PrgBody * body)594 void visit(PrgBody* body) { visitDfs(body, PrgNode::Body); }
visit(PrgAtom * atom)595 void visit(PrgAtom* atom) { visitDfs(atom, PrgNode::Atom); }
visit(PrgDisj * disj)596 void visit(PrgDisj* disj) { visitDfs(disj, PrgNode::Disj); }
597 private:
598 struct Call {
599 uintp node;
600 uint32 min;
601 uint32 next;
602 };
603 typedef PodVector<Call>::type CallStack;
604 typedef PodVector<uintp>::type NodeStack;
packNode(PrgNode * n,NodeType t)605 static uintp packNode(PrgNode* n, NodeType t) { return reinterpret_cast<uintp>(n) + uintp(t); }
unpackNode(uintp n)606 static PrgNode* unpackNode(uintp n) { return reinterpret_cast<PrgNode*>(n & ~uintp(3u));}
isNode(uintp n,NodeType t)607 static bool isNode(uintp n, NodeType t) { return (n & 3u) == uintp(t); }
608 bool doVisit(PrgNode* n, bool seen = true) const { return !n->ignoreScc() && n->relevant() && n->hasVar() && (!seen || !n->seen()); }
609 void visitDfs(PrgNode* n, NodeType t);
610 bool recurse(Call& c);
611 bool onNode(PrgNode* n, NodeType t, Call& c, uint32 data);
612 void addCall(PrgNode* n, NodeType t, uint32 next, uint32 min = 0) {
613 Call c = {packNode(n, t), min, next};
614 callStack_.push_back(c);
615 }
616 CallStack callStack_;
617 NodeStack nodeStack_;
618 LogicProgram* prg_;
619 AtomList* sccAtoms_;
620 uint32 count_;
621 uint32 sccs_;
622 };
623 //! A set of ids of strongly connected components having at least one head-cycle.
624 struct NonHcfSet : private PodVector<uint32>::type {
625 public:
626 typedef PodVector<uint32>::type base_type;
627 typedef base_type::const_iterator const_iterator;
628 using base_type::begin;
629 using base_type::end;
630 using base_type::size;
NonHcfSetNonHcfSet631 NonHcfSet() : config(0) {}
addNonHcfSet632 void add(uint32 scc) {
633 iterator it = std::lower_bound(begin(), end(), scc);
634 if (it == end() || *it != scc) { insert(it, scc); }
635 }
findNonHcfSet636 bool find(uint32 scc) const {
637 const_iterator it = scc != PrgNode::noScc ? std::lower_bound(begin(), end(), scc) : end();
638 return it != end() && *it == scc;
639 }
640 Configuration* config;
641 };
642 //@}
643 } }
644 #endif
645