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