Skip to content

Commit 8ebfffc

Browse files
pythonised testgraph
1 parent ff294ba commit 8ebfffc

11 files changed

Lines changed: 148 additions & 214 deletions

File tree

include/graph.h

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ namespace ecolab
6767
}
6868
};
6969

70+
template <class T>
71+
struct DotConversion
72+
{
73+
std::string dot() const {
74+
std::ostringstream os;
75+
os<<static_cast<const T&>(*this);
76+
return os.str();
77+
}
78+
void importDot(const std::string& dot) {
79+
std::istringstream is(dot);
80+
is>>static_cast<T&>(*this);
81+
}
82+
};
83+
7084
/// To support back_insert_iterators for Graph, define a special
7185
/// version that converts from BoostGraph edges
7286
template <class Graph, class BG>
@@ -90,7 +104,7 @@ namespace ecolab
90104
/**
91105
Abstract base class for graph algorithms.
92106
*/
93-
struct Graph
107+
struct Graph: public DotConversion<Graph>
94108
{
95109
typedef Edge value_type;
96110
typedef std::size_t size_type;
@@ -255,15 +269,12 @@ class ConcreteGraph: public GraphAdaptor<G>
255269
public:
256270
ConcreteGraph(unsigned nodes=0): GraphAdaptor<G>(g), g(nodes) {}
257271
template <class H> explicit ConcreteGraph(const H& g1): GraphAdaptor<G>(g), g(g1) {}
272+
template <class H> void asg(const H& g) {operator=(ConcreteGraph(g));}
258273
bool operator==(const ConcreteGraph& x) {return x.g==g;}
259274
bool operator!=(const ConcreteGraph& x) {return x.g!=g;}
260275
};
261276

