Replaced list with multi_index representation in EventQueue making it more efficient dev
authorDmitriy Morozov <dmitriy@mrzv.org>
Sun, 07 Feb 2010 10:46:23 -0800
branchdev
changeset 200 73e8dce642be
parent 199 2bde4c56101c
child 201 4759535221ee
Replaced list with multi_index representation in EventQueue making it more efficient
.issues/ebda8db3f9908e33/new/1221008555.M637662P30017Q16.cole
.issues/ebda8db3f9908e33/new/1265568370.M269870P17954Q1.vine
include/geometry/kinetic-sort.hpp
include/geometry/simulator.h
include/geometry/simulator.hpp
include/topology/lsvineyard.h
include/topology/lsvineyard.hpp
include/utilities/eventqueue.h
tests/geometry/test-eventqueue.cpp
tests/geometry/test-ksort-linear.cpp
--- a/.issues/ebda8db3f9908e33/new/1221008555.M637662P30017Q16.cole	Sat Feb 06 23:22:43 2010 -0800
+++ b/.issues/ebda8db3f9908e33/new/1221008555.M637662P30017Q16.cole	Sun Feb 07 10:46:23 2010 -0800
@@ -1,8 +1,9 @@
 From: Dmitriy Morozov <morozov@cs.duke.edu>
 Date: Mon, 25 Feb 2008 11:29:27 -0500
-State: new
+State: resolved
 Subject: Efficient EventQueue
 Message-Id: <ebda8db3f9908e33-0-artemis@metatron>
 category: kinetic
+resolution: fixed
 
 Change EventQueue to an efficient implementation, e.g., using a Fibonacci heap.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/ebda8db3f9908e33/new/1265568370.M269870P17954Q1.vine	Sun Feb 07 10:46:23 2010 -0800
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sun, 07 Feb 2010 10:45:04
+Subject: Switched to Boost's MultiIndex
+Message-Id: <ebda8db3f9908e33-e9c51216e26b5e19-artemis@vine>
+References: <ebda8db3f9908e33-0-artemis@metatron>
+In-Reply-To: <ebda8db3f9908e33-0-artemis@metatron>
+
+Switched EventQueue to Boost's MultiIndex with a sequence and ordered_non_unique
+indexing.
--- a/include/geometry/kinetic-sort.hpp	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/geometry/kinetic-sort.hpp	Sun Feb 07 10:46:23 2010 -0800
@@ -127,6 +127,8 @@
 	typedef 		typename Simulator::Function		        Function;
 	typedef 		typename Simulator::Time					Time;
 	
+    AssertMsg(simulator->audit_queue(), "Simulator's queue should be properly ordered");
+
 	Time t = simulator->audit_time();
 	rLog(rlKineticSortAudit, "Auditing at %s", tostring(t).c_str());
 
@@ -202,7 +204,6 @@
 	//std::cout << "Difference:         " << next_trajectory - i_trajectory << std::endl;
 
 	i->swap_event_key = simulator->add(next_trajectory - i_trajectory, SwapEvent(this, i));
-	//i->swap_event_key = simulator->add(next_trajectory, SwapEvent(this, i));
 }
 
 /* SwapEvent */
--- a/include/geometry/simulator.h	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/geometry/simulator.h	Sun Feb 07 10:46:23 2010 -0800
@@ -36,6 +36,7 @@
 
                                     Simulator(Time start = FunctionKernel::root(0)):
                                         current_(start)                         {}
+                                    ~Simulator()                                { for (Key cur = queue_.top(); cur != queue_.end(); ++cur) delete *cur; }
 
 
         template<class Event_> 
@@ -45,7 +46,7 @@
         void                        process();
         void                        update(Key k, const Function& f);
         
-        void                        remove(Key k)                               { queue_.remove(k); }
+        void                        remove(Key k)                               { Event* e = *k; queue_.remove(k); delete e; }
         Key                         null_key()                                  { return queue_.end(); }
 
         Time                        current_time() const                        { return current_; }
@@ -57,10 +58,9 @@
         unsigned                    size() const                                { return queue_.size(); }
         unsigned                    event_count() const                         { return count_; }
 
