Optimised plug dirty propagation.

In the case of plugs which affected multiple outputs, which then themselves affected multiple outputs and so on, we were doing far more work than necessary, because we were not pruning propagation when revisiting a plug via another path. We now build a boost::graph of dirtied plugs, prune duplicate propagation, and use a topological sort at the end to find the appropriate emission order, rather than repeatedly reordering the dirty list during propagation.

This reduces the execution time for the slightly diabolical test case from 17 seconds to practically nothing.