262-
// default is not directed
263-
template <class G> bool GraphAdaptor<G>::directed() const
264-
{return true;}
265-
266-
class DiGraph: private std::set<Edge>
277+
class DiGraph: private std::set<Edge>, public DotConversion<DiGraph>
267278
{
268279
unsigned num_nodes;
269280
CLASSDESC_ACCESS(DiGraph);
@@ -353,7 +364,7 @@ class BiDirectionalGraph_const_iterator/*:
353364

354365
/// A graph in which each link is bidirectional
355366
// base class is protected, because viewing this thing as a Graph is not correct
356-
class BiDirectionalGraph
367+
class BiDirectionalGraph: public DotConversion<BiDirectionalGraph>
357368
{
358369
DiGraph graph; ///< the representation
359370
CLASSDESC_ACCESS(BiDirectionalGraph);
@@ -369,10 +380,9 @@ class BiDirectionalGraph
369380
graph.push_back(e);
370381
}
371382
void clear(unsigned nodes=0) {graph.clear(nodes);}
372-
373383
BiDirectionalGraph(unsigned nodes=0): graph(nodes) {}
374384
/// initialise Graph using Graph "duck-typed" object
375-
template <class G> BiDirectionalGraph(const G& g) {asg(g);}
385+
template <class G> explicit BiDirectionalGraph(const G& g) {asg(g);}
376386
template <class G> void asg(const G& g) {
377387
clear(g.nodes());
378388
for (typename G::const_iterator i=g.begin(); i!=g.end(); ++i) push_back(*i);
@@ -389,8 +399,20 @@ class BiDirectionalGraph
389399
bool operator<(const BiDirectionalGraph& x) const {return graph<x.graph;}
390400
};
391401

392-
template <> inline
393-
bool GraphAdaptor<BiDirectionalGraph>::directed() const {return false;}
402+
template <class G>
403+
struct Directed{ const static bool value=true;};
404+
405+
template <>
406+
struct Directed<ecolab::BiDirectionalGraph>{ const static bool value=false;};
407+
408+
template <>
409+
struct Directed<const ecolab::BiDirectionalGraph>{ const static bool value=false;};
410+
411+
template <class G> bool GraphAdaptor<G>::directed() const
412+
{
413+
return Directed<G>::value;
414+
}
415+
394416

395417
// uses the sign of the off-diagonal term to indicate link
396418
// direction. Links point in the same direction have their weights
@@ -518,11 +540,14 @@ namespace classdesc_access
518540

519541
namespace std
520542
{
521-
/// for use with TCL_obj. Graphviz format is used with the netgraph command.
543+
/// Graphviz format is used with the netgraph command.
522544
std::ostream& operator<<(std::ostream& s, const ecolab::Graph& x);
523545
template <class G>
524546
std::ostream& operator<<(std::ostream& s, const ecolab::ConcreteGraph<G>& x)
525547
{return s<<static_cast<const ecolab::Graph&>(x);}
548+
template <class G>
549+
std::ostream& operator<<(std::ostream& s, const ecolab::GraphAdaptor<G>& x)
550+
{return s<<static_cast<const ecolab::Graph&>(x);}
526551

527552
inline std::ostream& operator<<(std::ostream& s, const ecolab::DiGraph& x)
528553
{return s<<ecolab::GraphAdaptor<const ecolab::DiGraph>(x);}
@@ -537,18 +562,25 @@ namespace std
537562

538563
inline std::istream& operator>>(std::istream& s, ecolab::DiGraph& x)
539564
{ecolab::GraphAdaptor<ecolab::DiGraph> g(x); return s>>g;}
565+
540566
inline std::istream& operator>>(std::istream& s, ecolab::BiDirectionalGraph& x)
541-
{ecolab::GraphAdaptor<ecolab::BiDirectionalGraph> g(x); return s>>g;}
567+
{ecolab::GraphAdaptor<ecolab::BiDirectionalGraph> g(x); std::cout<<g.directed()<<std::endl; return s>>g;}
542568
}
543569

544570
#if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
545571
#pragma GCC diagnostic push
546572
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
547573
#endif
548574

575+
// override json_pack with above GraphViz serialiser
576+
//#define CLASSDESC_json_pack___ecolab__GraphAdaptor_G_
577+
//#define CLASSDESC_json_unpack___ecolab__GraphAdaptor_G_
578+
//#define CLASSDESC_json_pack___ecolab__DiGraph
579+
//#define CLASSDESC_json_unpack___ecolab__BiDirectionalGraph
549580
#include "graph.cd"
550581

551582
#if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
552583
#pragma GCC diagnostic pop
553584
#endif
554585
#endif
586+

src/ecolab.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "pythonBuffer.h"
1717
#include "ecolab.h"
1818
#include "random.h"
19+
#include "graph.h"
1920
#ifdef MPI_SUPPORT
2021
#include "graphcode.h"
2122
#endif
@@ -241,6 +242,10 @@ namespace ecolab
241242
#ifdef UNURAN
242243
CLASSDESC_DECLARE_TYPE(unuran);
243244
#endif
245+
using DiGraph=ConcreteGraph<ecolab::DiGraph>;
246+
using BiDirectionalGraph=ConcreteGraph<ecolab::BiDirectionalGraph>;
247+
CLASSDESC_DECLARE_TYPE(DiGraph);
248+
CLASSDESC_DECLARE_TYPE(BiDirectionalGraph);
244249
}
245250

246251
// device SYCL kernels are running on

src/graph.cc

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,19 +275,12 @@ namespace ecolab
275275
else if (buf=="digraph {")
276276
parse_graphviz(s,x,false);
277277
else
278-
{
279-
// if (TCL_obj_properties().count(buf)==0)
280-
// throw error("%s does not exist!",buf.c_str());
281-
// if (Graph* g=TCL_obj_properties()[buf]->memberPtrCasted<Graph>())
282-
// x=*g;
283-
// else
284-
throw error("unable to assign variable %s, which is not a Graph, "
278+
throw error("unable to assign variable %s, which is not a Graph, "
285279
"to object of type %s", buf.c_str(), typeid(G).name());
286-
}
287280
return s;
288281
}
289282
}
290-
283+
291284
void ErdosRenyi_generate(Graph& g, unsigned nodes, unsigned links,
292285
urand& uni, random_gen& weight_dist)
293286
{

test/00/t0025a.sh

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,8 @@
55
#
66
# Open source licensed under the MIT license. See LICENSE for details.
77

8-
98
here=`pwd`
10-
if test $? -ne 0; then exit 2; fi
11-
tmp=/tmp/$$
12-
mkdir $tmp
13-
if test $? -ne 0; then exit 2; fi
14-
cd $tmp
15-
if test $? -ne 0; then exit 2; fi
16-
17-
fail()
18-
{
19-
echo "FAILED" 1>&2
20-
cd $here
21-
chmod -R u+w $tmp
22-
rm -rf $tmp
23-
exit 1
24-
}
25-
26-
pass()
27-
{
28-
echo "PASSED" 1>&2
29-
cd $here
30-
chmod -R u+w $tmp
31-
rm -rf $tmp
32-
exit 0
33-
}
34-
35-
trap "fail" 1 2 3 15
36-
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
37-
38-
# insert ecolab script code here
39-
# use \$ in place of $ to refer to variable contents
40-
# exit 0 to indicate pass, and exit 1 to indicate failure
41-
cat >input.tcl <<EOF
42-
EOF
9+
. $here/test/common-test.sh
4310

4411
$here/test/testCheckpointableFile
4512
if test $? -ne 0; then fail; fi

test/00/t0026a.sh

Lines changed: 0 additions & 43 deletions
This file was deleted.

test/00/testgraph.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#! /bin/sh
2+
# @copyright Russell Standish 2000-2013
3+
# @author Russell Standish
4+
# This file is part of Classdesc
5+
#
6+
# Open source licensed under the MIT license. See LICENSE for details.
7+
8+
here=`pwd`
9+
. $here/test/common-test.sh
10+
11+
python3 $here/test/testgraph.py
12+
if test $? -ne 0; then fail; fi
13+
14+
pass

test/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ endif
2020
GDBM+=-lgdbm
2121

2222
#MODELS=testrefassign testref testgraph test_boostgraph testCacheDBM testCairo accessor vector-pair
23-
MODELS=testParallel testCacheDBM
23+
MODELS=testParallel testCacheDBM testgraph
2424
# vector-pair - doesn't currently compile - see ticket #161
2525
#EXTRAMODELS=test_tcl_stl.exe tcl-arrays.exe complex_tcl_args.exe
2626
#EXES=test_omp_rw_lock testCheckpointableFile test_netcomplexity test_boostgraph test_ecostrstream posTest testarrays pangoTest testParallel

test/testgraph.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@
1616
using namespace ecolab;
1717

1818
Testgraph tg;
19-
make_model(tg);
19+
CLASSDESC_ADD_GLOBAL(tg);
20+
using DiGraph1=DiGraph;
21+
CLASSDESC_DECLARE_TYPE(DiGraph1);
22+
CLASSDESC_PYTHON_MODULE(testgraph);
23+
2024

test/testgraph.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,18 @@ struct Testgraph
1313
{
1414
ConcreteGraph<DiGraph> g;
1515
ConcreteGraph<BiDirectionalGraph> dg;
16-
void first(TCL_args args) { ///< create a graph with n nodes and l links
17-
unsigned n=args, l=args;
18-
g=BitRep(n,l); dg=BiDirectionalBitRep(n,l);}
19-
void next(TCL_args) { ///< create a graph with n nodes and l links
20-
BitRep b(g); b.next_perm(); g=b;
21-
BiDirectionalBitRep db(dg); db.next_perm(); dg=db;
16+
void first(unsigned n, unsigned l) { ///< create a graph with n nodes and l links
17+
g.asg(BitRep(n,l)); dg.asg(BiDirectionalBitRep(n,l));}
18+
void next() { ///< create a graph with n nodes and l links
19+
BitRep b(g); b.next_perm(); g.asg(b);
20+
BiDirectionalBitRep db(dg); db.next_perm(); dg.asg(db);
2221
}
2322
array<unsigned> degrees() {
2423
Degrees d=::degrees(g);
2524
return array<unsigned>(d.in_degree+d.out_degree);
2625
}
2726
urand uni;
28-
void randGraph(TCL_args args) {ErdosRenyi_generate(g,args[0],args[1],uni,uni);
27+
void randGraph(unsigned nodes, unsigned links) {ErdosRenyi_generate(g,nodes,links,uni,uni);
2928
}
30-
void prefAttach(TCL_args args) {PreferentialAttach_generate(g,args,uni);}
29+
void prefAttach(unsigned nodes) {PreferentialAttach_generate(g,nodes,uni);}
3130
};

test/testgraph.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!python3
2+
# @copyright Russell Standish 2000-2013
3+
# @author Russell Standish
4+
# This file is part of Classdesc
5+
#
6+
# Open source licensed under the MIT license. See LICENSE for details.
7+
8+
from testgraph import tg
9+
from ecolab import DiGraph, BiDirectionalGraph
10+
11+
tg.first(4, 4)
12+
assert tg.g.dot() == "digraph {\n0->1;\n0->2;\n0->3;\n1->0;\n}\n"
13+
assert tg.dg.dot()== "graph {\n0--1;\n0--2;\n0--3;\n1--2;\n}\n"
14+
15+
# test assignment
16+
ng=DiGraph()
17+
ng.importDot(tg.g.dot())
18+
assert tg.g.dot()==ng.dot(), "dot asg"
19+
20+
ndg=BiDirectionalGraph()
21+
ndg.importDot(tg.dg.dot())
22+
assert tg.dg.dot()==ndg.dot(), "bidi dot asg"
23+
24+
ng=DiGraph()
25+
ndg=BiDirectionalGraph()
26+
ng.importDot(tg.dg.dot())
27+
ndg.importDot(tg.dg.dot())
28+
assert ndg.dot()==tg.dg.dot(), "inbuilt tmp asg"
29+
30+
tg.g.output("pajek","g.net")
31+
tg.g.output("lgl","g.lgl")
32+
tg.dg.output("pajek","dg.net")
33+
tg.dg.output("lgl","dg.lgl")
34+
35+
ng=DiGraph()
36+
ng.input("pajek","g.net")
37+
assert ng.dot()==tg.g.dot(), "pajek input"
38+
39+
# LGL loses directionality, so we must symmetrise g
40+
ng=DiGraph()
41+
ng2=DiGraph()
42+
ndg=BiDirectionalGraph()
43+
ng.input("lgl", "g.lgl")
44+
# symmetrise g
45+
ndg.importDot(tg.g.dot())
46+
ng2.importDot(ndg.dot())
47+
assert ng.dot()==ng2.dot(), "lgl input"
48+
49+
ng=BiDirectionalGraph()
50+
ng.input("pajek","dg.net")
51+
assert ng.dot()==tg.dg.dot(), "pajek bidi inpout"
52+
53+
ng=BiDirectionalGraph()
54+
ng.input("lgl","dg.lgl")
55+
assert ng.dot()==tg.dg.dot(), "lgl bidi input"
56+
57+
# by generating a fully connected graph, we ensure that node
58+
# relabelling in the LGL routines is uniquely determined.
59+
tg.randGraph(4, 12)
60+
tg.dg(tg.g())
61+
ng=BiDirectionalGraph()
62+
for fmt in ["pajek", "lgl", "dot"]:
63+
tg.dg.output(fmt,"g.net")
64+
ng.clear()
65+
ng.input(fmt, "g.net")
66+
assert tg.dg.dot()==ng.dot(), fmt
67+
68+

0 commit comments

Comments
 (0)