-        std::ostream&               operator<<(std::ostream& out) const;
+        bool                        audit_queue() const;
 
-    private:
-        void                        update(Key i);
+        std::ostream&               operator<<(std::ostream& out) const;
 
     private:
         Time                        current_;
--- a/include/geometry/simulator.hpp	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/geometry/simulator.hpp	Sun Feb 07 10:46:23 2010 -0800
@@ -39,14 +39,18 @@
 
 	while (!ee->root_stack().empty() && ee->root_stack().top() < current_time())
 	{
+        // rLog(rlSimulator, "Popping expired root: %f", ee->root_stack().top());
 		ee->root_stack().pop();
 		sign *= -1;
 	}
+
     if (sign == -1)
     {
-        //AssertMsg(ee->root_stack().top() == current_time(), 
-        //          "If sign is negative, we must be in the degenerate case");
         rLog(rlSimulator, "Popping the root because of negative sign (degeneracy)");
+        // rLog(rlSimulator, "Popping the root because of negative sign (degeneracy): %f", ee->root_stack().top());
+        // rLog(rlSimulator, "  Current time: %f", current_time());
+        // AssertMsg(ee->root_stack().top() == current_time(), 
+                 // "If sign is negative, we must be in the degenerate case");
         ee->root_stack().pop();
     }
 
@@ -57,7 +61,8 @@
         rLog(rlSimulator, "Root stack size: %i", ee->root_stack().size());
         rLog(rlSimulator, "Pushing: %s", tostring(ee->root_stack().top()).c_str());
     }
-	return queue_.push(ee);
+	Key k = queue_.push(ee);
+    return k;
 }
 		
 template<class FuncKernel_, template<class Event> class EventComparison_>
@@ -70,7 +75,7 @@
 	FunctionKernel::solve(f, ee->root_stack());
 	while (!ee->root_stack().empty() && ee->root_stack().top() < current_time())
 		ee->root_stack().pop();
-	update(k);
+	queue_.update(k);
 }
 
 template<class FuncKernel_, template<class Event> class EventComparison_>
@@ -86,23 +91,13 @@
     rLog(rlSimulator, "Processing event: %s", intostring(*e).c_str());
 	
 	current_ = e->root_stack().top(); e->root_stack().pop();
-	
+    queue_.update(top);
+
     // Get the top element out of the queue, put it back depending on what process() says
-    EventQueueS             tmp; tmp.prepend(top, queue_);
-
-	if (e->process(this))				{ queue_.prepend(top, tmp); update(top); }
-	else								{ delete e; }
+	if (!(e->process(this)))            { queue_.remove(top);  delete e; }
 
     ++count_;
 }
-
-template<class FuncKernel_, template<class Event> class EventComparison_>
-void
-Simulator<FuncKernel_, EventComparison_>::
-update(Key i)
-{
-	queue_.update(i);
-}
 		
 template<class FuncKernel_, template<class Event> class EventComparison_>
 typename Simulator<FuncKernel_, EventComparison_>::Time
@@ -115,6 +110,27 @@
 	if (e->root_stack().empty()) return current_ + 1;
 	else return FunctionKernel::between(e->root_stack().top(), current_);
 }
+
+template<class FuncKernel_, template<class Event> class EventComparison_>
+bool
+Simulator<FuncKernel_, EventComparison_>::
+audit_queue() const
+{
+	const_Key next = queue_.top();
+    const_Key cur = next++;
+	        
+    while (next != queue_.end())
+    {
+        if (IndirectEventComparison()(*next, *cur))
+        {
+            rError("Events [%s] and [%s] not in order", intostring(**cur).c_str(), intostring(**next).c_str());
+            queue_.print(std::cout, "  ");
+            return false;
+        }
+        cur = next++;
+    }
+    return true;
+}
 		
 template<class FuncKernel_, template<class Event> class EventComparison_>
 std::ostream&
--- a/include/topology/lsvineyard.h	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/topology/lsvineyard.h	Sun Feb 07 10:46:23 2010 -0800
@@ -153,6 +153,10 @@
 operator<<(std::ostream& out, const typename LSVineyard<V,VE,S,C>::VertexIndex& vi)    
 { return out << vi->vertex(); }
 
