summaryrefslogtreecommitdiff
path: root/src/theory/uf
diff options
context:
space:
mode:
authorDejan Jovanović <dejan.jovanovic@gmail.com>2012-05-21 20:15:52 +0000
committerDejan Jovanović <dejan.jovanovic@gmail.com>2012-05-21 20:15:52 +0000
commit6ce8f5cc5d7767d5ff9e74bc08d3c8a364ad8bf1 (patch)
tree67622f3ea73388f3a93ae381b0b8a6de92049f70 /src/theory/uf
parentfdd00c4dbfa64da59c65d5d1fef3e8505a842cc8 (diff)
Updating equality manager to handle tagged trigger terms. Notifications are pushed out for relationships between terms tagged with the same tag. No performance impact.
Diffstat (limited to 'src/theory/uf')
-rw-r--r--src/theory/uf/equality_engine.cpp185
-rw-r--r--src/theory/uf/equality_engine.h116
-rw-r--r--src/theory/uf/theory_uf.cpp8
-rw-r--r--src/theory/uf/theory_uf.h4
4 files changed, 248 insertions, 65 deletions
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index f9220c7f3..2527893ff 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -62,8 +62,15 @@ void EqualityEngine::init() {
d_false = NodeManager::currentNM()->mkConst<bool>(false);
addTerm(d_true);
addTerm(d_false);
+
+ d_triggerDatabaseAllocatedSize = 100000;
+ d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize);
}
+EqualityEngine::~EqualityEngine() throw(AssertionException) {
+ free(d_triggerDatabase);
+}
+
EqualityEngine::EqualityEngine(context::Context* context, std::string name)
: ContextNotifyObj(context)
@@ -74,10 +81,11 @@ EqualityEngine::EqualityEngine(context::Context* context, std::string name)
, d_nodesCount(context, 0)
, d_assertedEqualitiesCount(context, 0)
, d_equalityTriggersCount(context, 0)
-, d_individualTriggersSize(context, 0)
, d_constantRepresentativesSize(context, 0)
, d_constantsSize(context, 0)
, d_stats(name)
+, d_triggerDatabaseSize(context, 0)
+, d_triggerTermSetUpdatesSize(context, 0)
{
init();
}
@@ -91,10 +99,11 @@ EqualityEngine::EqualityEngine(EqualityEngineNotify& notify, context::Context* c
, d_nodesCount(context, 0)
, d_assertedEqualitiesCount(context, 0)
, d_equalityTriggersCount(context, 0)
-, d_individualTriggersSize(context, 0)
, d_constantRepresentativesSize(context, 0)
, d_constantsSize(context, 0)
, d_stats(name)
+, d_triggerDatabaseSize(context, 0)
+, d_triggerTermSetUpdatesSize(context, 0)
{
init();
}
@@ -162,7 +171,7 @@ EqualityNodeId EqualityEngine::newNode(TNode node) {
// Add it to the equality graph
d_equalityGraph.push_back(+null_edge);
// Mark the no-individual trigger
- d_nodeIndividualTrigger.push_back(+null_id);
+ d_nodeIndividualTrigger.push_back(+null_set_id);
// Mark non-constant by default
d_constantRepresentative.push_back(node.isConst() ? newId : +null_id);
// Add the equality node to the nodes
@@ -423,22 +432,67 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
}
// Notify the trigger term merges
- EqualityNodeId class2triggerId = d_nodeIndividualTrigger[class2Id];
- if (class2triggerId != +null_id) {
- EqualityNodeId class1triggerId = d_nodeIndividualTrigger[class1Id];
- if (class1triggerId == +null_id) {
- // If class1 is not an individual trigger, but class2 is, mark it
- d_nodeIndividualTrigger[class1Id] = class2triggerId;
+ TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id];
+ if (class2triggerRef != +null_set_id) {
+ TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id];
+ if (class1triggerRef == +null_set_id) {
+ // If class1 doesn't have individual triggers, but class2 does, mark it
+ d_nodeIndividualTrigger[class1Id] = class2triggerRef;
// Add it to the list for backtracking
- d_individualTriggers.push_back(class1Id);
- d_individualTriggersSize = d_individualTriggersSize + 1;
+ d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, +null_set_id));
+ d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
} else {
- // Notify when done
- if (d_performNotify) {
- if (!d_notify.eqNotifyTriggerTermEquality(d_nodes[class1triggerId], d_nodes[class2triggerId], true)) {
- return false;
+ // Get the triggers
+ TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
+ TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
+
+ // Initialize the merged set
+ d_newSetTags = Theory::setUnion(class1triggers.tags, class2triggers.tags);
+ d_newSetTriggersSize = 0;
+
+ int i1 = 0;
+ int i2 = 0;
+ Theory::Set tags1 = class1triggers.tags;
+ Theory::Set tags2 = class2triggers.tags;
+ TheoryId tag1 = Theory::setPop(tags1);
+ TheoryId tag2 = Theory::setPop(tags2);
+
+ // Comparing the THEORY_LAST is OK because all other theories are
+ // smaller, and will therefore be preferred
+ while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
+ {
+ if (tag1 < tag2) {
+ // copy tag1
+ d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
+ tag1 = Theory::setPop(tags1);
+ } else if (tag1 > tag2) {
+ // copy tag2
+ d_newSetTriggers[d_newSetTriggersSize++] = class2triggers.triggers[i2++];
+ tag2 = Theory::setPop(tags2);
+ } else {
+ // copy tag1
+ EqualityNodeId tag1id = d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
+ // since they are both tagged notify of merge
+ if (d_performNotify) {
+ EqualityNodeId tag2id = class2triggers.triggers[i2++];
+ if (!d_notify.eqNotifyTriggerTermEquality(tag1, d_nodes[tag1id], d_nodes[tag2id], true)) {
+ return false;
+ }
+ }
+ // Next tags
+ tag1 = Theory::setPop(tags1);
+ tag2 = Theory::setPop(tags2);
}
- }
+ }
+
+ // Add the new trigger set, if different from previous one
+ if (class1triggers.tags != class2triggers.tags) {
+ // Add it to the list for backtracking
+ d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef));
+ d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
+ // Mark the the new set as a trigger
+ d_nodeIndividualTrigger[class1Id] = newTriggerTermSet();
+ }
}
}
@@ -513,12 +567,13 @@ void EqualityEngine::backtrack() {
d_equalityEdges.resize(2 * d_assertedEqualitiesCount);
}
- if (d_individualTriggers.size() > d_individualTriggersSize) {
+ if (d_triggerTermSetUpdates.size() > d_triggerTermSetUpdatesSize) {
// Unset the individual triggers
- for (int i = d_individualTriggers.size() - 1, i_end = d_individualTriggersSize; i >= i_end; -- i) {
- d_nodeIndividualTrigger[d_individualTriggers[i]] = +null_id;
+ for (int i = d_triggerTermSetUpdates.size() - 1, i_end = d_triggerTermSetUpdatesSize; i >= i_end; -- i) {
+ const TriggerSetUpdate& update = d_triggerTermSetUpdates[i];
+ d_nodeIndividualTrigger[update.classId] = update.oldValue;
}
- d_individualTriggers.resize(d_individualTriggersSize);
+ d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
}
if (d_constantRepresentatives.size() > d_constantRepresentativesSize) {
@@ -935,9 +990,10 @@ size_t EqualityEngine::getSize(TNode t)
return getEqualityNode(getEqualityNode(t).getFind()).getSize();
}
-void EqualityEngine::addTriggerTerm(TNode t)
+void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
{
- Debug("equality::internal") << "EqualityEngine::addTriggerTerm(" << t << ")" << std::endl;
+ Debug("equality::internal") << "EqualityEngine::addTriggerTerm(" << t << ", " << tag << ")" << std::endl;
+ Assert(tag != THEORY_LAST);
// Add the term if it's not already there
addTerm(t);
@@ -947,31 +1003,67 @@ void EqualityEngine::addTriggerTerm(TNode t)
EqualityNode& eqNode = getEqualityNode(eqNodeId);
EqualityNodeId classId = eqNode.getFind();
- if (d_nodeIndividualTrigger[classId] != +null_id) {
- // No need to keep it, just propagate the existing individual triggers
+ // Possibly existing set of triggers
+ TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
+ if (triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag)) {
+ // If the term already is in the equivalence class that a tagged representative, just notify
if (d_performNotify) {
- d_notify.eqNotifyTriggerTermEquality(t, d_nodes[d_nodeIndividualTrigger[classId]], true);
+ EqualityNodeId triggerId = getTriggerTermSet(triggerSetRef).getTrigger(tag);
+ d_notify.eqNotifyTriggerTermEquality(tag, t, d_nodes[triggerId], true);
}
} else {
+
+ // Setup the data for the new set
+ if (triggerSetRef != null_set_id) {
+ // Get the existing set
+ TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
+ // Initialize the new set for copy/insert
+ d_newSetTags = Theory::setInsert(tag, triggerSet.tags);
+ d_newSetTriggersSize = 0;
+ // Copy into to new one, and insert the new tag/id
+ unsigned i = 0;
+ Theory::Set tags = d_newSetTags;
+ TheoryId current;
+ while ((current = Theory::setPop(tags)) != THEORY_LAST) {
+ // Remove from the tags
+ tags = Theory::setRemove(current, tags);
+ // Insert the id into the triggers
+ d_newSetTriggers[d_newSetTriggersSize++] =
+ current == tag ? eqNodeId : triggerSet.triggers[i++];
+ }
+ } else {
+ // Setup a singleton
+ d_newSetTags = Theory::setInsert(tag);
+ d_newSetTriggers[0] = eqNodeId;
+ d_newSetTriggersSize = 1;
+ }
+
// Add it to the list for backtracking
- d_individualTriggers.push_back(classId);
- d_individualTriggersSize = d_individualTriggersSize + 1;
- // Mark the class id as a trigger
- d_nodeIndividualTrigger[classId] = eqNodeId;
+ d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
+ d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
+ // Mark the the new set as a trigger
+ d_nodeIndividualTrigger[classId] = newTriggerTermSet();
}
}
-bool EqualityEngine::isTriggerTerm(TNode t) const {
+bool EqualityEngine::isTriggerTerm(TNode t, TheoryId tag) const {
if (!hasTerm(t)) return false;
EqualityNodeId classId = getEqualityNode(t).getFind();
- return d_nodeIndividualTrigger[classId] != +null_id;
+ TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
+ return triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag);
}
-TNode EqualityEngine::getTriggerTermRepresentative(TNode t) const {
- Assert(isTriggerTerm(t));
+TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const {
+ Assert(isTriggerTerm(t, tag));
EqualityNodeId classId = getEqualityNode(t).getFind();
- return d_nodes[d_nodeIndividualTrigger[classId]];
+ const TriggerTermSet& triggerSet = getTriggerTermSet(d_nodeIndividualTrigger[classId]);
+ unsigned i = 0;
+ Theory::Set tags = triggerSet.tags;
+ while (Theory::setPop(tags) != tag) {
+ ++ i;
+ }
+ return d_nodes[triggerSet.triggers[i]];
}
void EqualityEngine::storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId) {
@@ -1010,6 +1102,31 @@ void EqualityEngine::getUseListTerms(TNode t, std::set<TNode>& output) {
}
}
+EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet() {
+ // Size of the required set
+ size_t size = sizeof(TriggerTermSet) + d_newSetTriggersSize*sizeof(EqualityNodeId);
+ // Align the size
+ size = (size + 7) & ~((size_t)7);
+ // Reallocate if necessary
+ if (d_triggerDatabaseSize + size > d_triggerDatabaseAllocatedSize) {
+ d_triggerDatabaseAllocatedSize *= 2;
+ d_triggerDatabase = (char*) realloc(d_triggerDatabase, d_triggerDatabaseAllocatedSize);
+ }
+ // New reference
+ TriggerTermSetRef newTriggerSetRef = d_triggerDatabaseSize;
+ // Update the size
+ d_triggerDatabaseSize = d_triggerDatabaseSize + size;
+ // Copy the information
+ TriggerTermSet& newSet = getTriggerTermSet(newTriggerSetRef);
+ newSet.tags = d_newSetTags;
+ for (unsigned i = 0; i < d_newSetTriggersSize; ++i) {
+ newSet.triggers[i] = d_newSetTriggers[i];
+ }
+ // Return the new reference
+ return newTriggerSetRef;
+}
+
+
} // Namespace uf
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 047e9de49..c59436aaf 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -32,6 +32,7 @@
#include "util/output.h"
#include "util/stats.h"
#include "theory/rewriter.h"
+#include "theory/theory.h"
namespace CVC4 {
namespace theory {
@@ -244,11 +245,12 @@ public:
/**
* Notifies about the merge of two trigger terms.
*
+ * @param tag the theory that both triggers were tagged with
* @param t1 a term marked as trigger
* @param t2 a term marked as trigger
* @param value true if equal, false if dis-equal
*/
- virtual bool eqNotifyTriggerTermEquality(TNode t1, TNode t2, bool value) = 0;
+ virtual bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) = 0;
/**
* Notifies about the merge of two constant terms.
@@ -267,7 +269,7 @@ class EqualityEngineNotifyNone : public EqualityEngineNotify {
public:
bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; }
bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; }
- bool eqNotifyTriggerTermEquality(TNode t1, TNode t2, bool value) { return true; }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; }
bool eqNotifyConstantTermMerge(TNode t1, TNode t2) { return true; }
};
@@ -557,21 +559,6 @@ private:
std::vector<TriggerId> d_nodeTriggers;
/**
- * List of terms that are marked as individual triggers.
- */
- std::vector<EqualityNodeId> d_individualTriggers;
-
- /**
- * Size of the individual triggers list.
- */
- context::CDO<unsigned> d_individualTriggersSize;
-
- /**
- * Map from ids to the individual trigger id representative.
- */
- std::vector<EqualityNodeId> d_nodeIndividualTrigger;
-
- /**
* Map from ids to the id of the constant that is the representative.
*/
std::vector<EqualityNodeId> d_constantRepresentative;
@@ -666,6 +653,81 @@ private:
*/
void init();
+ /** Set of trigger terms */
+ struct TriggerTermSet {
+ /** Set of theories in this set */
+ Theory::Set tags;
+ /** The trigger terms */
+ EqualityNodeId triggers[0];
+ /** Returns the theory tags */
+ Theory::Set hasTrigger(TheoryId tag) const { return Theory::setContains(tag, tags); }
+ /** Returns a trigger by tag */
+ EqualityNodeId getTrigger(TheoryId tag) const {
+ return triggers[Theory::setIndex(tag, tags)];
+ }
+ };
+
+ /** Internal tags for creating a new set */
+ Theory::Set d_newSetTags;
+
+ /** Internal triggers for creating a new set */
+ EqualityNodeId d_newSetTriggers[THEORY_LAST];
+
+ /** Size of the internal triggers array */
+ unsigned d_newSetTriggersSize;
+
+ /** The information about trigger terms is stored in this easily maintained memory. */
+ char* d_triggerDatabase;
+
+ /** Allocated size of the trigger term database */
+ size_t d_triggerDatabaseAllocatedSize ;
+
+ /** Reference for the trigger terms set */
+ typedef size_t TriggerTermSetRef;
+
+ /** Null reference */
+ static const TriggerTermSetRef null_set_id = (size_t)(-1);
+
+ /** Create new trigger term set based on the internally set information */
+ TriggerTermSetRef newTriggerTermSet();
+
+ /** Get the trigger set give a reference */
+ TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) {
+ Assert(ref < d_triggerDatabaseSize);
+ return *(reinterpret_cast<TriggerTermSet*>(d_triggerDatabase + ref));
+ }
+
+ /** Get the trigger set give a reference */
+ const TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) const {
+ Assert(ref < d_triggerDatabaseSize);
+ return *(reinterpret_cast<const TriggerTermSet*>(d_triggerDatabase + ref));
+ }
+
+ /** Used part of the trigger term database */
+ context::CDO<size_t> d_triggerDatabaseSize;
+
+ struct TriggerSetUpdate {
+ EqualityNodeId classId;
+ TriggerTermSetRef oldValue;
+ TriggerSetUpdate(EqualityNodeId classId = null_id, TriggerTermSetRef oldValue = null_set_id)
+ : classId(classId), oldValue(oldValue) {}
+ };
+
+ /**
+ * List of trigger updates for backtracking.
+ */
+ std::vector<TriggerSetUpdate> d_triggerTermSetUpdates;
+
+ /**
+ * Size of the individual triggers list.
+ */
+ context::CDO<unsigned> d_triggerTermSetUpdatesSize;
+
+ /**
+ * Map from ids to the individual trigger set representatives.
+ */
+ std::vector<TriggerTermSetRef> d_nodeIndividualTrigger;
+
public:
/**
@@ -681,7 +743,7 @@ public:
/**
* Just a destructor.
*/
- virtual ~EqualityEngine() throw(AssertionException) {}
+ virtual ~EqualityEngine() throw(AssertionException);
/**
* Adds a term to the term database.
@@ -764,25 +826,29 @@ public:
void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions);
/**
- * Add term to the trigger terms. The notify class will get notified
- * when two trigger terms become equal or dis-equal. The notification
- * will not happen on all the terms, but only on the ones that are
- * represent the class.
+ * Add term to the set of trigger terms with a corresponding tag. The notify class will get
+ * notified when two trigger terms with the same tag become equal or dis-equal. The notification
+ * will not happen on all the terms, but only on the ones that are represent the class. Note that
+ * a term can be added more than once with different tags, and each tag apperance will merit
+ * it's own notification.
+ *
+ * @param t the trigger term
+ * @param tag tag for this trigger (do NOT use THEORY_LAST)
*/
- void addTriggerTerm(TNode t);
+ void addTriggerTerm(TNode t, TheoryId theoryTag);
/**
* Returns true if t is a trigger term or in the same equivalence
* class as some other trigger term.
*/
- bool isTriggerTerm(TNode t) const;
+ bool isTriggerTerm(TNode t, TheoryId theoryTag) const;
/**
* Returns the representative trigger term of the given term.
*
* @param t the term to check where isTriggerTerm(t) should be true
*/
- TNode getTriggerTermRepresentative(TNode t) const;
+ TNode getTriggerTermRepresentative(TNode t, TheoryId theoryTag) const;
/**
* Adds a notify trigger for equality. When equality becomes true eqNotifyTriggerEquality
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 7f173a0c4..0b9e1b3a7 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -345,7 +345,7 @@ EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
void TheoryUF::addSharedTerm(TNode t) {
Debug("uf::sharing") << "TheoryUF::addSharedTerm(" << t << ")" << std::endl;
- d_equalityEngine.addTriggerTerm(t);
+ d_equalityEngine.addTriggerTerm(t, THEORY_UF);
}
void TheoryUF::computeCareGraph() {
@@ -405,14 +405,14 @@ void TheoryUF::computeCareGraph() {
continue;
}
- if (!d_equalityEngine.isTriggerTerm(x) || !d_equalityEngine.isTriggerTerm(y)) {
+ if (!d_equalityEngine.isTriggerTerm(x, THEORY_UF) || !d_equalityEngine.isTriggerTerm(y, THEORY_UF)) {
// Not connected to shared terms, we don't care
continue;
}
// Get representative trigger terms
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y);
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
switch (eqStatusDomain) {
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index 9017928b7..1dfcb86f0 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -63,8 +63,8 @@ public:
}
}
- bool eqNotifyTriggerTermEquality(TNode t1, TNode t2, bool value) {
- Debug("uf") << "NotifyClass::eqNotifyTriggerTermMerge(" << t1 << ", " << t2 << std::endl;
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("uf") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << std::endl;
if (value) {
return d_uf.propagate(t1.eqNode(t2));
} else {
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback