The examples which follow do not specify controller objects. By that, all constructed objects are assigned to the goblinDefaultContext controller. If you do so also with your application code - and this is adequate if you do not run concurrent jobs - all library configuration must be addressed to the default controller object. For example, `goblinDefaultContext.SuppressLogging()`

would disable the logging event handler.

graph H(G.N()); for (TNode u=0;u<G.N();++u) { for (TNode v=u+1;v<G.N();++v) { if (G.Adjacency(u,v)==NoArc) H.InsertArc(u,v); } }

The initial constructor call results in a void graph with an identical node set as G. Then, the procedure iterates on all unordered node pairs u,v and checks if these nodes are adjacent in G. If not, an arc is added to H.

graph G(TNode(0)); TNode** subset = new TNode*[cardinality]; for (TNode i=0;i<cardinality;++i) { subset[i] = new TNode[cardinality]; for (TNode j=i+1;j<cardinality;++j) { subset[i][j] = G.InsertNode(); for (TNode k=0 ;k<i;++k) G.InsertArc(subset[i][j],subset[k][j]); for (TNode k=i+1;k<j;++k) G.InsertArc(subset[i][j],subset[i][k]); for (TNode k=0 ;k<i;++k) G.InsertArc(subset[i][j],subset[k][i]); } } for (TNode i=0;i<cardinality;++i) delete[] subset[i]; delete[] subset;

Both loops enumerate on the ground set elements which are represented by indices 0, 1, .., cardinality-1. The InsertNode() call returns the index of the added graph node and saves it in a table for convenience. So, the `subset[i][j]`

is an obvious encoding of the subset {i,j}, assuming i<j.

Basically, the sequence of node indices returned by InsertNode() is is 0,1,2,.., and it would be more economic (but less comprehensible) to use a formula in replace of table lookup.

The calls of InsertArc() require indices of already existing nodes, and so the enumeration of arcs still takes some care. Convince yourself that no graph incidence is missed.

This code has been taken from the triangularGraph constructor, to be found in sparseGraph.cpp. This file also defines constructors like openGrid which compute node indices from formula instead of table lookup. The following depicts the special case of constructing a grid graph with quadrangular faces:

graph G(TNode(numRows*numColumns)); for (TNode k=0;k<numRows;++k) { for (TNode l=0;l<numColumns;++l) { if (l<numColumns-1) InsertArc(k*numColumns + l, k *numColumns + (l+1)); if (k<numRows-1) InsertArc(k*numColumns + l,(k+1)*numColumns + l ); } }

sparseDiGraph *Hypercube = new sparseDiGraph(TNode(1)); for (unsigned long i=0;i<dimension;++i) { sparseDiGraph *NextCube = new sparseDiGraph(*Hypercube,Hypercube->OPT_CLONE); NextCube -> AddGraphByNodes(*Hypercube); TNode n0 = Hypercube->N(); for (TNode j=0;j<n0;++j) { NextCube -> InsertArc(j,n0+j); } delete Hypercube; Hypercube = NextCube; }

The procedure starts with a one-node digraph, that is the hypercube of dimension zero. To obtain the (d+1)-hypercube from the (d)-hypercube, the digraph copy constructor is used. The OPT_CLONE specifier herein demands that the new sparseDiGraph instance has an identical incidence structure (otherwise arcs with zero upper capacity bounds are not mapped, and the order of arc indices changes).

The AddGraphByNodes() call generates a second, node-disjoint copy of the (d)-hypercube. This has node indices n0, n0+1, .., 2n0-1 in the compound graph. Both (d)-hypercube subgraphs are then connected by explicit InsertArc() method calls which take the end node indices as parameters.

Similar, compilable code is provided by the file testHypercube.cpp.

class binaryTree : public sparseDiGraph { binaryTree(TNode depth,goblinController& _CT = goblinDefaultContext); }; binaryTree::binaryTree(TNode depth,goblinController &_CT) : managedObject(_CT), sparseDiGraph(TNode(1)) { if (depth==0) return; binaryTree TR(depth-1,_CT); static_cast<sparseRepresentation*>(Representation()) -> SetCapacity(2*TR.N()+1,2*TR.N()+2); AddGraphByNodes(TR); AddGraphByNodes(TR); InsertArc(0,1); InsertArc(0,TR.N()+1); }

The managedObject initializer assigns new instances to a goblinController object. The sparseDiGraph initializer lets the constructor start from a singleton node graph. This node serves as the root node. If the specified tree depth is zero, nothing more has to be done. Otherwise, the depth (d+1) binary tree is obtained from two disjoint copies of a depth (d) binary tree, calling abstractMixedGraph::AddGraphByNodes() twice. To obtain the (d) binary tree, the displayed constructor method is called recursively.

The sparseRepresentation::SetCapacity() call is not esssential. But it prevents from reallocations, every time, a node or arc is added. It is directly addressed to the representational object, like most of the methods which manipulate graph instances.

In a final step, the root node of the depth (d+1) binary tree is connected to the root nodes of the depth (d) binary trees by calling InsertArc() with the respective node indices.

Similar, compilable code is provided by the file testBinTree.cpp.

managedObject* X = goblinDefaultContext.ImportByFormatName(filename,formatName); if (X && X->IsGraphObject()) { abstractMixedGraph *G = dynamic_cast<abstractMixedGraph*>(X); ... }

This code can load from any file format supported by the library, and construct objects of any target types, as required for the selected `formatName`

. The obvious overhead is that the precise object type must be reconstructed later.

When the input file format is known in advance, the cast operations can be avoided by using a more low-level method:

sparseDiGraph* G = goblinDefaultContext.Import_DimacsEdge(filename); if (G) { ... }

or, for the library native formats, like this:

sparseDiGraph* G = NULL; try { G = new sparseDiGraph(filename); } catch (ERParse) { ... } catch (ERFile) { ... }

Note that the first two methods return a NULL pointer in every case of trouble. The third method might throw two different exceptions, for non-existing files and for syntax violations.

Similar, compilable code is provided by the file testPlanarity.cpp.