+template<class V, class VE, class S, class C>
+std::ostream& 
+operator<<(std::ostream& out, const typename LSVineyard<V,VE,S,C>::KineticVertexType& v)    
+{ return out << v.vertex(); }
 
 template<class V, class VE, class S, class C>
 class LSVineyard<V,VE,S,C>::KineticVertexType
--- a/include/topology/lsvineyard.hpp	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/topology/lsvineyard.hpp	Sun Feb 07 10:46:23 2010 -0800
@@ -123,7 +123,6 @@
     KineticSortDS       sort(vertices_.begin(), vertices_.end(), 
                              boost::bind(&LSVineyard::swap, this, bl::_1, bl::_2),
                              &simulator, traj);
-    AssertMsg(sort.audit(&simulator), "Sort audit should succeed");
     
     // Process all the events (compute the vineyard in the process)
     change_evaluator(new KineticEvaluator(*this, simulator, time_count_, traj));
@@ -134,7 +133,7 @@
         rLog(rlLSVineyardDebug, "Processed event");
     }
     rLog(rlLSVineyard, "Processed %d events", simulator.event_count());
-    AssertMsg(sort.audit(&simulator), "Sort audit should succeed");
+    // AssertMsg(sort.audit(&simulator), "Sort audit should succeed");
     
     veval_ = veval;
     change_evaluator(new StaticEvaluator(*this, ++time_count_));
@@ -149,7 +148,7 @@
     VertexIndex b = boost::next(a);
     rLog(rlLSVineyardDebug, "Entered swap");
     rLog(rlLSVineyardDebug, "Vertices: %d %d compare %d", a->vertex(), b->vertex(), vcmp_(a->vertex(), b->vertex()));
-    AssertMsg(!vcmp_(b->vertex(), a->vertex()), "In swap(a,b), a must precede b");
+    AssertMsg(!vcmp_(b->vertex(), a->vertex()), "In swap(a,b), a must precede b");      // true since we are using linear iterpolation
     AssertMsg(a < b, "In swap(a,b), a must precede b");
     transpose_vertices(a);
     AssertMsg(b < a, "In swap(a,b), b must precede a after the transposition");
--- a/include/utilities/eventqueue.h	Sat Feb 06 23:22:43 2010 -0800
+++ b/include/utilities/eventqueue.h	Sun Feb 07 10:46:23 2010 -0800
@@ -5,16 +5,20 @@
 #include <functional>
 #include <boost/utility.hpp>
 
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+namespace bmi = boost::multi_index;
+
+#include <utilities/log.h>
+#ifdef LOGGING
+static rlog::RLogChannel* rlEventQueue =             DEF_CHANNEL("utilities/eventqueue", rlog::Log_Debug);
+#endif // LOGGING
+
 #include <iostream>
-#include <cassert>					// TODO: switch to internal debugging system
 #include <string>
 #include <algorithm>
 
