+ model_print("\n");
+}
+
+/** @brief Get a (likely) unique hash for this ModelAction */
+unsigned int ModelAction::hash() const
+{
+ unsigned int hash = (unsigned int)this->type;
+ hash ^= ((unsigned int)this->order) << 3;
+ hash ^= seq_number << 5;
+ hash ^= id_to_int(tid) << 6;
+
+ if (is_read()) {
+ if (reads_from)
+ hash ^= reads_from->get_seq_number();
+ else if (reads_from_promise)
+ hash ^= reads_from_promise->get_index();
+ hash ^= get_reads_from_value();
+ }
+ return hash;
+}
+
+/**
+ * @brief Checks the NodeStack to see if a ModelAction is in our may-read-from set
+ * @param write The ModelAction to check for
+ * @return True if the ModelAction is found; false otherwise
+ */
+bool ModelAction::may_read_from(const ModelAction *write) const
+{
+ for (int i = 0; i < node->get_read_from_past_size(); i++)
+ if (node->get_read_from_past(i) == write)
+ return true;
+ return false;
+}
+
+/**
+ * @brief Checks the NodeStack to see if a Promise is in our may-read-from set
+ * @param promise The Promise to check for
+ * @return True if the Promise is found; false otherwise
+ */
+bool ModelAction::may_read_from(const Promise *promise) const
+{
+ for (int i = 0; i < node->get_read_from_promise_size(); i++)
+ if (node->get_read_from_promise(i) == promise)
+ return true;
+ return false;
+}
+
+/**
+ * Only valid for LOCK, TRY_LOCK, UNLOCK, and WAIT operations.
+ * @return The mutex operated on by this action, if any; otherwise NULL
+ */
+std::mutex * ModelAction::get_mutex() const
+{
+ if (is_trylock() || is_lock() || is_unlock())
+ return (std::mutex *)get_location();
+ else if (is_wait())
+ return (std::mutex *)get_value();
+ else
+ return NULL;