Commit c0020617 authored by Yoann Dufresne's avatar Yoann Dufresne
Browse files

simple transitive reduction done

parent 122475c5
import networkx as nx
from itertools import combinations
from d2_path import Path, Unitig
""" Remove unnecessary transitions
def transitive_reduction(d2g):
nxg = d2g.nx_graph
edges = list(nxg.edges())
# Remove self edges
for edge in edges:
if edge[0] == edge[1]:
nb_removed = 0
for edge in edges:
# Extract dgs
dg1 = d2g.nodes[edge[0]]
dg2 = d2g.nodes[edge[1]]
# Extract common neighbors
nei1 = frozenset(nxg.neighbors(d2g.nodes.inverse[dg1]))
nei2 = frozenset(nxg.neighbors(d2g.nodes.inverse[dg2]))
common = nei1.intersection(nei2)
# Look for all the common neighbors, if edge must be remove or not
current_dist = d2g.distances[dg1.idx][dg2.idx]
for node in common:
com_dg = d2g.nodes[node]
extern_dist = d2g.distances[dg1.idx][com_dg.idx] + d2g.distances[com_dg.idx][dg2.idx]
# If better path, remove the edge
if extern_dist <= current_dist:
# Remove from graph
# Remove in distances
del d2g.distances[dg1.idx][dg2.idx]
if len(d2g.distances[dg1.idx]) == 0:
del d2g.distances[dg1.idx]
del d2g.distances[dg2.idx][dg1.idx]
if len(d2g.distances[dg2.idx]) == 0:
del d2g.distances[dg2.idx]
nb_removed += 1
print(f"{nb_removed} edge removed")
print(f"{len(nxg.edges())} remaining")
""" For each node of the d2 graph, construct a node in the reducted graph.
Then, for each node, compute the closest neighbors in d2 (with equal scores) and add an edge
in the greedy graph.
......@@ -76,12 +76,15 @@ class D2Graph(object):
# Extract d-graphs from nx graph
self.all_d_graphs = []
self.node_by_idx = {}
self.nodes = {}
for idx, node in enumerate(self.nx_graph.nodes()):
dg = Dgraph.load(node, self.graph)
self.nodes[node] = dg
if dg.idx == -1:
dg.idx = idx
self.node_by_idx[dg.idx] = dg
self.nodes = bidict(self.nodes)
# Extract edges and re-compute distances
self.distances = {}
#!/usr/bin/env python3
import networkx as nx
import argparse
import sys
import d2_graph as d2
import d2_algorithms as d2a
def parse_arguments():
parser = argparse.ArgumentParser(description='Reduce the number of edges of a d2 graph. The reduction is performed on edges that are redundant.')
parser.add_argument('barcode_graph', help='The barcode graph file. Must be a gefx formated file.')
parser.add_argument('d2_graph', help='d2 graph to reduce. Must be a gefx formated file.')
parser.add_argument('--output_d2_name', '-o', default="transitively_reduced_d2.gexf", help="Output file prefix.")
args = parser.parse_args()
return args
def main():
# Parsing the arguments and validate them
args = parse_arguments()
barcode_file = args.barcode_graph
d2_file = args.d2_graph
if (not barcode_file.endswith('.gexf')) or (not d2_file.endswith(".gexf")):
print("Inputs file must be gexf formatted", file=sys.stderr)
# Loading
G = nx.read_gexf(barcode_file)
d2g = d2.D2Graph(G)
# Algorithms for reduction
# Write the simplificated graph
nx.write_gexf(d2g.nx_graph, args.output_d2_name)
if __name__ == "__main__":
......@@ -29,13 +29,18 @@ class Dgraph(object):
# Head parsing
head = head.split(' ')
dg = Dgraph(int(head[-3]))
center = head[-3]
if not center in barcode_graph:
center = int(center)
dg = Dgraph(center)
if len(head) == 4:
dg.idx = int(head[0])
# Reload halves
h1 = [int(x.split(' ')[-2]) for x in h1.split(',')]
h2 = [int(x.split(' ')[-2]) for x in h2.split(',')]
h1 = [x.split(' ')[-2] for x in h1.split(',')]
h1 = [int(x) if not x in barcode_graph else x for x in h1]
h2 = [x.split(' ')[-2] for x in h2.split(',')]
h2 = [int(x) if not x in barcode_graph else x for x in h2]
dg.put_halves(h1, h2, barcode_graph)
return dg
......@@ -23,6 +23,7 @@ def main():
filename = args.barcode_graph
if not filename.endswith('.gexf'):
print("Input file must be gexf formatted", file=sys.stderr)
G = nx.read_gexf(filename)
# Index size must be changed for general purpose. 8 is good for d=5
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment