OpenBI Docs Buy

Open Graph

Open Graph is the graph library inside OpenBI: Norway Analytics’ own C library for networks, from building a graph to centrality, communities, paths, flows and layouts. It has every function of igraph 1.0’s C interface, under the og_ prefix, and this reference describes each one.

What Open Graph is

Open Graph is written in C11 by Norway Analytics and ships inside OpenBI from OpenBI Studio 0.3.76: the engine’s OAX network functions run on it, in OpenBI Studio and on OpenBI Server.

It is API-compatible with igraph 1.0’s C interface. All 1,088 functions, types and macros of that interface are here, under the same names with og_ in place of igraph_ (and OG_ in place of IGRAPH_), taking the same arguments in the same order, with the same meaning. A program written for igraph’s C interface moves to Open Graph by renaming.

Every C name in Open Graph starts with og_ (OG_ for constants and macros) because C has no namespaces: the prefix keeps Open Graph’s names apart from those of every other library a program uses. These pages leave it off where they name an entry, so og_betweenness is shown as betweenness and the macro OG_MATRIX as MATRIX; values without an entry of their own, such as the error code OG_EINVAL, are written in full. Each entry’s signature, its example and its C name line give the full name, and the search and the All functions filter find an entry by either name, or by its igraph name.

It was written clean room: from descriptions of what each function must do, the papers and textbooks behind the algorithms, and the answers python-igraph 1.0 gives when it is run. python-igraph served only as a black box, an oracle whose answers the tests compare with; no line of igraph’s source code was read.

Beyond igraph’s interface, Open Graph has four extensions of its own: a thread layer, SIMD kernels, the Jacobian, which measures how sensitive a centrality is to each edge’s weight, and the rollup, which multiplies along every path from a set of starts and adds the paths up.

The reference

The reference has a page per area. Every entry gives the C signature, what the function does, its parameters, what it returns, its errors and its time complexity, how it is checked, whether it uses threads or SIMD, its igraph name, and related entries.

PageWhat it coversEntries
Graph basicsMaking a graph, changing it and reading its structure; the vertex and edge selectors and iterators most functions take; errors, warnings, memory and random numbers.118
AttributesValues kept on a graph, its vertices and its edges.57
Deterministic generatorsGraphs built by a rule rather than by chance: from edge lists and matrices, regular shapes and lattices, trees, degree sequences and named graphs.37
Random graphsRandom graph models: uniform random graphs and block models, preferential attachment and other growth models, degree sequences and fitness, rewiring, and geometric graphs.35
Components and structureConnectivity and components, cut vertices and bridges, percolation, spanning trees, self-loops and multi-edges, cores and trusses, density and degree summaries, and the graph as a matrix.50
Paths and distancesDistances and shortest paths with and without weights, path statistics such as diameter and eccentricity, widest paths, efficiency, neighbourhoods and Voronoi cells.40
CentralityDegree and strength, closeness and harmonic centrality, betweenness, eigenvector centrality, hubs and authorities, PageRank, Burt's constraint, local scan statistics and centralization.37
Similarity, transitivity and mixingHow alike vertices are, how clustered the graph is, how vertices mix by degree or type, the Laplacian, and matchings.29
Community detectionModularity and comparing partitions, and the community detection methods.23
Cliques, independent sets and colouringCliques and maximal cliques, weighted cliques, independent vertex sets, graph colouring and perfect graphs, and vertex separators.33
Cycles, motifs and epidemicsCycles and cycle bases, acyclic graphs and feedback sets, Eulerian paths, triangles and census counts, motifs, graphlets, and the SIR epidemic model.30
Flows, cuts and traversalMaximum flows, minimum cuts, connectivity and disjoint paths, dominator trees, breadth-first and depth-first search, and random walks.28
Operators and bipartite graphsBipartite graphs, unions, intersections and differences, subgraphs, and products and other transformations.36
IsomorphismWhether two graphs are the same up to relabelling, subgraph isomorphism, automorphisms and canonical labellings, and the isomorphism classes of small graphs.29
LayoutsCoordinates for drawing a graph in 2D and 3D: simple shapes, force-directed layouts, trees and layered drawings, distance-based layouts, and merging and aligning layouts.31
Spatial graphs and numbersGraphs from points in the plane or in space (Delaunay, Gabriel, nearest neighbours, beta skeletons), convex hulls, random samples, power-law fits, and comparing numbers with a tolerance.22
Reading and writing filesReading and writing graphs as edge lists and in the NCOL, LGL, GraphML, GML, Pajek, DIMACS, graph database, DL, DOT and LEDA formats.20
Hierarchical random graphs and progressHierarchical random graphs.23
Linear algebra and embeddingsSpectral embeddings, and the dense linear algebra Open Graph uses itself: vector and matrix products, LU solves, dense eigenvalue problems and iterative eigensolvers.23
VectorsThe growable arrays Open Graph's functions take and return: vectors of real numbers and their integer, Boolean, character and complex twins, and vectors of pointers.112
Matrices, stacks, queues and heapsDense matrices stored column by column, three-dimensional arrays, and the stack, double-ended queue and heap containers.126
Sparse matricesSparse matrices in triplet or column-compressed form.74
String vectors, lists and bit setsString vectors, lists of vectors, adjacency and incidence lists (also built on demand), prefix-sum trees for weighted sampling, and bit sets.109
Jacobian ExtensionAn extension of Open Graph's own.14
Rollup ExtensionAn extension of Open Graph's own: totals along every path from a set of starts, loops refused or solved - bills of materials, ownership, cost allocation, input-output.6
Threads ExtensionAn extension of Open Graph's own: how many threads its parallel functions may use, and how a host lends its own thread pool.7
SIMD ExtensionAn extension of Open Graph's own: which vector instructions its kernels run on.2
Binary interface ExtensionAn extension of Open Graph's own.11

