[repacker] begin storing each nodes parents.

Will be used for connected component search.
This commit is contained in:
Garret Rieger 2021-09-24 15:58:57 -07:00
parent efda2f14e1
commit c77bdf1dcf
1 changed files with 87 additions and 45 deletions

View File

@ -41,7 +41,7 @@ struct graph_t
vertex_t () : vertex_t () :
distance (0), distance (0),
space (0), space (0),
incoming_edges (0), parents (),
start (0), start (0),
end (0), end (0),
priority(0) {} priority(0) {}
@ -51,14 +51,44 @@ struct graph_t
hb_serialize_context_t::object_t obj; hb_serialize_context_t::object_t obj;
int64_t distance; int64_t distance;
int64_t space; int64_t space;
unsigned incoming_edges; hb_vector_t<unsigned> parents;
unsigned start; unsigned start;
unsigned end; unsigned end;
unsigned priority; unsigned priority;
bool is_shared () const bool is_shared () const
{ {
return incoming_edges > 1; return parents.length > 1;
}
unsigned incoming_edges () const
{
return parents.length;
}
void remove_parent (unsigned parent_index)
{
for (unsigned i = 0; i < parents.length; i++)
{
if (parents[i] != parent_index) continue;
parents.remove (i);
break;
}
}
void remap_parents (const hb_vector_t<unsigned>& id_map)
{
for (unsigned i = 0; i < parents.length; i++)
parents[i] = id_map[parents[i]];
}
void remap_parent (unsigned old_index, unsigned new_index)
{
for (unsigned i = 0; i < parents.length; i++)
{
if (parents[i] == old_index)
parents[i] = new_index;
}
} }
bool is_leaf () const bool is_leaf () const
@ -131,7 +161,7 @@ struct graph_t
* serializer * serializer
*/ */
graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects) graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects)
: edge_count_invalid (true), : parents_invalid (true),
distance_invalid (true), distance_invalid (true),
positions_invalid (true), positions_invalid (true),
successful (true) successful (true)
@ -233,7 +263,7 @@ struct graph_t
hb_vector_t<unsigned> removed_edges; hb_vector_t<unsigned> removed_edges;
if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
update_incoming_edge_count (); update_parents ();
queue.push (root_idx ()); queue.push (root_idx ());
int new_id = vertices_.length - 1; int new_id = vertices_.length - 1;
@ -249,7 +279,7 @@ struct graph_t
for (const auto& link : next.obj.links) { for (const auto& link : next.obj.links) {
removed_edges[link.objidx]++; removed_edges[link.objidx]++;
if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx])) if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
queue.push (link.objidx); queue.push (link.objidx);
} }
} }
@ -259,7 +289,7 @@ struct graph_t
if (!check_success (new_id == -1)) if (!check_success (new_id == -1))
DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
remap_obj_indices (id_map, &sorted_graph); remap_all_obj_indices (id_map, &sorted_graph);
sorted_graph.as_array ().reverse (); sorted_graph.as_array ().reverse ();
@ -290,7 +320,7 @@ struct graph_t
hb_vector_t<unsigned> removed_edges; hb_vector_t<unsigned> removed_edges;
if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
update_incoming_edge_count (); update_parents ();
queue.insert (root ().modified_distance (0), root_idx ()); queue.insert (root ().modified_distance (0), root_idx ());
int new_id = root_idx (); int new_id = root_idx ();
@ -305,7 +335,7 @@ struct graph_t
for (const auto& link : next.obj.links) { for (const auto& link : next.obj.links) {
removed_edges[link.objidx]++; removed_edges[link.objidx]++;
if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx])) if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
// Add the order that the links were encountered to the priority. // Add the order that the links were encountered to the priority.
// This ensures that ties between priorities objects are broken in a consistent // This ensures that ties between priorities objects are broken in a consistent
// way. More specifically this is set up so that if a set of objects have the same // way. More specifically this is set up so that if a set of objects have the same
@ -321,7 +351,7 @@ struct graph_t
if (!check_success (new_id == -1)) if (!check_success (new_id == -1))
DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
remap_obj_indices (id_map, &sorted_graph); remap_all_obj_indices (id_map, &sorted_graph);
sorted_graph.as_array ().reverse (); sorted_graph.as_array ().reverse ();
@ -366,12 +396,12 @@ struct graph_t
*/ */
bool isolate_subgraph (unsigned root_idx) bool isolate_subgraph (unsigned root_idx)
{ {
update_incoming_edge_count (); update_parents ();
hb_hashmap_t<unsigned, unsigned> subgraph; hb_hashmap_t<unsigned, unsigned> subgraph;
// incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
// set the subgraph incoming edge count to match all of root_idx's incoming edges // set the subgraph incoming edge count to match all of root_idx's incoming edges
subgraph.set (root_idx, vertices_[root_idx].incoming_edges); subgraph.set (root_idx, vertices_[root_idx].incoming_edges ());
find_subgraph (root_idx, subgraph); find_subgraph (root_idx, subgraph);
hb_hashmap_t<unsigned, unsigned> index_map; hb_hashmap_t<unsigned, unsigned> index_map;
@ -381,7 +411,7 @@ struct graph_t
const auto& node = vertices_[entry.first]; const auto& node = vertices_[entry.first];
unsigned subgraph_incoming_edges = entry.second; unsigned subgraph_incoming_edges = entry.second;
if (subgraph_incoming_edges < node.incoming_edges) if (subgraph_incoming_edges < node.incoming_edges ())
{ {
// Only de-dup objects with incoming links from outside the subgraph. // Only de-dup objects with incoming links from outside the subgraph.
made_changes = true; made_changes = true;
@ -454,12 +484,13 @@ struct graph_t
clone->obj.tail = buffer->tail; clone->obj.tail = buffer->tail;
clone->distance = child.distance; clone->distance = child.distance;
clone->space = child.space; clone->space = child.space;
clone->incoming_edges = 0; clone->parents.reset ();
unsigned clone_idx = vertices_.length - 2;
for (const auto& l : child.obj.links) for (const auto& l : child.obj.links)
{ {
clone->obj.links.push (l); clone->obj.links.push (l);
vertices_[l.objidx].incoming_edges++; vertices_[l.objidx].parents.push (clone_idx);
} }
check_success (!clone->obj.links.in_error ()); check_success (!clone->obj.links.in_error ());
@ -468,10 +499,10 @@ struct graph_t
// The root's obj idx does change, however since it's root nothing else refers to it. // The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected. // all other obj idx's will be unaffected.
vertex_t root = vertices_[vertices_.length - 2]; vertex_t root = vertices_[vertices_.length - 2];
vertices_[vertices_.length - 2] = *clone; vertices_[clone_idx] = *clone;
vertices_[vertices_.length - 1] = root; vertices_[vertices_.length - 1] = root;
return vertices_.length - 2; return clone_idx;
} }
/* /*
@ -481,7 +512,7 @@ struct graph_t
*/ */
bool duplicate (unsigned parent_idx, unsigned child_idx) bool duplicate (unsigned parent_idx, unsigned child_idx)
{ {
update_incoming_edge_count (); update_parents ();
unsigned links_to_child = 0; unsigned links_to_child = 0;
for (const auto& l : vertices_[parent_idx].obj.links) for (const auto& l : vertices_[parent_idx].obj.links)
@ -489,7 +520,7 @@ struct graph_t
if (l.objidx == child_idx) links_to_child++; if (l.objidx == child_idx) links_to_child++;
} }
if (vertices_[child_idx].incoming_edges <= links_to_child) if (vertices_[child_idx].incoming_edges () <= links_to_child)
{ {
// Can't duplicate this node, doing so would orphan the original one as all remaining links // Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent. // to child are from parent.
@ -504,20 +535,19 @@ struct graph_t
unsigned clone_idx = duplicate (child_idx); unsigned clone_idx = duplicate (child_idx);
if (clone_idx == (unsigned) -1) return false; if (clone_idx == (unsigned) -1) return false;
// duplicate shifts the root node idx, so if parent_idx was root update it. // duplicate shifts the root node idx, so if parent_idx was root update it.
unsigned original_parent_idx = parent_idx;
if (parent_idx == clone_idx) parent_idx++; if (parent_idx == clone_idx) parent_idx++;
auto& clone = vertices_[clone_idx];
auto& child = vertices_[child_idx];
auto& parent = vertices_[parent_idx]; auto& parent = vertices_[parent_idx];
for (unsigned i = 0; i < parent.obj.links.length; i++) for (unsigned i = 0; i < parent.obj.links.length; i++)
{ {
auto& l = parent.obj.links[i]; auto& l = parent.obj.links[i];
if (l.objidx == child_idx) if (original_parent_idx != parent_idx)
{ vertices_[l.objidx].remap_parent (original_parent_idx, parent_idx);
l.objidx = clone_idx; if (l.objidx != child_idx)
clone.incoming_edges++; continue;
child.incoming_edges--;
} reassign_link (l, parent_idx, clone_idx);
} }
return true; return true;
@ -571,7 +601,7 @@ struct graph_t
{ {
if (!DEBUG_ENABLED(SUBSET_REPACK)) return; if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
update_incoming_edge_count (); update_parents ();
for (const auto& o : overflows) for (const auto& o : overflows)
{ {
const auto& parent = vertices_[o.parent]; const auto& parent = vertices_[o.parent];
@ -579,10 +609,10 @@ struct graph_t
DEBUG_MSG (SUBSET_REPACK, nullptr, DEBUG_MSG (SUBSET_REPACK, nullptr,
" overflow from %d (%d in, %d out) => %d (%d in, %d out)", " overflow from %d (%d in, %d out) => %d (%d in, %d out)",
o.parent, o.parent,
parent.incoming_edges, parent.incoming_edges (),
parent.obj.links.length, parent.obj.links.length,
o.child, o.child,
child.incoming_edges, child.incoming_edges (),
child.obj.links.length); child.obj.links.length);
} }
} }
@ -597,22 +627,20 @@ struct graph_t
/* /*
* Creates a map from objid to # of incoming edges. * Creates a map from objid to # of incoming edges.
*/ */
void update_incoming_edge_count () void update_parents ()
{ {
if (!edge_count_invalid) return; if (!parents_invalid) return;
for (unsigned i = 0; i < vertices_.length; i++) for (unsigned i = 0; i < vertices_.length; i++)
vertices_[i].incoming_edges = 0; vertices_[i].parents.reset ();
for (const vertex_t& v : vertices_) for (unsigned p = 0; p < vertices_.length; p++)
{ {
for (auto& l : v.obj.links) for (auto& l : vertices_[p].obj.links)
{ vertices_[l.objidx].parents.push (p);
vertices_[l.objidx].incoming_edges++;
}
} }
edge_count_invalid = false; parents_invalid = false;
} }
/* /*
@ -742,6 +770,20 @@ struct graph_t
} }
} }
/*
* Updates a link in the graph to point to a different object. Corrects the
* parents vector on the previous and new child nodes.
*/
void reassign_link (hb_serialize_context_t::object_t::link_t& link,
unsigned parent_idx,
unsigned new_idx)
{
unsigned old_idx = link.objidx;
link.objidx = new_idx;
vertices_[old_idx].remove_parent (parent_idx);
vertices_[new_idx].parents.push (parent_idx);
}
/* /*
* Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts. * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
*/ */
@ -756,9 +798,8 @@ struct graph_t
{ {
auto& link = vertices_[i].obj.links[j]; auto& link = vertices_[i].obj.links[j];
if (!id_map.has (link.objidx)) continue; if (!id_map.has (link.objidx)) continue;
vertices_[link.objidx].incoming_edges--;
link.objidx = id_map[link.objidx]; reassign_link (link, i, id_map[link.objidx]);
vertices_[link.objidx].incoming_edges++;
} }
} }
} }
@ -766,11 +807,12 @@ struct graph_t
/* /*
* Updates all objidx's in all links using the provided mapping. * Updates all objidx's in all links using the provided mapping.
*/ */
void remap_obj_indices (const hb_vector_t<unsigned>& id_map, void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
hb_vector_t<vertex_t>* sorted_graph) const hb_vector_t<vertex_t>* sorted_graph) const
{ {
for (unsigned i = 0; i < sorted_graph->length; i++) for (unsigned i = 0; i < sorted_graph->length; i++)
{ {
(*sorted_graph)[i].remap_parents (id_map);
for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++) for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
{ {
auto& link = (*sorted_graph)[i].obj.links[j]; auto& link = (*sorted_graph)[i].obj.links[j];
@ -830,7 +872,7 @@ struct graph_t
hb_vector_t<vertex_t> vertices_; hb_vector_t<vertex_t> vertices_;
private: private:
hb_vector_t<clone_buffer_t> clone_buffers_; hb_vector_t<clone_buffer_t> clone_buffers_;
bool edge_count_invalid; bool parents_invalid;
bool distance_invalid; bool distance_invalid;
bool positions_invalid; bool positions_invalid;
bool successful; bool successful;