-
Notifications
You must be signed in to change notification settings - Fork 40
Example codes
This page shows several examples with Graphillion.
- Congested roads - edge inclusion and exclusion
- Ekillion - weighted edges and vertices
- Collection of path sets
- Network reliability
- Impact of universe list
- Vertex list representation of path and cycle
This problem is found in the entrance exam to Hokkaido University, 2014; the original version is here (4th question).
Consider paths from S (21) to G (5) with eight edges (i.e., least edge paths). Each edge requires two minutes to pass through, but edge 'a' (17,18) takes one minute and edge 'b' (10,15) is eight minutes.
1 --- 2 --- 3 --- 4 --- G
| | | | |
6 --- 7 --- 8 --- 9 -- 10
| | | | : b
11 -- 12 -- 13 -- 14 -- 15
| | | | |
16 -- 17 == 18 -- 19 -- 20
| | a | | |
S -- 22 -- 23 -- 24 -- 25
- How many paths are there that pass through edge 'a'?
- How many paths are there that pass through edge 'b' without 'a'?
- How long does it take from S to G on average?
from graphillion import GraphSet
import graphillion.tutorial as tl
GraphSet.set_universe(tl.grid(4, 4))
S, G, a, b, L = 21, 5, (17,18), (10,15), 8
paths = GraphSet.paths(S, G).len(L)
print('1.', len(paths.including(a)))
print('2.', len(paths.excluding(a).including(b)))
def average_time(paths):
t = 0.
for p in paths:
for e in p:
if e == a: t += 1
elif e == b: t += 8
else : t += 2
return t / len(paths)
print('3.', average_time(paths))
The least edge constraint is indispensable to allow test-takers to count the paths efficiently by manual with the binomial coefficient, but Graphillion allows us to solve this problem without the constraint, as follows.
paths = GraphSet.paths(S, G) # without least edge constraint
print("1.", len(paths.including(a)))
print("2.", len(paths.excluding(a).including(b)))
print("3.", average_time(paths))
We examine a key algorithm of Ekillion, which is a Web service enumerating all train paths between a given pair of stations.
Assume the following railway map, in which distances between stations are shown in parentheses, and lunch boxes are sold at Shinjuku and Yotsuya stations.
+--(11.3)------------------------- Ueno
| |
| (3.6)
| |
Shinjuku --(3.7)-- Yotsuya --(6.6)-- Tokyo
| |
| (6.8)
| |
+--(10.6)-------------------- Shinagawa
- How many paths are there from Tokyo to Shinagawa?
- Find the most longest path from Tokyo to Shinagwa.
- Find a path going by Yotsuya from Tokyo to Shinagwa.
- Find a path with most lunch stations from Tokyo to Shinagwa.
from graphillion import GraphSet
universe = [('Tokyo' , 'Shinagawa', 6.8),
('Shinagawa', 'Shinjuku' , 10.6),
('Shinjuku' , 'Ueno' , 11.3),
('Ueno' , 'Tokyo' , 3.6),
('Tokyo' , 'Yotsuya' , 6.6),
('Yotsuya' , 'Shinjuku' , 3.7)]
GraphSet.set_universe(universe)
paths = GraphSet.paths('Tokyo', 'Shinagawa')
print('1.', len(paths))
print('2.', paths.max_iter().next())
print('3.', paths.including('Yotsuya').choice())
# Since weights have to be set on vertices, not edges like the above,
# for indicating lunch stations, we give weights on edges of lunch
# stations as follows.
#
# +--(0.5)------------------------ Ueno
# | |
# | (0)
# | |
# Shinjuku --(1)-- Yotsuya --(0.5)-- Tokyo
# | |
# | (0)
# | |
# +--(0.5)------------------- Shinagawa
lunch_weights = {}
lunch_stations = ['Shinjuku', 'Yotsuya']
for e in universe:
e = (e[0], e[1]) # remove distance
lunch_weights[e] = 0.5 * len([v for v in lunch_stations if v == e[0] or v == e[1]])
print('4.', paths.max_iter(lunch_weights).next())
The low-level GraphSet constructor named graphs()
can specify arbitrary complicated graph types. With this constructor, find all sets of a path between 1 and 5 and another path between 21 and 25, as follows.
1 2 3 4 5
| |
6 --- 7 --- 8 9 -- 10
| |
11 -- 12 13 -- 14 15
| |
16 17 18 19 -- 20
| | | |
21 22 -- 23 -- 24 25
from graphillion import GraphSet
import graphillion.tutorial as tl
GraphSet.set_universe(tl.grid(4, 4))
degree_constraints = {}
for v in range(1, 26):
if v == 1 or v == 5 or v == 21 or v == 25:
degree_constraints[v] = 1 # degree of vertex v is one
else:
degree_constraints[v] = range(0, 3, 2) # zero or two
path_sets = GraphSet.graphs(vertex_groups=[(1, 5), (21, 25)],
degree_constraints=degree_constraints,
no_loop=True)
print(len(path_sets))
This problem examines an impact of the universe edge list on the memory/storage footprint.
4--8
/
2--5
/
1
\
3--6
\
7
We consider the above tree as our universe, and enumerate subtrees with the following constraints; these subtrees must consist of two or more edges, and they must include at least one of edges (1,2) and (2,4).
Find the best order of the universe edge list in terms of the memory/storage footprint, with the Monte-Carlo method by randomly sorting the universe edge list.
from graphillion import GraphSet
from random import shuffle
universe = [(1,2), (1,3), (2,4), (2,5), (3,6), (3,7), (4,8)]
best = { 'list': None, 'footprint': 99999 }
for _ in range(100):
shuffle(universe)
GraphSet.set_universe(universe, traversal='as-is') # without re-ordering the universe list
trees = GraphSet.trees().larger(1);
trees = trees.including((1,2)) | trees.including((2,4))
footprint = len(trees.dumps()) # size of internal representation
if footprint < best['footprint']:
best = { 'list': universe, 'footprint': footprint }
print(best['list'])
Given a set of vertices and probabilities of link availability, we calculate the probability such that all the vertices in the set are connected.
Consider the following graph, which has five vertices and six edges. Each link would be available with probability of 0.9.
1 --- 2 --- 4
| | |
+---- 3 --- 5
Graphillion tells us that three vertices, 1, 3, and 4 are connected with probability of 0.967383, as follows.
from graphillion import GraphSet
GraphSet.set_universe([(1,2), (1,3), (2,3), (2,4), (3,5), (4,5)])
# find all subgraphs that connect vertices 1, 3, and 4
gs = GraphSet({}).including(GraphSet.connected_components([1,3,4]))
# calculate the probability such that any of the subgraphs happens.
probabilities = {(1,2): .9, (1,3): .9, (2,3): .9, (2,4): .9, (3,5): .9, (4,5): .9}
print(gs.probability(probabilities))
Graphillion represents a path or a cycle as a set of edges, like [(1, 2), (2, 3), (3, 4)]
, or as a NetworkX graph object. However, you might like to simply use a vertex list, [1, 2, 3, 4]
, to represent a path or a cycle. A set of edges and NetworkX graph object can be easily converted into a simple vertex list, as follows.
import networkx as nx
E = [(1, 2), (2, 3), (3, 4)] # set of edges, representing path
G = nx.Graph(E) # NetworkX graph object
print(list(nx.dfs_preorder_nodes(G, 1))) # [1, 2, 3, 4]