{
"cells": [
{
"cell_type": "markdown",
"id": "bde34bab-b2cb-4e5e-bcb6-c7e1d8056bad",
"metadata": {},
"source": [
"# heterograph: basics"
]
},
{
"cell_type": "markdown",
"id": "d591d6de-00f6-4245-9064-c0e8879e737b",
"metadata": {},
"source": [
"## overview\n",
"\n",
"Heterograph is a Python graph library designed to capture model descriptions, from neural network architectures to software programs. It provides a uniform program abstraction for both analysis and manipulation.\n",
"\n",
"Built on top of [graph-tool](https://graph-tool.skewed.de/), a scalable and fast graph library with a core engine written in C++, Heterograph extends graph-tool by adding several unique features:\n",
"\n",
"- **Persistent Identifiers**: Ensures that vertices and edges retain their identifiers across sessions.\n",
"- **Custom Neighbor Ordering**: Allows ordering between input and output neighbors of any vertex.\n",
"- **Read-Only Graphs**: Enables the creation of graphs that cannot be modified, ensuring data integrity.\n",
"- **Property Maps**: Captures arbitrary data for graphs, vertices, and edges, enhancing the ability to store and retrieve complex information.\n",
"- **Graph Styles**: Facilitates the creation of richly styled graphs for better visualization and interpretation.\n",
"- **Web App Visualization**: Provides tools for visualizing graphs within a web application, making it easier to explore and understand graph structures interactively."
]
},
{
"cell_type": "markdown",
"id": "f9bfc671-bf0e-454b-8acf-66b1e97932ac",
"metadata": {},
"source": [
"## creating a graph\n",
"\n",
"To create a graph, we import `heterograph` module and instantiate `HGraph` class as follows:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c6ceb7f2-a9cf-406b-b622-196b971aba36",
"metadata": {},
"outputs": [],
"source": [
"from heterograph import *\n",
"g = HGraph() # create HGraph"
]
},
{
"cell_type": "markdown",
"id": "2fc1fba4-ee0a-41f8-82b9-eb69a41759f6",
"metadata": {},
"source": [
"## vertices\n",
"\n",
"Each vertex in `HGraph` is identified by an integer. It remains persistent and unique within the graph, even if other parts of the graph are changed. Therefore, the vertex ID can be safely used as an index. \n",
"\n",
"### adding vertices\n",
"\n",
"To add one or more vertices, we use `add_vx` and specify `n` - the number of vertices to add:\n",
"- if `n == 1` (or no argument is specified): one vertex is added, returning the vertex ID as an integer.\n",
"- if `n > 1`: `n` vertices are added, returning a list of corresponding vertex IDs."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "4af6d829-a199-4148-a364-e61243c77ccb",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_vx() # adds one vertex, identified by ID 0"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "6760e22a-33ed-46bb-8b22-9fed13492d61",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 2, 3, 4]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_vx(4) # adds two vertices, identified by IDs 1 to 3"
]
},
{
"cell_type": "markdown",
"id": "17abbea6-a02e-47e9-8228-9a7f64845f99",
"metadata": {},
"source": [
"### removing vertices\n",
"\n",
"To remove one or more vertices, we use `rm_vx(vs, verify=True)` and specify either the vertex ID (`int`) or a `list` of vertex IDs to be removed. By default, the `verify` parameter is set to `True`, meaning that any vertex ID not found raises an exception. Otherwise, any vertex not found is ignored.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c2a88389-9fe3-475f-8f96-5d590cc6ab79",
"metadata": {},
"outputs": [],
"source": [
"g.rm_vx(0) # remove vertex 0"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b29a08c6-ad4f-434b-a560-809b04bbbc39",
"metadata": {},
"outputs": [],
"source": [
"g.rm_vx([3,4]) # remove vertices 3 and 4"
]
},
{
"cell_type": "markdown",
"id": "475c57a4-d3f6-417d-9f81-34c47ca8ca88",
"metadata": {},
"source": [
"### listing vertices\n",
"To retrieve the list of available vertices, we use the `vertices` property."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "dc0d9dde-519b-45ad-82f0-345c01aac9bc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 2]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.vertices"
]
},
{
"cell_type": "markdown",
"id": "c61339e5-123f-492f-99d4-3956ac2c4880",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"### checking vertices\n",
"\n",
"To verify whether a vertex (or a set of vertices) exists, we utilize the `check_vx(vs, verify=False)` method. By default, it returns `True` if all specified vertices exist and `False` otherwise. However, when the `verify` parameter is set to `True`, it raises an exception if any vertex is not found. This is particularly useful in pre-condition checks."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b085b9e8-ebf5-4dd8-a6d5-c32ce317c816",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.check_vx(1)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "c557dd87-66d4-4a7e-934c-e31741c3520e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.check_vx([0, 1])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "a11ebb90-8c79-4bd4-b7a6-bc94b57e8d21",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"pre-check failed!\n"
]
}
],
"source": [
"try:\n",
" g.check_vx([0, 1], verify=True)\n",
"except:\n",
" print(\"pre-check failed!\")"
]
},