Skip to main content

Module foreign

Module foreign 

Source
Expand description

Reading and writing graphs in foreign file formats (igraph_foreign.h).

igraph can exchange graphs with other software through a number of textual (and one binary) file formats. This module wraps all of them, in two flavours:

  • file based: Graph::read_graph_*(path, ...) and graph.write_graph_*(path, ...) take anything implementing AsRef<Path> and open/close the file themselves (the file handle is always closed, also on errors, and write errors detected when flushing are reported);
  • in memory: Graph::read_graph_*_from_str(&str, ...) parses a string and graph.write_graph_*_to_string(...) returns the serialization as a String, without touching the file system (they use the POSIX fmemopen/open_memstream streams under the hood). igraph copies string attributes byte by byte, so a _to_string writer replaces invalid UTF-8 (only possible in attributes read from files in another encoding, e.g. Latin-1 Pajek labels) with U+FFFD: use the file based writer to keep the exact bytes.

On top of that, GraphFormat together with Graph::read_graph and Graph::write_graph offers a format-agnostic entry point, able to guess the format from the file extension (GraphFormat::from_path).

§Example

use igraph::{foreign::GmlWriteOptions, prelude::*};

// A directed triangle with a pendant vertex, serialized as an edge list...
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0), (2, 3)], 4, true).unwrap();
let text = g.write_graph_edgelist_to_string().unwrap();
assert_eq!(text, "0 1\n1 2\n2 0\n2 3\n");

// ...and parsed back: exactly the same graph.
let h = Graph::read_graph_edgelist_from_str(&text, 0, true).unwrap();
assert!(g.is_same_graph(&h).unwrap());

// GML round trip of Zachary's karate club, through a temporary file.
let karate = Graph::famous("Zachary").unwrap();
let path = std::env::temp_dir().join(format!("igraph-doc-foreign-{}.gml", std::process::id()));
karate.write_graph_gml(&path, &GmlWriteOptions::default()).unwrap();
let k = Graph::read_graph_gml(&path).unwrap();
std::fs::remove_file(&path).unwrap();
assert!(!k.is_directed());
assert_eq!(k, karate); // GML keeps vertex ids and edges

§Supported formats

FormatReadWriteAttributes (after attributes::enable)Notes
Edge listread_graph_edgelistwrite_graph_edgelistnonewhitespace separated 0-based vertex ids
NCOLread_graph_ncolwrite_graph_ncolvertex name, edge weightsymbolic (named) weighted edge list of the LGL software
LGLread_graph_lglwrite_graph_lglvertex name, edge weightadjacency-list-like, # vertex headers
Pajekread_graph_pajekwrite_graph_pajekname, x/y/z, color, bipartite type, edge weight, ….net files, 1-based ids
GraphMLread_graph_graphmlwrite_graph_graphml, write_graph_graphml_withall (typed, with defaults), node ids as vertex idXML; reading requires igraph built with libxml2; the in-memory writer write_graph_graphml_to_string takes the prefixattr flag of write_graph_graphml_with
GMLread_graph_gmlwrite_graph_gmlnumeric and string ones, numeric vertex idsee GmlWriteOptions
DIMACS flowread_graph_dimacs_flowwrite_graph_dimacs_flownone (capacities in DimacsFlow)max-flow / edge problems
graph databaseread_graph_graphdb—nonebinary, see read_graph_graphdb_from_bytes
UCINET DLread_graph_dl—vertex name, edge weightfull matrix, edge list and node list forms
Graphviz DOT—write_graph_dotalloutput only
LEDA—write_graph_ledaone vertex and one edge attributeoutput only

Every file based function has an in-memory twin with the _from_str / _to_string suffix (_from_bytes for the binary graph database format), taking the same arguments but the path. The one exception is GraphML: write_graph_graphml_to_string(prefixattr) is the twin of write_graph_graphml_with(path, prefixattr) (pass false for the behaviour of write_graph_graphml(path)). SafeLocale and with_safe_locale bind igraph’s locale helpers.

§Attributes

Many formats carry vertex names, edge weights and other attributes. igraph stores them through a pluggable, process-wide attribute handler, which is off by default and is turned on by attributes::enable (see the attributes module for the typed accessors):

  • without the handler, readers parse attributes (validating their syntax) but discard them: only the structure of the graph is returned. The options asking to store names or weights (NcolLglOptions) are accepted and harmless. Writers see no attribute: those asked to export a named one (e.g. the names/weights arguments of write_graph_ncol) emit an igraph warning (see take_warnings) and fall back to plain vertex ids, and GraphML/GML/DOT files are written without attributes;
  • with the handler (call enable before reading), readers store what they find in the file as graph, vertex and edge attributes (the “Attributes” column above), and the writers export the attributes of the graph. Values missing for some elements are NaN for numeric attributes, "" for strings and false for booleans, unless the format has its own defaults (a missing NCOL/LGL weight is 1, a GraphML <key> may declare a <default>, Pajek parameters take Pajek’s defaults, see the readers); GraphML and GML omit NaN values when writing.

