Graphs and NetworkX

This tutorial will demonstrate how one can use WLPlan for various graph-related procedures:

  • converting planning problems and states into graphs,

  • converting WLPlan graphs into NetworkX graphs, and

  • visualising WLPlan graphs.

We will assume that you have gone through and ran the code for the introductory tutorial which sets up the environment and constructs the dataset required for this tutorial. The corresponding notebook for this tutorial is available here.

We begin by importing the necessary packages and loading the dataset from the previous tutorial.

[ ]:
# NetworkX draw requires matplotlib
%pip install matplotlib

import pickle
import matplotlib.pyplot as plt
import networkx as nx
from wlplan.graph_generator import init_graph_generator, to_networkx, from_networkx

# We assume we have generated the dataset from the introductory tutorial and load it
with open("wlplan-blocks.pkl", "rb") as f:
    domain, dataset, y = pickle.load(f)

Initialising a Graph Generator

In the following two lines of code, we initialise a graph generator and use it to convert the entire dataset into a list of graphs. The specific graph representation we will use for representing planning problems is the Instance Learning Graph (ILG) introduced in Definition 3.1 of the ICAPS paper Return to Tradition: Learning Reliable Heuristics with Classical Machine Learning. Informally, the ILG nodes represent objects, true facts, and goals in the problem, with edges connecting objects to facts and goals they are instantiated in. An ILG subgraph of a Blocksworld problem is illustrated as follows:

82a78423aa7740999ff8ee274aff6371

[ ]:
graph_generator = init_graph_generator(graph_representation="ilg", domain=domain)
graphs = graph_generator.to_graphs(dataset)

You can view some basic attributes of the graph or dump it to console entirely.

[ ]:
graph = graphs[20]

print(f"{graph=}")
print(f"{graph.node_colours=}")
print(f"{graph.edges=}")

graph.dump()

Converting to and from NetworkX

NetworkX is a Python package with various useful graph manipulation algorithms. WLPlan has two simple functions for transforming its graph classes into NetworkX graphs and vice versa. Note that this means you can construct your own custom graphs for use with WLPlan to generate features.

[ ]:
G = to_networkx(graph)

print(f"{G.nodes=}")
print(f"{G.edges=}")
print(f"{nx.diameter(G)=}")

back_to_wlplan_graph = from_networkx(G)

print(f"{back_to_wlplan_graph=}")
print(f"{back_to_wlplan_graph.node_colours=}")
print(f"{back_to_wlplan_graph.edges=}")

Visualising WLPlan Graphs

We can make use of NetworkX and Matplotlib to do the heavy lifting and give us the options for visualising graphs.

[ ]:
pos = nx.bipartite_layout(G)  # objects on one side, atoms on the other
cmap = plt.cm.cool  # brighter colours
nx.draw(
    G,
    pos,
    with_labels=True,
    cmap=cmap,
    edge_cmap=cmap,
    node_color=[G.nodes[n]["colour"] for n in G.nodes],
    edge_color=[G.edges[e].get("relation") for e in G.edges],
    node_size=800,
)
plt.show()