20 #ifndef INCLUDE_MOLASSEMBLER_ORDER_DISCORVERY_HELPER
21 #define INCLUDE_MOLASSEMBLER_ORDER_DISCORVERY_HELPER
23 #include "boost/graph/adjacency_list.hpp"
24 #include "boost/graph/graphviz.hpp"
30 namespace Molassembler {
43 using DependencyGraphType = boost::adjacency_list<
64 using VertexIndexType =
typename DependencyGraphType::vertex_descriptor;
67 std::map<T, VertexIndexType> sourceMap_;
68 DependencyGraphType graph_;
88 std::vector<VertexIndexType>
91 using Iterator =
typename DependencyGraphType::vertex_iterator;
94 std::tie(iter, end) = boost::vertices(graph_);
97 auto outDegree = boost::out_degree(*iter, graph_);
99 if(degreeToSetMap.count(outDegree) == 0) {
100 degreeToSetMap[outDegree] = {*iter};
102 degreeToSetMap.at(outDegree).push_back(*iter);
114 [&](
const auto& mapIterPair) -> std::vector<T> {
117 [&](
const auto& index) -> T {
118 return graph_[index].data;
125 VertexIndexType addItem_(
const T& item) {
126 auto newIndex = boost::add_vertex(graph_);
128 graph_[newIndex].data = item;
145 void operator() (std::ostream& os)
const {
146 os <<
"graph [fontname = \"Arial\", layout = \"dot\"];\n"
147 <<
"node [fontname = \"Arial\", shape = circle, style = filled];\n"
148 <<
"edge [fontname = \"Arial\"];\n";
151 void operator() (std::ostream& os,
const VertexIndexType& vertexIndex)
const {
152 os << R
"([label=")" << baseRef_.graph_[vertexIndex].data << R"("])";
155 void operator() (std::ostream& ,
const typename DependencyGraphType::edge_descriptor& )
const {
170 template<
typename Container>
173 std::begin(container),
189 std::map<VertexIndexType, VertexIndexType> vertexMapping;
191 for(VertexIndexType i = 0; i < boost::num_vertices(other.graph_); ++i) {
193 const auto& vertexData = other.graph_[i].data;
194 if(sourceMap_.count(vertexData) > 0) {
195 vertexMapping.emplace(
197 sourceMap_.at(vertexData)
204 auto edgeIterPair = boost::edges(other.graph_);
205 edgeIterPair.first != edgeIterPair.second;
208 auto otherEdgeSource = boost::source(*edgeIterPair.first, other.graph_);
209 auto otherEdgeTarget = boost::target(*edgeIterPair.first, other.graph_);
212 vertexMapping.count(otherEdgeSource) > 0
213 && vertexMapping.count(otherEdgeTarget) > 0
215 auto thisEdgeSource = vertexMapping.at(otherEdgeSource);
216 auto thisEdgeTarget = vertexMapping.at(otherEdgeTarget);
219 auto thisGraphEdge = boost::edge(
226 if(thisGraphEdge.second) {
231 auto inverseGraphEdge = boost::edge(
237 if(inverseGraphEdge.second) {
238 throw "Contradicting information in other OrderDiscoveryHelper graph!";
242 boost::add_edge(thisEdgeSource, thisEdgeTarget, graph_);
247 addTransferabilityEdges();
262 std::map<VertexIndexType, VertexIndexType> vertexMapping;
265 for(VertexIndexType i = 0; i < boost::num_vertices(other.graph_); ++i) {
267 const auto& vertexData = other.graph_[i].data;
268 if(sourceMap_.count(vertexData) == 0) {
269 auto newIndex = addItem_(other.graph_[i].data);
270 vertexMapping.emplace(
275 vertexMapping.emplace(
277 sourceMap_.at(vertexData)
284 auto edgeIterPair = boost::edges(other.graph_);
285 edgeIterPair.first != edgeIterPair.second;
288 auto otherEdgeSource = boost::source(*edgeIterPair.first, other.graph_);
289 auto otherEdgeTarget = boost::target(*edgeIterPair.first, other.graph_);
291 auto thisEdgeSource = vertexMapping.at(otherEdgeSource);
292 auto thisEdgeTarget = vertexMapping.at(otherEdgeTarget);
295 auto thisGraphEdge = boost::edge(
302 if(thisGraphEdge.second) {
307 auto inverseGraphEdge = boost::edge(
313 if(inverseGraphEdge.second) {
314 throw "Contradicting information in other OrderDiscoveryHelper graph!";
318 boost::add_edge(thisEdgeSource, thisEdgeTarget, graph_);
321 addTransferabilityEdges();
334 for(VertexIndexType i = 0; i < boost::num_vertices(graph_); ++i) {
335 std::vector<VertexIndexType> seeds;
338 auto edgeIterPair = boost::out_edges(i, graph_);
339 edgeIterPair.first != edgeIterPair.second;
343 boost::target(*edgeIterPair.first, graph_)
348 std::vector<VertexIndexType> newSeeds;
350 for(
const auto& seed: seeds) {
351 if(!boost::edge(i, seed, graph_).
second) {
352 boost::add_edge(i, seed, graph_);
356 auto edgeIterPair = boost::out_edges(seed, graph_);
357 edgeIterPair.first != edgeIterPair.second;
360 newSeeds.emplace_back(
361 boost::target(*edgeIterPair.first, graph_)
366 seeds = std::move(newSeeds);
367 }
while(!seeds.empty());
376 template<
typename It>
378 if(boost::num_vertices(graph_) > 0) {
384 for(; iter != end; ++iter) {
393 template<
typename Container>
397 Temple::Traits::getValueType<Container>,
400 "Container value must match OrderDiscoveryHelper's template argument T"
404 std::begin(container),
417 return getSetsByDegree_();
428 return Temple::copy_if(
430 [](
const auto& set) ->
bool {
431 return set.size() > 1;
441 auto N = boost::num_vertices(graph_);
443 return(boost::num_edges(graph_) == N * (N - 1) / 2);
471 GraphvizWriter propertyWriter(*
this);
473 std::stringstream ss;
475 boost::write_graphviz(
498 if(sourceMap_.count(a) == 0 || sourceMap_.count(b) == 0) {
503 auto smallerEdge = boost::edge(sourceMap_.at(a), sourceMap_.at(b), graph_);
504 return smallerEdge.second;
std::vector< std::vector< T > > getUndecidedSets() const
Returns grouped data (in descending order) whose internal order is undecided.
Definition: OrderDiscoveryHelper.h:426
void setUnorderedValues(It iter, const It end)
Range-abstracted.
Definition: OrderDiscoveryHelper.h:377
Definition: OrderDiscoveryHelper.h:39
auto map_stl(const Container< T, Dependents< T >...> &container, UnaryFunction &&function)
Definition: Functional.h:73
Container aiding in gradual discovery of order.
Definition: OrderDiscoveryHelper.h:37
std::vector< std::vector< T > > getSetsByDegree_() const
Get a grouped list of the ordered data sorted by out_degree ascending.
Definition: OrderDiscoveryHelper.h:77
std::string dumpGraphviz() const
Dumps a graphviz string for visualization of relationships.
Definition: OrderDiscoveryHelper.h:470
std::vector< std::vector< T > > getSets() const
Get a list of sets (in descending order) as currently discovered.
Definition: OrderDiscoveryHelper.h:415
constexpr Get< 1 > second
Calls std::get<1> on any argument it is invoked with.
Definition: Functor.h:125
void addRelationshipsFromOther(const OrderDiscoveryHelper &other)
Transfer relationships from another OrderDiscoveryHelper.
Definition: OrderDiscoveryHelper.h:187
bool isTotallyOrdered() const
Returns whether the total order has been discovered or not.
Definition: OrderDiscoveryHelper.h:440
void addAllFromOther(const OrderDiscoveryHelper &other)
Adds vertices and edges from another instance, then adds transferability edges.
Definition: OrderDiscoveryHelper.h:260
void setUnorderedValues(Container &&container)
Container-abstracted.
Definition: OrderDiscoveryHelper.h:394
constexpr auto map(const ArrayType< T, size > &array, UnaryFunction &&function)
Maps all elements of any array-like container with a unary function.
Definition: Containers.h:63
void addTransferabilityEdges()
Adds missing transferability edges.
Definition: OrderDiscoveryHelper.h:333
Definition: OrderDiscoveryHelper.h:138
OrderDiscoveryHelper(const Container &container)
Arbitrary container constructor.
Definition: OrderDiscoveryHelper.h:171
bool isSmaller(const T &a, const T &b) const
Check if a value is smaller than another.
Definition: OrderDiscoveryHelper.h:497
Functional-style container-related algorithms.
void addLessThanRelationship(const T &a, const T &b)
Add a less-than relationship to the graph.
Definition: OrderDiscoveryHelper.h:450