"""Reading graph files (read_graph_from_file) and one-time start-up (warm_up)."""
import networkx as nx
from _orbitsi_core import read_graph
from .arraygraph import ArrayGraph
from .graphindex import GraphIndex
[docs]
def read_graph_from_file(filepath, build_index=True):
"""Read a graph file into a NetworkX graph.
The file is parsed in C++ straight into arrays (see :doc:`/file_format`). The result is an
:class:`orbitsi.arraygraph.ArrayGraph`: a :class:`networkx.Graph` whose node and adjacency
dictionaries are built only when first used.
Parameters
----------
filepath : str or os.PathLike
Path to the graph file.
build_index : bool, default True
Also build the graph's integer index (:class:`orbitsi.graphindex.GraphIndex`), its
neighbour-label frequencies and the C++ core's copy (:func:`orbitsi.core.data_graph`), so
that their cost is paid here and not by the first pattern searched; also runs
:func:`warm_up` once per process.
Returns
-------
networkx.Graph
The undirected graph, with each node's label in its ``'label'`` attribute.
Raises
------
ValueError
If a ``v`` or ``e`` line has a missing or non-integer field, or an integer outside 64 bits.
"""
with open(filepath, "rb") as f:
data = f.read()
G = ArrayGraph(arrays=read_graph(data))
del data
if build_index:
from .core import data_graph
GraphIndex.of(G).nlf_table()
data_graph(G)
warm_up()
return G
_warm = False
[docs]
def warm_up():
"""Pay one-time library start-up costs now.
Runs filtering, ordering and counting once on a tiny graph with both backends, so that one-time
start-up (NumPy's first sort sets up its SIMD dispatch, about 50 ms; the first calls of other
array routines and of the C++ extensions) is paid at load, not by the first pattern. Does
nothing after its first call in a process.
"""
global _warm
if _warm:
return
_warm = True
from .orbit import EVOKEOrbitCounter
from .search import OrbitSIEngine
G = nx.Graph([(0, 1), (1, 2), (2, 0), (2, 3), (3, 4), (4, 1)])
nx.set_node_attributes(G, {v: v % 2 for v in G.nodes}, "label")
P = G.subgraph([0, 1, 2, 3]).copy()
for backend in ("cpp", "python"):
OrbitSIEngine(G, EVOKEOrbitCounter, order_method="core", backend=backend).count(P)