-// TODO: change inefficient list-based implementation to something heap-based
-// Need a queue that supports deleting arbitrary items (given by iterator), 
-// and maintaining correctness of iterators when different operations (notably 
-// remove and update are performed)
-
 template<class Event_, class EventComparison_>
 class EventQueue
 {
@@ -23,22 +27,29 @@
 		typedef					Event_											Event;
 		typedef					EventComparison_								EventComparison;
 
-		typedef					std::list<Event>								QueueRepresentation;
+        // Not actually a heap, but will work for now
+        typedef                 boost::multi_index_container<Event, 
+                                                             bmi::indexed_by<
+                                                                bmi::sequenced<>,
+                                                                bmi::ordered_non_unique<bmi::identity<Event>, EventComparison >
+                                                             > >
+                                                                                QueueRepresentation;
 		typedef					typename QueueRepresentation::iterator			iterator;
 		typedef					typename QueueRepresentation::const_iterator	const_iterator;
 		
 		EventQueue()			{}
 		
-		const_iterator 			top() const					{ assert(!empty()); return queue_.begin(); }
-		iterator 				top()						{ assert(!empty()); return queue_.begin(); }
-		iterator 				push(Event e)				{ queue_.push_front(e); iterator i = top(); update(i); return i; }
-		void 					pop()						{ assert(!empty()); queue_.erase(queue_.begin()); }
+		const_iterator 			top() const					{ AssertMsg(!empty(), "Queue must not be empty"); return queue_.begin(); }
+		iterator 				top()						{ AssertMsg(!empty(), "Queue must not be empty"); return queue_.begin(); }
+		// iterator 				push(Event e)				{ return queue_.insert(insert_position(e), e).first; }
+		iterator 				push(Event e)				{ iterator i = queue_.push_front(e).first; update(i); return i; }
+		void 					pop()						{ AssertMsg(!empty(), "Queue must not be empty"); queue_.erase(queue_.begin()); }
 		void					remove(iterator i)			{ queue_.erase(i); }
-		void					update(iterator i);
-        void                    prepend(iterator i, 
-                                        EventQueue& other)  { queue_.splice(queue_.begin(), other.queue_, i); }
-        ///< intended for temporary storage of elements from other queues
+        void                    replace(iterator i,
+                                        Event e)            { queue_.replace(i, e); update(i); }
 
+        iterator                begin()                     { return queue_.begin(); }
+        const_iterator          begin() const               { return queue_.begin(); }
 		iterator 				end()						{ return queue_.end(); }
 		const_iterator 			end() const					{ return queue_.end(); }
 		bool					empty() const				{ return queue_.empty(); }
@@ -46,24 +57,21 @@
 
 		std::ostream&			print(std::ostream& out, const std::string& prefix) const;
 
+        iterator                update(iterator i)
+        { 
+            iterator bg = bmi::project<0>(queue_, bmi::get<1>(queue_).lower_bound(*i)); 
+            iterator pos = std::find_if(bg, queue_.end(), std::bind1st(EventComparison(), *i));
+            queue_.replace(i, *i);
+            queue_.relocate(pos, i);
+            return pos; 
+        }
+
 	private:
 		QueueRepresentation		queue_;
 };
 
 
 template<class Event_, class EventComparison_>
-void
-EventQueue<Event_, EventComparison_>::
-update(iterator i)
-{
-	QueueRepresentation tmp;
-	tmp.splice(tmp.end(), queue_, i);
-	//iterator pos = std::find_if(queue_.begin(), queue_.end(), std::not1(std::bind2nd(EventComparison(), *i)));
-	iterator pos = std::find_if(queue_.begin(), queue_.end(), std::bind1st(EventComparison(), *i));
-	queue_.splice(pos, tmp);
-}
-
-template<class Event_, class EventComparison_>
 std::ostream&
 EventQueue<Event_, EventComparison_>::
 print(std::ostream& out, const std::string& prefix) const
--- a/tests/geometry/test-eventqueue.cpp	Sat Feb 06 23:22:43 2010 -0800
+++ b/tests/geometry/test-eventqueue.cpp	Sun Feb 07 10:46:23 2010 -0800
@@ -4,7 +4,7 @@
 
 int main()
 {
-	typedef EventQueue<int, std::less<int> >			EQ;
+	typedef EventQueue<int, std::less<int> >		    EQ;
 	typedef EQ::iterator								iterator;
 	 
 	EQ queue;
@@ -15,8 +15,7 @@
 	iterator j = queue.push(6);
 	queue.push(5);
 
-	*i = 8;
-	queue.update(i);
+	queue.replace(i,8);
 	queue.remove(j);
 
 	while (!queue.empty())
--- a/tests/geometry/test-ksort-linear.cpp	Sat Feb 06 23:22:43 2010 -0800
+++ b/tests/geometry/test-ksort-linear.cpp	Sun Feb 07 10:46:23 2010 -0800
@@ -55,6 +55,7 @@
     // Insert polynomials and sort the list for current time
     list.push_back(Function(2, -2));
     list.push_back(Function(1, 3));
+    list.push_back(Function(-1, 6));
     list.push_back(Function(2));
     list.push_back(Function(2, 2));
     //list.sort(EvaluatedComparison(simulator.current_time()));