include/geometry/kinetic-sort.hpp
author Christos Mantoulidis <cmad@stanford.edu>
Tue, 04 Aug 2009 13:23:16 -0700
branchdev
changeset 156 f75fb57d2831
parent 66 6021ec481b1f
child 199 2bde4c56101c
permissions -rw-r--r--
Changed implementation of WeightedRips to store simplex values (max distance between simplices' vertices) as an invisible layer on top of each simplex object, so that the data() field of WeightedRips has been freed for use by the users again.

#include "utilities/log.h"
#include "utilities/counter.h"

#ifdef LOGGING
static rlog::RLogChannel* rlKineticSort =           DEF_CHANNEL("geometry/kinetic-sort", rlog::Log_Debug);
static rlog::RLogChannel* rlKineticSortAudit =      DEF_CHANNEL("geometry/kinetic-sort/audit", rlog::Log_Debug);
static rlog::RLogChannel* rlKineticSortSchedule =   DEF_CHANNEL("geometry/kinetic-sort/schedule", rlog::Log_Debug);
static rlog::RLogChannel* rlKineticSortProcess =    DEF_CHANNEL("geometry/kinetic-sort/process", rlog::Log_Debug);
#endif // LOGGING

#ifdef COUNTERS
static Counter*  cKineticSort =                     GetCounter("kinetic-sort");
static Counter*  cKineticSortSwap =                 GetCounter("kinetic-sort/swap");
#endif // COUNTERS


template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
KineticSort()
{}	

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
KineticSort(ElementIterator b, ElementIterator e, Swap swap, Simulator* simulator)
{
	initialize(b, e, swap, simulator);
}

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
initialize(ElementIterator b, ElementIterator e, Swap swap, Simulator* simulator)
{
	swap_ = swap;
	for (ElementIterator cur = b; cur != e; ++cur)
		list_.push_back(Node(cur, simulator->null_key()));
	schedule_swaps(list_.begin(), list_.end(), simulator);
}

/// Adds elements in the range [f,l) of the underlying data structure to the management by the KineticSort.
/// pos must be a valid iterator, i.e., it cannot be end().
template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
insert(iterator pos, ElementIterator f, ElementIterator l, Simulator* simulator)
{
	iterator previous = pos; --previous;
	if (previous != list_.end()) simulator->remove(previous->swap_event_key);

	ElementIterator cur = boost::next(previous)->element;
	while(cur != pos->element)
		list_.insert(pos->element, Node(cur++, simulator->null_key()));

	if (previous != list_.end()) 
		schedule_swaps(previous, pos, simulator);
	else
		schedule_swaps(list_.begin(), pos, simulator);
}

/// Removes pos from the KineticSort structure. Assumes that the element of the underlying data structure 
/// that *pos refers to has already been removed.
template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
erase(iterator pos, Simulator* simulator)
{
	simulator->remove(pos->swap_event_key);
	iterator prev = pos; --prev;
	list_.erase(pos);
	schedule_swaps(prev, simulator);
}

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
update_trajectory(iterator pos, Simulator* simulator)
{
	iterator prev = boost::prior(pos);
	if (prev != list_.end())
	{
		simulator->remove(prev->swap_event_key);
		schedule_swaps(prev, simulator);
	}

	if (boost::next(pos) != list_.end())
	{
		simulator->remove(pos->swap_event_key);
		schedule_swaps(pos, simulator);
	}
}


template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void						
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
swap(iterator pos, Simulator* simulator)
{
	// TODO: AssertMsg(boost::next(pos) != list_.end(), "Cannot swap the last element");

    Count(cKineticSortSwap);
	swap_(pos->element, simulator);

	// Remove events
	iterator prev = boost::prior(pos);
	if (prev != list_.end())
		simulator->remove(prev->swap_event_key);
	iterator next = boost::next(pos);
	simulator->remove(next->swap_event_key);

	// Swap
	list_.splice(pos, list_, next);
	
	// update events
	next->swap_event_key = pos->swap_event_key;
	static_cast<SwapEvent*>(*(next->swap_event_key))->set_position(next);
	schedule_swaps(prev, simulator);
	schedule_swaps(pos, simulator);
	//audit(simulator);
}

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
bool
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
audit(Simulator* simulator) const
{
	typedef 		typename Simulator::Function		        Function;
	typedef 		typename Simulator::Time					Time;
	
	Time t = simulator->audit_time();
	rLog(rlKineticSortAudit, "Auditing at %s", tostring(t).c_str());

	TrajectoryExtractor	te;
	
	typename NodeList::const_iterator next = list_.begin();
	typename NodeList::const_iterator cur = next++;
	Function cur_trajectory = te(cur->element);
	while (next != list_.end())
	{
		rLog(rlKineticSortAudit, "  %s", intostring(**(cur->swap_event_key)).c_str());

		Function next_trajectory = te(next->element);
		rLog(rlKineticSortAudit, "  Auditing:   %s, %s", tostring(cur_trajectory).c_str(),
                                                         tostring(next_trajectory).c_str());
		rLog(rlKineticSortAudit, "  Difference: %s", tostring(next_trajectory - cur_trajectory).c_str());
		rLog(rlKineticSortAudit, "  Sign at:    %s, %s", tostring(t).c_str(),
                                                         tostring(FunctionKernel::sign_at(next_trajectory - cur_trajectory, t)).c_str());
		if (FunctionKernel::sign_at(next_trajectory - cur_trajectory, t) == -1)
		{
			rError("Audit failed at %s, %s", tostring(*cur->element).c_str(), 
                                             tostring(*next->element).c_str());
			return false;
		}

		cur_trajectory = next_trajectory;
		cur = next++;
	}
	if (cur != list_.end()) rLog(rlKineticSortAudit, "  %s", intostring(**(cur->swap_event_key)).c_str());
	return true;
}

		
template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void						
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
schedule_swaps(iterator b, iterator e, Simulator* simulator)
{
	typedef 		typename Simulator::Function		        Function;
	
	TrajectoryExtractor	te;
	
	iterator next = b; 
	iterator cur = next++;
	Function cur_trajectory = te(cur->element);
	while (next != e)
	{
		Function next_trajectory = te(next->element);
		rLog(rlKineticSortSchedule, "Next trajectory: %s", tostring(next_trajectory).c_str());
		// TODO: add assertion that (next_trajectory - cur_trajectory)(s->curren_time()) > 0
		cur->swap_event_key = simulator->add(next_trajectory - cur_trajectory, SwapEvent(this, cur));
		cur = next++;
		cur_trajectory = next_trajectory;
	}
	if (cur != e) schedule_swaps(cur, simulator);
}

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
void						
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::
schedule_swaps(iterator i, Simulator* simulator)
{
	typedef 		typename Simulator::Function		        Function;
	
	if (i == list_.end()) return;
	if (boost::next(i) == list_.end())
	{
		i->swap_event_key = simulator->add(SwapEvent(this, i));
		return;
	}

	TrajectoryExtractor	te;
	
	iterator next = boost::next(i); 
	Function i_trajectory = te(i->element);
	Function next_trajectory = te(next->element);
	
	//std::cout << "Updating swaps for: " << i_trajectory << ", " << next_trajectory << std::endl;
	//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 */
template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
class KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::SwapEvent: public Simulator::Event
{
	public:
		typedef						typename Simulator::Event					Parent;

									SwapEvent(const SwapEvent& e):
										sort_(e.sort_), pos_(e.pos_)			{}
									SwapEvent(KineticSort* sort, iterator pos):
										sort_(sort), pos_(pos)					{}

		virtual bool				process(Simulator* s) const;
		void						set_position(iterator i)					{ pos_ = i; }
		iterator					position() const							{ return pos_; }
		std::ostream&				operator<<(std::ostream& out) const;

	private:
		KineticSort*				sort_;
		iterator					pos_;
};

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
bool
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::SwapEvent::
process(Simulator* s) const
{ 
	rLog(rlKineticSortProcess, "Swapping. Current time: %s", tostring(s->current_time()).c_str());
	sort_->swap(pos_, s); 
	return true; 
}

template<class ElementIterator_, class TrajectoryExtractor_, class Simulator_, class Swap_>
std::ostream&				
KineticSort<ElementIterator_, TrajectoryExtractor_, Simulator_, Swap_>::SwapEvent::
operator<<(std::ostream& out) const
{
	Parent::operator<<(out) << "SwapEvent at " << TrajectoryExtractor_()(position()->element);
	return out;
}