Skip to content

Commit

Permalink
Do breadth first search
Browse files Browse the repository at this point in the history
  • Loading branch information
Sophia Castellarin committed Jul 31, 2019
1 parent 793e77b commit cb55739
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 2 deletions.
21 changes: 20 additions & 1 deletion conda/models/prefix_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,23 @@ def __init__(self, records, specs=()):
consolidated_graph[node.name] = cg
self.graph_by_name = consolidated_graph

def depth_first_search_by_name(self, root_spec, spec_name, allowed_specs):
def breadth_first_search_by_name(self, root_spec, spec_name):
"""Return shorted path from root_spec to spec_name"""
queue = []
queue.append([root_spec.name])
while queue:
path = queue.pop(0)
node = path[-1]
if node == spec_name:
return path
children = sorted(self.graph_by_name.get(node, set()),
key=lambda x: list(self.graph_by_name.keys()).index(x))
for adj in children:
new_path = list(path)
new_path.append(adj)
queue.append(new_path)

def depth_first_search_by_name(self, root_spec, spec_name):
"""Return paths from root_spec to spec_name"""
if root_spec.name == spec_name:
return [[root_spec]]
Expand All @@ -434,8 +450,11 @@ def build_dependency_chain(node, spc, chains=None):
return chains

chains = build_dependency_chain(root_spec.name, spec_name)
return chains

def get_dependency_chains(self, root_spec, spec_name, allowed_specs):
final_chains = []
chains = [self.breadth_first_search_by_name(root_spec, spec_name)]
for chain in sorted(chains, key=len):
if chain[0] == root_spec.name and chain[-1] == spec_name:
# remap to matchspecs
Expand Down
2 changes: 1 addition & 1 deletion conda/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def build_conflict_map(self, specs, specs_to_add=None, history_specs=None):
key=lambda x: list(g.graph_by_name.keys()).index(x.name))
for spec in spec_order:
# the DFS approach works well when things are actually in the graph
bad_deps.extend(g.depth_first_search_by_name(spec, dep, sdeps[spec]))
bad_deps.extend(g.get_dependency_chains(spec, dep, sdeps[spec]))

if not bad_deps:
# no conflicting nor missing packages found, return the bad specs
Expand Down
50 changes: 50 additions & 0 deletions tests/test_resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,56 @@ def test_unsat_simple():
assert "b -> c[version='>=2,<3']" in str(excinfo.value)


def test_unsat_shortest_chain():
index = (
simple_rec(name='a', depends=['d', 'c <1.3.0']),
simple_rec(name='b', depends=['c']),
simple_rec(name='c', version='1.3.6',),
simple_rec(name='c', version='1.2.8',),
simple_rec(name='d', depends=['c >=0.8.0']),
)
r = Resolve(OrderedDict((prec, prec) for prec in index))
with pytest.raises(UnsatisfiableError) as excinfo:
r.install(['c=1.3.6', 'a', 'b'])
assert "a -> c[version='<1.3.0']" in str(excinfo.value)
assert "b -> c" in str(excinfo.value)
assert "c=1.3.6" in str(excinfo.value)


def test_unsat_shortest_reverse_chain():
index = (
simple_rec(name='a', depends=['d', 'c >=0.8.0']),
simple_rec(name='b', depends=['c']),
simple_rec(name='c', version='1.3.6',),
simple_rec(name='c', version='1.2.8',),
simple_rec(name='d', depends=['c <1.3.0']),
)
r = Resolve(OrderedDict((prec, prec) for prec in index))
with pytest.raises(UnsatisfiableError) as excinfo:
r.install(['c=1.3.6', 'a', 'b'])
assert "a -> d -> c[version='<1.3.0']" in str(excinfo.value)
assert "b -> c" in str(excinfo.value)
assert "c=1.3.6" in str(excinfo.value)


def test_unsat_shortest_long_chain():
index = (
simple_rec(name='a', depends=['f', 'e']),
simple_rec(name='b', depends=['c']),
simple_rec(name='c', version='1.3.6',),
simple_rec(name='c', version='1.2.8',),
simple_rec(name='d', depends=['c >=0.8.0']),
simple_rec(name='e', depends=['c <1.3.0']),
simple_rec(name='f', depends=['d']),
)
r = Resolve(OrderedDict((prec, prec) for prec in index))
with pytest.raises(UnsatisfiableError) as excinfo:
r.install(['c=1.3.6', 'a', 'b'])
assert "a -> e -> c[version='<1.3.0']" in str(excinfo.value)
assert "b -> c" in str(excinfo.value)
assert "c=1.3.6" in str(excinfo.value)


def test_unsat_chain():
# a -> b -> c=1.x -> d=1.x
# e -> c=2.x -> d=2.x
Expand Down

0 comments on commit cb55739

Please sign in to comment.