All functions lists the 1,162 entries on one page, with a filter.

How it is checked

Each entry has a badge that says how it was checked. Open Graph’s tests compare it with python-igraph 1.0 on the edge cases (the empty graph, a single vertex, isolated vertices, self-loops, multi-edges, directed and undirected graphs, weights of zero and none at all) and, for the deterministic functions, on hundreds of seeded random graphs each, and require the same error code for the same mistake.

BadgeEntriesWhat it means
Exact421The same answer as python-igraph 1.0: integers and orders exactly, real numbers within 1e-10 of each other (1e-12 near zero), and the same error code for the same mistake.
Within tolerance56An iterative method (an eigenvector, PageRank's solvers, a layout from given start positions): python-igraph 1.0's answer within the tolerance the entry states.
Same quality79A method that draws random numbers in its own way: for one seed another answer than igraph's, of the same quality, measured over many seeds (modularity, code length, the spread of a distribution).
Unit tests587Nothing in python-igraph to compare with (containers, memory, handlers, the thread and SIMD extensions, the Jacobian's betweenness margins): checked by Open Graph's own tests.
Exact Extension14Open Graph's own, with nothing in python-igraph to compare with: the same as their own reference, as each entry says. Here the Jacobian's types, defaults, measure names, smoothness classes and warnings, as in Norway Analytics' earlier Jacobian tool (in C#), which Open Graph's Jacobian ports and extends; the rollup's types and defaults, by their definitions.
Within tolerance Extension5Open Graph's own, with nothing in python-igraph to compare with: their own reference's answer within the tolerance each entry states. Here the Jacobian's derivatives, compared with Norway Analytics' earlier Jacobian tool (in C#) and with finite differences; the rollup's totals, compared with an independent reference (exact fractions, every path counted, dense solves) and with Statistics Norway's and Statistics Finland's published input-output inverses.

community_fastgreedy and feedback_arc_set are marked Partial: they work and are tested, but do not yet give python-igraph's answer in every case. Their entries say where they differ.

Community detection and OpenBI 0.3.75

From OpenBI 0.3.76, OpenBI’s network analysis runs on Open Graph, Norway Analytics’ own library. Open Graph draws its random numbers as igraph does (the same generator, PCG32, seeded the same way), and Louvain, Leiden and label propagation use those numbers in igraph’s order and break ties as igraph does. So for the same seed they find the same communities, and so do walktrap and edge betweenness, which draw nothing: NETWORK.COMMUNITIES gave the same communities as OpenBI 0.3.75 with these five methods on the networks we compared.

From OpenBI 0.3.77, the NETWORK.* functions number a network’s nodes by their values, where earlier versions numbered them in the order the rows came (see NETWORK.NODES). Rows that come in another order now give the same communities, ties and drawings. As the methods visit the nodes in that order, a community can come out otherwise than in 0.3.76: a ring of twelve nodes, for one, was split one way for its rows in order and another way for them reversed, and is now split the same way for both.

Two methods can differ from 0.3.75:

  • Infomap computes its own logarithms, so that Windows and macOS agree to the last bit. Its partitions are of the same quality as igraph’s (their code lengths as short or shorter in our tests), but for a given seed not always the same partition.
  • Fast greedy follows igraph’s order of merges on most small networks, but on large networks, and where gains are tied, it can merge in another order and so find other communities.

Layouts

A layout is a drawing, not an answer, and they differ by design. Layouts that follow a rule (circle, star, grid, sphere, the Reingold-Tilford trees) give igraph’s coordinates. Fruchterman-Reingold, Kamada-Kawai, GraphOpt and MDS agree with igraph within tolerance when they start from the same positions. Layouts that draw random numbers as they go (DrL, GEM, Davidson-Harel, LGL, UMAP and others) make drawings of the same quality with other coordinates. A drawing from NETWORK.LAYOUT can therefore place the nodes differently from 0.3.75, and, with the nodes numbered by their values, from 0.3.76.

The same answer everywhere

Open Graph gives the same answer, to the last bit, wherever it runs:

  • At any number of threads. A parallel function cuts its work into pieces that don’t depend on how many threads there are, and adds floating-point results in one fixed order.
  • On every CPU path. Plain C, AVX2 and AVX-512 on x64 processors, NEON on ARM64 processors such as Apple silicon: every SIMD kernel adds its numbers in one fixed order.
  • On Windows and macOS. Open Graph is built without fused multiply-adds, so a * b + c is rounded the same way by both compilers, and it computes its own logarithms where an answer depends on their last bit (Infomap).
  • For a given seed. Randomised functions draw from Open Graph’s own generator, one per thread, so a seed gives one answer on every machine.

The tests run every function at 1, 2, 3, 4, 8 and 16 threads, with the tasks also in reverse and in scrambled order, on every SIMD path the processor has, on Windows (MSVC) and on macOS (Apple clang), and compare the answers bit for bit.

Threads and SIMD

Threads

Threads are off by default: every function runs on the thread that calls it. set_num_threads lets the parallel functions use more (0 means every logical processor), and set_executor lends them a host’s own thread pool. OpenBI’s engine lends its own thread pool and lets Open Graph use all of its threads. Functions that can use threads have the Threads badge.

The 46 entries that can use threads: distances, distances_cutoff, distances_dijkstra, distances_dijkstra_cutoff, distances_johnson, average_path_length, path_length_hist, diameter, eccentricity, radius, graph_center, global_efficiency, closeness, harmonic_centrality, closeness_cutoff, harmonic_centrality_cutoff, betweenness, edge_betweenness, betweenness_cutoff, edge_betweenness_cutoff, betweenness_subset, edge_betweenness_subset, centralization_betweenness, centralization_closeness, similarity_jaccard, similarity_jaccard_pairs, similarity_jaccard_es, similarity_dice, similarity_dice_pairs, similarity_dice_es, community_infomap, triad_census, motifs_randesu, motifs_randesu_no, motifs_randesu_estimate, layout_kamada_kawai, layout_kamada_kawai_3d, layout_reingold_tilford, layout_reingold_tilford_circular, roots_for_tree_layout, jacobian_column, jacobian_row, jacobian_top_k, jacobian_full, jacobian_betweenness_margins, rollup.

SIMD

The SIMD kernels pick their path once, at first use, from what the processor and the operating system support: AVX-512, AVX2, NEON or plain C. simd_path says which one runs; the environment variable OG_SIMD (scalar, avx2, avx512 or neon) chooses a lower path, to compare paths on one machine. Functions that use the kernels have the SIMD badge.

The 29 entries whose inner loops run on the SIMD kernels: reachability, count_reachable, transitive_closure, eigenvector_centrality, hub_and_authority_scores, centralization_eigenvector_centrality, similarity_jaccard, similarity_dice, layout_drl, layout_drl_3d, layout_fruchterman_reingold, layout_kamada_kawai, layout_mds, adjacency_spectral_embedding, laplacian_spectral_embedding, blas_ddot, blas_dnrm2, blas_dgemv, blas_dgemm, blas_dgemv_array, lapack_dsyevr, lapack_dgeev, lapack_dgeevx, arpack_rssolve, arpack_rnsolve, bitset_or, bitset_and, bitset_xor, bitset_popcount.

The Jacobian extension

How much does a node’s centrality change when one link’s weight changes? The Jacobian, J[i][e], the derivative of vertex i’s centrality with respect to edge e’s weight, answers that for PageRank, eigenvector centrality, strength, betweenness, closeness and harmonic centrality.

The derivatives are exact by default, worked out from each measure’s own equations; finite differences are there to compare with. Closeness and harmonic centrality are piecewise linear in the weights and betweenness is piecewise constant, so at ties the Jacobian gives both one-sided derivatives and marks the tie, and jacobian_betweenness_margins tells how far each weight can move before any betweenness changes. In OAX, NETWORK.SENSITIVITY runs on it.

The rollup extension

How many spokes do 500 bikes need, at two wheels a bike and 36 spokes a wheel? What share of a company does an owner really hold, through the companies in between? rollup answers both kinds of question, new in OpenBI Studio 0.3.78: each edge carries a coefficient (a quantity per unit, a share, a cost rate) and each start an amount, and a vertex’s total is the start’s amount times the coefficients along each path to it, every path added up.

  • Several edges between one pair add up exactly, and a coefficient may be negative (a by-product).
  • Where edges loop back, the loops are refused, with one cycle named (a bill of materials must have none), or solved exactly, as cross-holdings, reciprocal cost allocation and input-output tables need. A loop that doesn’t converge is an error that names it.
  • Each vertex gets a level: the most edges from a start, a loop counted as one stop.
  • Each start’s own totals on request, a row per start and vertex (rollup_options_t), worked out in parallel with the same bits at any number of threads.

It is checked against an independent reference (exact fractions, every path counted, dense solves) and reproduces Statistics Norway’s and Statistics Finland’s published Leontief inverses from their published flows. In OAX, NETWORK.ROLLUP runs on it, and in a notebook’s C#, Graph.Rollup (In notebooks).

Conventions

Open Graph keeps igraph’s conventions, so its functions read alike. Graph basics has the details.

Types

A graph is an og_t, directed or undirected, with vertices numbered from 0 to n − 1 and edges numbered from 0 in the order they were added. Ids and counts are og_int_t, a signed 64-bit integer; real numbers are og_real_t (double), truth values og_bool_t, and complex numbers og_complex_t, a pair of reals.

Errors

A function that can fail returns an og_error_t: OG_SUCCESS (0), or the code for what went wrong, with igraph’s numbers (OG_ENOMEM 2, OG_EINVAL 4, OG_EINVVID 7 and so on). Each entry lists its codes. On an error Open Graph first calls the error handler, which by default prints the error and stops the program; a program that checks the codes installs error_handler_ignore with set_error_handler, or a handler of its own that calls it, as OpenBI’s engine does. Either way, a function that fails frees what it made itself.

Memory and outputs

Results go into objects the caller owns: initialise a vector or matrix (og_vector_init, og_matrix_init), pass a pointer, and the function resizes and fills it; destroy it when done. Output arguments documented as optional may be NULL. Memory Open Graph allocates for you is freed with free.

Vectors and matrices

og_vector_t holds real numbers; og_vector_int_t, og_vector_bool_t, og_vector_char_t and og_vector_complex_t hold the other types, with the same functions under the type’s name (og_vector_int_size). Matrices are stored column by column. VECTOR(v)[i] and MATRIX(m, i, j) reach an element directly. See Vectors and Matrices.

Selectors and iterators

A function that works on some of the vertices or edges takes a selector: og_vs_t for vertices, og_es_t for edges (all of them, one, a vector of ids, a range, the neighbours of a vertex and more). The immediate forms, og_vss_* and og_ess_*, are written straight into the call and need no clean-up: og_degree(&g, &deg, og_vss_all(), OG_ALL, OG_LOOPS). Iterators walk a selector’s ids.

Random numbers

Randomised functions draw from rng_default, a PCG32 generator per thread, seeded from the clock until you seed it: og_rng_seed(og_rng_default(), 42).

OAX network functions

The OAX NETWORK.* functions build a graph from a table’s rows and call Open Graph. Each function’s page links back here.

OAX functionOpen Graph functions
NETWORK.NODESstrength, pagerank, betweenness_cutoff, betweenness, coreness, connected_components, articulation_points, community_multilevel
NETWORK.LINKSedge_betweenness_cutoff, edge_betweenness, bridges, biconnected_components
NETWORK.LAYOUTlayout_fruchterman_reingold
NETWORK.PATHget_shortest_path_dijkstra
NETWORK.CENTRALITYstrength, harmonic_centrality, eigenvector_centrality, hub_and_authority_scores, transitivity_local_undirected, eccentricity, connected_components
NETWORK.COMMUNITIEScommunity_multilevel, strength, community_leiden, community_walktrap, community_fastgreedy, community_label_propagation, community_infomap, community_edge_betweenness, modularity
NETWORK.GRAPHdensity, connected_components, transitivity_undirected, transitivity_avglocal_undirected, assortativity_degree, diameter, average_path_length, community_multilevel, modularity, reciprocity
NETWORK.EMBEDstrength, adjacency_spectral_embedding
NETWORK.CYCLESsimple_cycles
NETWORK.PROPAGATEpersonalized_pagerank_vs
NETWORK.FLOWmaxflow
NETWORK.TRIADStriad_census
NETWORK.CLIQUESmaximal_cliques
NETWORK.SENSITIVITYjacobian_full, jacobian_column, pagerank, eigenvector_centrality, strength, closeness, harmonic_centrality, betweenness
NETWORK.COMPAREcompare_communities
NETWORK.RINGStrussness, count_adjacent_triangles
NETWORK.WEAKPOINTSbiconnected_components, bridges, connected_components, strength
NETWORK.CUTSconnected_components, gomory_hu_tree
NETWORK.PREDICThrg_init, hrg_predict, hrg_destroy
NETWORK.ROLLUProllup

NETWORK.EDGES, NETWORK.SIMILARITY, NETWORK.SIR, NETWORK.SIR.NODES, NETWORK.REACH, NETWORK.MATCH are OpenBI's own code and call no Open Graph function.

In notebooks

A notebook’s C# steps in OpenBI Studio call Open Graph too, the same library as the engine’s, from the rows the model gives the step: the measures on report pages and the ones a step computes agree.

Graph.FromTable(Dax(...), "From", "To", weight: "Weight") makes the graph the OAX NETWORK.* functions would, and its methods measure it as tables (PageRank, communities by seven methods, cut points, maximum flow, cliques, motifs, similar nodes, likely links, the Jacobian); Og has every function of this reference in C# terms: 513 as methods with arrays and exceptions, 555 more as C declares them. In notebooks says how, and every entry’s page names its C# form.

Last updated · Open Graph 0.1.0 · OpenBI Studio 0.3.78