What each format keeps, with the handler on (the individual readers and writers have the details):

FormatRead into attributesWritten from attributes
Edge list, DIMACS, graph databasenothingnothing
NCOL, LGLvertex name (string), edge weight (numeric), as selected by NcolLglOptionsthe vertex / edge attributes named by the names / weights arguments
UCINET DLvertex name (labels), edge weight (values)—
Pajekvertex name, x/y/z, color, shapes and the other Pajek parameters, bipartite type (boolean), edge weight and edge parametersthe attributes named after Pajek parameters; other attributes are ignored
GraphMLevery <key>, typed (boolean, numeric, string), for graph, vertices and edges; the node ids as the string vertex attribute idevery graph, vertex and edge attribute (typed keys), optionally prefixed (g_/v_/e_, write_graph_graphml_with)
GMLevery numeric or string field of the graph, node and edge records, including the numeric node idnumeric and string attributes (booleans as 0/1); a numeric vertex id supplies the node ids
DOT—every graph, vertex and edge attribute
LEDA—one vertex and one edge attribute, named in the call

Two GraphML caveats: the node ids land in a string id vertex attribute (unless a vertex key already defines an attribute named id), which the GraphML writer then exports as an ordinary <key>, so a second round trip carries it as data; and when the <edge> elements have ids, igraph 1.0.0 and 1.0.1 also create a string id edge attribute but, because of a bug in src/io/graphml.c, fill it with the node ids (in node order, padded with "" if there are more edges than nodes): don’t rely on it (delete it with remove_edge_attr if it gets in the way). See read_graph_graphml.

use igraph::{attributes, foreign::NcolLglOptions, prelude::*};

attributes::enable().unwrap(); // before reading!
let text = "rome paris 1420\nparis london 460\nlondon rome\n";
let g = Graph::read_graph_ncol_from_str(text, &[], &NcolLglOptions::default()).unwrap();
assert_eq!(g.vertex_attr_str_values("name", ..).unwrap(), ["rome", "paris", "london"]);
// A missing weight defaults to 1 when at least one edge has an explicit weight.
assert_eq!(g.edge_attr_numeric_values("weight", ..).unwrap(), [1420.0, 460.0, 1.0]);
// Writers use the attributes they are asked for.
let out = g.write_graph_ncol_to_string(Some("name"), Some("weight")).unwrap();
assert_eq!(out, "rome paris 1420\nparis london 460\nrome london 1\n");

Data that igraph returns through explicit output arguments does not need the handler, e.g. the capacities and source/target vertices of a DIMACS file, returned in DimacsFlow. When only the vertex naming of an NCOL file matters, the predefnames argument of read_graph_ncol fixes it without attributes: vertex i then is the i-th predefined name.

§Locale and threads

The parsers and writers assume that the C locale uses a decimal point. Rust programs start in the "C" locale, so nothing needs to be done unless some library called setlocale; in that case wrap the I/O with SafeLocale or with_safe_locale.

All the functions can be called from several threads at once (but see SafeLocale for platforms without per-thread locales). The GML reader of igraph 1.0.0 and 1.0.1 is not reentrant (it uses static buffers), and so is the default GML Creator line (it uses ctime): these wrappers serialize them internally with a process-wide lock.

§See also

The C documentation of the whole chapter is at https://igraph.org/c/html/latest/igraph-Foreign.html.

Structs§

DimacsFlow
The content of a DIMACS flow file, as returned by Graph::read_graph_dimacs_flow.
GmlWriteOptions
Options of the GML writer (Graph::write_graph_gml).
NcolLglOptions
Options of the NCOL and LGL readers (Graph::read_graph_ncol, Graph::read_graph_lgl).
SafeLocale
RAII guard temporarily switching the numeric locale to "C" (igraph_enter_safelocale / igraph_exit_safelocale).

Enums§

DimacsProblem
The problem described by a DIMACS file, see DimacsFlow.
GraphFormat
Graph file formats known to igraph, for the format-agnostic Graph::read_graph and Graph::write_graph.

Functions§

with_safe_locale
Runs f with the "C" numeric locale in effect, see SafeLocale.