solver: Replace dict with a proper object

Signed-off-by: Niels Thykier <niels@thykier.net>
ubuntu/rebased
Niels Thykier 6 years ago
parent 93f101bee2
commit cdcfe85bfa
No known key found for this signature in database
GPG Key ID: A65B78DBE67C7AAC

@ -21,6 +21,15 @@ from itertools import chain
from britney2.utils import (ifilter_only, iter_except) from britney2.utils import (ifilter_only, iter_except)
class OrderNode(object):
__slots__ = ['before', 'after']
def __init__(self):
self.after = set()
self.before = set()
def compute_scc(graph): def compute_scc(graph):
"""Iterative algorithm for strongly-connected components """Iterative algorithm for strongly-connected components
@ -35,7 +44,7 @@ def compute_scc(graph):
node_stack = [] node_stack = []
def _cannot_be_a_scc(graph_node): def _cannot_be_a_scc(graph_node):
if not graph[graph_node]['before'] or not graph[graph_node]['after']: if not graph[graph_node].before or not graph[graph_node].after:
# Short-cut obviously isolated component # Short-cut obviously isolated component
result.append((graph_node,)) result.append((graph_node,))
# Set the item number so high that no other item might # Set the item number so high that no other item might
@ -63,7 +72,7 @@ def compute_scc(graph):
continue continue
succ_num = len(low) succ_num = len(low)
low[succ] = succ_num low[succ] = succ_num
work_stack.append((succ, len(node_stack), succ_num, graph[succ]['before'])) work_stack.append((succ, len(node_stack), succ_num, graph[succ].before))
node_stack.append(succ) node_stack.append(succ)
# "Recurse" into the child node first # "Recurse" into the child node first
return True return True
@ -81,7 +90,7 @@ def compute_scc(graph):
low[n] = root_num low[n] = root_num
# DFS work-stack needed to avoid call recursion. It (more or less) # DFS work-stack needed to avoid call recursion. It (more or less)
# replaces the variables on the call stack in Tarjan's algorithm # replaces the variables on the call stack in Tarjan's algorithm
work_stack = [(n, len(node_stack), root_num, graph[n]['before'])] work_stack = [(n, len(node_stack), root_num, graph[n].before)]
node_stack.append(n) node_stack.append(n)
while work_stack: while work_stack:
node, stack_idx, orig_node_num, successors = work_stack[-1] node, stack_idx, orig_node_num, successors = work_stack[-1]
@ -132,17 +141,18 @@ def apply_order(key, relation, ptable, order, negative_relation, debug_solver, l
if other == key: if other == key:
# "Self-relation" => ignore # "Self-relation" => ignore
return return
order_key = order[key]
if negative_relation: if negative_relation:
order_key_fwd = 'before' order_key.before.add(other)
order_key_back = 'after' order[other].after.add(key)
debug_check = order_key.before
else: else:
order_key_fwd = 'after' order_key.after.add(other)
order_key_back = 'before' order[other].before.add(key)
if debug_solver and other not in order[key][order_key_fwd]: # pragma: no cover debug_check = order_key.after
if debug_solver and other not in debug_check: # pragma: no cover
cause = 'Conflict' if negative_relation else 'Conflict' cause = 'Conflict' if negative_relation else 'Conflict'
logger.debug("%s induced order: %s before %s", cause, key, other) logger.debug("%s induced order: %s before %s", cause, key, other)
order[key][order_key_fwd].add(other)
order[other][order_key_back].add(key)
class InstallabilitySolver(object): class InstallabilitySolver(object):
@ -207,16 +217,16 @@ class InstallabilitySolver(object):
other_rms.add(other) other_rms.add(other)
for other in (other_adds - other_rms): for other in (other_adds - other_rms):
if debug_solver and other != key and other not in order[key]['after']: # pragma: no cover if debug_solver and other != key and other not in order[key].after: # pragma: no cover
self.logger.debug("Dependency induced order (add): %s before %s", key, other) self.logger.debug("Dependency induced order (add): %s before %s", key, other)
order[key]['after'].add(other) order[key].after.add(other)
order[other]['before'].add(key) order[other].before.add(key)
for other in (other_rms - other_adds): for other in (other_rms - other_adds):
if debug_solver and other != key and other not in order[key]['before']: # pragma: no cover if debug_solver and other != key and other not in order[key].before: # pragma: no cover
self.logger.debug("Dependency induced order (remove): %s before %s", key, other) self.logger.debug("Dependency induced order (remove): %s before %s", key, other)
order[key]['before'].add(other) order[key].before.add(other)
order[other]['after'].add(key) order[other].after.add(key)
def _compute_group_order(self, groups, key2item): def _compute_group_order(self, groups, key2item):
universe = self._universe universe = self._universe
@ -231,7 +241,7 @@ class InstallabilitySolver(object):
for (item, adds, rms) in groups: for (item, adds, rms) in groups:
key = str(item) key = str(item)
key2item[key] = item key2item[key] = item
order[key] = {'before': set(), 'after': set()} order[key] = OrderNode()
going_in.update(adds) going_in.update(adds)
going_out.update(rms) going_out.update(rms)
for x in chain(adds, rms): for x in chain(adds, rms):
@ -271,13 +281,13 @@ class InstallabilitySolver(object):
if len(com) < 2: if len(com) < 2:
# Trivial case # Trivial case
continue continue
so_before = order[scc_id]['before'] so_before = order[scc_id].before
so_after = order[scc_id]['after'] so_after = order[scc_id].after
for n in com: for n in com:
if n == scc_id: if n == scc_id:
continue continue
so_before.update(order[n]['before']) so_before.update(order[n].before)
so_after.update(order[n]['after']) so_after.update(order[n].after)
merged[n] = scc_id merged[n] = scc_id
del order[n] del order[n]
if debug_solver: # pragma: no cover if debug_solver: # pragma: no cover
@ -285,22 +295,22 @@ class InstallabilitySolver(object):
for com in comps: for com in comps:
node = com[0] node = com[0]
nbefore = set(merged[b] for b in order[node]['before']) nbefore = set(merged[b] for b in order[node].before)
nafter = set(merged[b] for b in order[node]['after']) nafter = set(merged[b] for b in order[node].after)
# Drop self-relations (usually caused by the merging) # Drop self-relations (usually caused by the merging)
nbefore.discard(node) nbefore.discard(node)
nafter.discard(node) nafter.discard(node)
order[node]['before'] = nbefore order[node].before = nbefore
order[node]['after'] = nafter order[node].after = nafter
for com in comps: for com in comps:
scc_id = com[0] scc_id = com[0]
for other_scc_id in order[scc_id]['before']: for other_scc_id in order[scc_id].before:
order[other_scc_id]['after'].add(scc_id) order[other_scc_id].after.add(scc_id)
for other_scc_id in order[scc_id]['after']: for other_scc_id in order[scc_id].after:
order[other_scc_id]['before'].add(scc_id) order[other_scc_id].before.add(scc_id)
return scc return scc
@ -338,14 +348,14 @@ class InstallabilitySolver(object):
initial_round = [] initial_round = []
for com in sorted(order): for com in sorted(order):
if debug_solver and order[com]['before']: # pragma: no cover if debug_solver and order[com].before: # pragma: no cover
self.logger.debug("N: %s <= %s", com, str(sorted(order[com]['before']))) self.logger.debug("N: %s <= %s", com, str(sorted(order[com].before)))
if not order[com]['after']: if not order[com].after:
# This component can be scheduled immediately, add it # This component can be scheduled immediately, add it
# to the queue # to the queue
initial_round.append(com) initial_round.append(com)
elif debug_solver: # pragma: no cover elif debug_solver: # pragma: no cover
self.logger.debug("N: %s >= %s", com, str(sorted(order[com]['after']))) self.logger.debug("N: %s >= %s", com, str(sorted(order[com].after)))
queue.extend(sorted(initial_round, key=len)) queue.extend(sorted(initial_round, key=len))
del initial_round del initial_round
@ -355,18 +365,18 @@ class InstallabilitySolver(object):
self.logger.debug("-- LINEARIZED ORDER --") self.logger.debug("-- LINEARIZED ORDER --")
for cur in iter_except(queue.popleft, IndexError): for cur in iter_except(queue.popleft, IndexError):
if order[cur]['after'] <= emitted and cur not in emitted: if order[cur].after <= emitted and cur not in emitted:
# This item is ready to be emitted right now # This item is ready to be emitted right now
if debug_solver: # pragma: no cover if debug_solver: # pragma: no cover
self.logger.debug("%s -- %s", cur, sorted(scc_items[cur])) self.logger.debug("%s -- %s", cur, sorted(scc_items[cur]))
emitted.add(cur) emitted.add(cur)
result.append([key2item[x] for x in scc_items[cur]]) result.append([key2item[x] for x in scc_items[cur]])
if order[cur]['before']: if order[cur].before:
# There are components that come after this one. # There are components that come after this one.
# Add it to queue: # Add it to queue:
# - if it is ready, it will be emitted. # - if it is ready, it will be emitted.
# - else, it will be dropped and re-added later. # - else, it will be dropped and re-added later.
queue.extend(sorted(order[cur]['before'] - emitted, key=len)) queue.extend(sorted(order[cur].before - emitted, key=len))
if debug_solver: # pragma: no cover if debug_solver: # pragma: no cover
self.logger.debug("-- END LINEARIZED ORDER --") self.logger.debug("-- END LINEARIZED ORDER --")

Loading…
Cancel
Save