
{
"cell_type": "markdown",
"id": "65989607-8c4c-4cee-aaae-1c5d238178b9",
"metadata": {},
"source": [
"## edges\n",
"\n",
"An edge connects a source vertex `s` to a target vertex `t` and is identified by the tuple `(s, t)`, where `s` and `t` represent the vertex IDs. The following types of edges are not supported by `HGraph`:\n",
"- self-loop edges, i.e., `(vx, vx)`, where an edge has the same source and target vertex.\n",
"- two edges with the same source and target. Hence, `(s, t)` uniquely identifies an edge.\n",
"\n",
"### adding edges\n",
"\n",
"To add one or more edges, we use the `add_edge(s, t)` method:\n",
"- both `s` and `t` can be either integers or lists of integers denoting vertex IDs.\n",
"- a cartesian product is performed if either `s` or `t` are lists.\n",
"- ignores if edge is a self-loop `(s, s)` or if edge already exists\n",
"- returns a list of added edge IDs "
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "02eaf34f-719c-4513-846a-1403ddee52c7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(0, 1), (0, 2)]"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g=HGraph()\n",
"g.add_vx(5)\n",
"g.add_edge(0, [1,2])"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "ec2a01ec-83d5-46f9-92fa-79352cd26e90",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(1, 3), (2, 3)]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_edge([1,2], 3)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "6a452701-4189-473b-a56e-9a5fdd9a593a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(3, 4)]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_edge(3, 4)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "69541927-eddd-4a5c-b80e-42d607927962",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_edge(3, 3) # ignores if self-loop"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "7a0b7030-806d-4e74-9739-3db80a1edb19",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.add_edge(3, 4) # ignores if adding an existing edge"
]
},
{
"cell_type": "markdown",
"id": "28b04e19-fc70-46fb-8388-8b0a6119afbb",
"metadata": {},
"source": [
"### removing edges\n",
"\n",
"To remove one or more edge, we use `rm_edge(edge, verify=True)` and specify either an edge ID (tuple `(s, t)`) or a list of edge IDs to be removed. By default, the `verify` parameter is set to `True`, meaning that any edge ID not found raises an exception. Otherwise, any edge not found is ignored."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "971589c4-4fba-4931-b36b-cbc4435c9f46",
"metadata": {},
"outputs": [],
"source": [
"g.rm_edge((3, 4))"
]
},
{
"cell_type": "markdown",
"id": "1b0f0509-221a-417d-b847-3c565321440d",
"metadata": {},
"source": [
"### listing edges"
]
},
{
"cell_type": "markdown",
"id": "3a64b290-cd40-4d7e-885b-ebcf3de76923",
"metadata": {},
"source": [
"To retrieve the list of available edges, we use the `edges` property."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "6dd7568c-0b85-4ae8-b234-16c26901729f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(0, 1), (0, 2), (1, 3), (2, 3)]"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.edges"
]
},
{
"cell_type": "markdown",
"id": "e6eb341c-fdc0-40f0-a664-9e3095d30a91",
"metadata": {},
"source": [
"### checking edges\n",
"\n",
"To verify whether an edge (or a set of edges) exists, we utilize the `check_edge(vs, verify=False)` method. By default, it returns `True` if all specified edges exist and `False` otherwise. However, when the `verify` parameter is set to `True`, it raises an exception if any edge is not found. This is particularly useful in pre-condition checks."
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "8f40de3b-c593-4576-a96c-97f8f1f8fdcc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.check_edge((3, 4))"
]
},
{
"cell_type": "markdown",
"id": "16292cc7-972d-4e13-afb5-b5c022e0ca0e",
"metadata": {},
"source": [
"### neighbours\n",
"\n",
"To return adjacent vertices of a vertex `vx`, use the `in_vx(vx)` method for input vertices (vertices that have an edge pointing to `vx`) and the `out_vx(vx)` method for output vertices (vertices that `vx` points to)."
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "265df97b-9544-4b50-9196-7b1332884736",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(0, 1), (0, 2)]"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g=HGraph()\n",
"g.add_vx(3)\n",
"g.add_edge(0, [1,2])"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "8d64b47d-77fa-4e84-9ae4-6d2c74735890",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.in_vx(1)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "c96d513e-6b57-46da-8fb6-4eabbd34cc82",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1, 2]"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g.out_vx(0)"
]
},
{
"cell_type": "markdown",
"id": "081b4047-6257-49ef-8720-6d863a91a6de",
"metadata": {},
"source": [
"## visualizing a graph\n",
"\n",
"To visualize a graph, use the `view(host='0.0.0.0', port='8888')` method. This launches a web app that can be accessed at `http://localhost:8888`. The web app allows to zoom and pan the graph for detailed examination. When this method is invoked inside a Jupyter Notebook, the graph is displayed directly within the notebook. More details about visualisation can be found [here](./4-hgraph-visualisation.ipynb).\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "d75b7c0b-e673-4eff-95e1-886912bdcd14",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"g.view()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.1.undefined"
}
},
"nbformat": 4,
"nbformat_minor": 5
}