1 |
/* ASCEND modelling environment |
2 |
Copyright (C) 2007 Carnegie Mellon University |
3 |
|
4 |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2, or (at your option) |
7 |
any later version. |
8 |
|
9 |
This program is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
13 |
|
14 |
You should have received a copy of the GNU General Public License |
15 |
along with this program; if not, write to the Free Software |
16 |
Foundation, Inc., 59 Temple Place - Suite 330, |
17 |
Boston, MA 02111-1307, USA. |
18 |
*//** @file |
19 |
System graph output |
20 |
|
21 |
Use variable and relation filters to generate a graph between the selected |
22 |
vars and rels, by querying their incidence data. Write the graph in DOT |
23 |
format to the provided FILE*. |
24 |
|
25 |
by John Pye, March 2007 |
26 |
*/ |
27 |
|
28 |
#ifdef HAVE_GRAPHVIZ_BOOLEAN |
29 |
# define HAVE_BOOLEAN |
30 |
#endif |
31 |
#include <ascend/general/platform.h> |
32 |
|
33 |
/*#ifdef WITH_GRAPHVIZ |
34 |
# ifdef __WIN32__ |
35 |
# include <gvc.h> |
36 |
# else |
37 |
# include <graphviz/gvc.h> |
38 |
# endif |
39 |
# define HAVE_BOOLEAN |
40 |
#endif*/ |
41 |
|
42 |
boolean X; |
43 |
|
44 |
#include "graph.h" |
45 |
#include "slv_client.h" |
46 |
#include "incidence.h" |
47 |
#include <ascend/general/ascMalloc.h> |
48 |
#include <ascend/general/panic.h> |
49 |
#include <dlfcn.h> |
50 |
#include <graphviz/gvc.h> |
51 |
|
52 |
int system_write_graph(slv_system_t sys |
53 |
, FILE *fp |
54 |
, const char *format |
55 |
){ |
56 |
incidence_vars_t id; |
57 |
build_incidence_data(sys, &id); |
58 |
|
59 |
void * handle; |
60 |
handle = dlopen("libgvc.so",RTLD_NOW); |
61 |
if(handle==NULL) |
62 |
{ |
63 |
printf("Graphviz was not found on your system"); |
64 |
return 1; |
65 |
} |
66 |
|
67 |
Agraph_t *g; |
68 |
Agraph_t *(*agop)(char* , int); |
69 |
|
70 |
GVC_t *gvc; |
71 |
GVC_t *(*gvConte)(); |
72 |
|
73 |
void (*agnodeat) (Agraph_t* , char* , char*); |
74 |
|
75 |
*(void **) (&gvConte) = dlsym(handle,"gvContext"); |
76 |
*(void **) (&agop) = dlsym(handle,"agopen"); |
77 |
*(void **) (&agnodeat) = dlsym(handle,"agnodeattr"); |
78 |
|
79 |
|
80 |
unsigned edgecount = 0; |
81 |
unsigned nodecount = 0; |
82 |
|
83 |
gvc = (*gvConte)(); |
84 |
g = (*agop)("g",AGDIGRAPH); |
85 |
(*agnodeat)(g,"shape","ellipse"); |
86 |
(*agnodeat)(g,"label",""); |
87 |
(*agnodeat)(g,"color",""); |
88 |
(*agnodeat)(g,"style",""); |
89 |
|
90 |
char temp[200]; |
91 |
|
92 |
/* first create nodes for the relations */ |
93 |
unsigned i; |
94 |
Agnode_t *n, *m; |
95 |
Agnode_t *(*agno)(Agraph_t* , char*); |
96 |
void (*ags) (Agnode_t* , char* , char*); |
97 |
|
98 |
*(void **) (&agno) = dlsym(handle,"agnode"); |
99 |
*(void **) (&ags) = dlsym(handle,"agset"); |
100 |
|
101 |
|
102 |
for(i=0; i < id.neqn; ++i){ |
103 |
char *relname; |
104 |
relname = rel_make_name(sys,id.rlist[i]); |
105 |
sprintf(temp,"r%d",rel_sindex(id.rlist[i])); |
106 |
n = (*agno)(g,temp); |
107 |
(*ags)(n,"label",relname); |
108 |
if(rel_satisfied(id.rlist[i])){ |
109 |
(*ags)(n,"style","filled"); |
110 |
(*ags)(n,"color","blue"); |
111 |
} |
112 |
ASC_FREE(relname); |
113 |
nodecount++; |
114 |
} |
115 |
|
116 |
/* now create nodes for the variables */ |
117 |
unsigned j; |
118 |
for(j=0; j < id.nvar; ++j){ |
119 |
char *varname; |
120 |
varname = var_make_name(sys,id.vlist[j]); |
121 |
sprintf(temp,"v%d",var_sindex(id.vlist[j])); |
122 |
n = (*agno)(g,temp); |
123 |
(*ags)(n,"label",varname); |
124 |
(*ags)(n, "shape", "box"); |
125 |
if(var_fixed(id.vlist[j])){ |
126 |
CONSOLE_DEBUG("VAR '%s' IS FIXED",varname); |
127 |
(*ags)(n,"style","filled"); |
128 |
(*ags)(n,"color","green"); |
129 |
} |
130 |
if(!var_active(id.vlist[j])){ |
131 |
CONSOLE_DEBUG("VAR '%s' IS FIXED",varname); |
132 |
(*ags)(n,"style","filled"); |
133 |
(*ags)(n,"color","gray"); |
134 |
} |
135 |
ASC_FREE(varname); |
136 |
nodecount++; |
137 |
} |
138 |
|
139 |
/* now create edges */ |
140 |
const struct var_variable **ivars; |
141 |
unsigned niv; |
142 |
char reltemp[200]; |
143 |
Agedge_t *e; |
144 |
Agedge_t *(*aged)(Agraph_t* , Agnode_t*, Agnode_t*); |
145 |
|
146 |
*(void **) (&aged) = dlsym(handle,"agedge"); |
147 |
|
148 |
for(i=0; i < id.nprow; ++i){ |
149 |
ivars = rel_incidence_list(id.rlist[i]); |
150 |
niv = rel_n_incidences(id.rlist[i]); |
151 |
sprintf(reltemp,"r%d",rel_sindex(id.rlist[i])); |
152 |
char *relname; |
153 |
relname = rel_make_name(sys,id.rlist[i]); |
154 |
CONSOLE_DEBUG("rel = '%s'",relname); |
155 |
ASC_FREE(relname); |
156 |
for(j=0; j < niv; ++j){ |
157 |
const struct var_variable *v; |
158 |
v = ivars[j]; |
159 |
sprintf(temp,"v%d",var_sindex(v)); |
160 |
n = (*agno)(g, reltemp); |
161 |
m = (*agno)(g, temp); |
162 |
|
163 |
if(id.v2pc[var_sindex(v)]==id.e2pr[rel_sindex(id.rlist[i])]){ |
164 |
e = (*aged)(g,n,m); /* from rel to var */ |
165 |
}else{ |
166 |
e = (*aged)(g,m,n); /* from var to rel */ |
167 |
} |
168 |
edgecount++; |
169 |
} |
170 |
} |
171 |
|
172 |
if(nodecount > 300 || edgecount > 300){ |
173 |
ERROR_REPORTER_HERE(ASC_USER_ERROR,"Graph is too complex, will not launch GraphViz (%d nodes, %d edges)", nodecount, edgecount); |
174 |
return 1; |
175 |
} |
176 |
|
177 |
|
178 |
void (*gvLayo)(GVC_t* , Agraph_t*, char*); |
179 |
void (*gvRend)(GVC_t* , Agraph_t*, char*, FILE*); |
180 |
|
181 |
*(void **) (&gvLayo) = dlsym(handle,"gvLayout"); |
182 |
*(void **) (&gvRend) = dlsym(handle,"gvRender"); |
183 |
|
184 |
|
185 |
(*gvLayo)(gvc, g, "dot"); |
186 |
(*gvRend)(gvc, g, (char*)format, fp); |
187 |
|
188 |
printf("\nErrors encountered %s\n",(*dlerror)()); |
189 |
dlclose(handle); |
190 |
|
191 |
#if 0//def WITH_GRAPHVIZ |
192 |
|
193 |
|
194 |
Agraph_t *g; |
195 |
GVC_t *gvc; |
196 |
|
197 |
unsigned edgecount = 0; |
198 |
unsigned nodecount = 0; |
199 |
|
200 |
gvc = gvContext(); |
201 |
g = agopen("g",AGDIGRAPH); |
202 |
agnodeattr(g,"shape","ellipse"); |
203 |
agnodeattr(g,"label",""); |
204 |
agnodeattr(g,"color",""); |
205 |
agnodeattr(g,"style",""); |
206 |
|
207 |
char temp[200]; |
208 |
|
209 |
/* first create nodes for the relations */ |
210 |
unsigned i; |
211 |
Agnode_t *n, *m; |
212 |
for(i=0; i < id.neqn; ++i){ |
213 |
char *relname; |
214 |
relname = rel_make_name(sys,id.rlist[i]); |
215 |
sprintf(temp,"r%d",rel_sindex(id.rlist[i])); |
216 |
n = agnode(g,temp); |
217 |
agset(n,"label",relname); |
218 |
if(rel_satisfied(id.rlist[i])){ |
219 |
agset(n,"style","filled"); |
220 |
agset(n,"color","blue"); |
221 |
} |
222 |
ASC_FREE(relname); |
223 |
nodecount++; |
224 |
} |
225 |
|
226 |
/* now create nodes for the variables */ |
227 |
unsigned j; |
228 |
for(j=0; j < id.nvar; ++j){ |
229 |
char *varname; |
230 |
varname = var_make_name(sys,id.vlist[j]); |
231 |
sprintf(temp,"v%d",var_sindex(id.vlist[j])); |
232 |
n = agnode(g,temp); |
233 |
agset(n,"label",varname); |
234 |
agset(n, "shape", "box"); |
235 |
if(var_fixed(id.vlist[j])){ |
236 |
CONSOLE_DEBUG("VAR '%s' IS FIXED",varname); |
237 |
agset(n,"style","filled"); |
238 |
agset(n,"color","green"); |
239 |
} |
240 |
if(!var_active(id.vlist[j])){ |
241 |
CONSOLE_DEBUG("VAR '%s' IS FIXED",varname); |
242 |
agset(n,"style","filled"); |
243 |
agset(n,"color","gray"); |
244 |
} |
245 |
ASC_FREE(varname); |
246 |
nodecount++; |
247 |
} |
248 |
|
249 |
/* now create edges */ |
250 |
const struct var_variable **ivars; |
251 |
unsigned niv; |
252 |
char reltemp[200]; |
253 |
struct Agedge_t *e; |
254 |
for(i=0; i < id.nprow; ++i){ |
255 |
ivars = rel_incidence_list(id.rlist[i]); |
256 |
niv = rel_n_incidences(id.rlist[i]); |
257 |
sprintf(reltemp,"r%d",rel_sindex(id.rlist[i])); |
258 |
char *relname; |
259 |
relname = rel_make_name(sys,id.rlist[i]); |
260 |
CONSOLE_DEBUG("rel = '%s'",relname); |
261 |
ASC_FREE(relname); |
262 |
for(j=0; j < niv; ++j){ |
263 |
const struct var_variable *v; |
264 |
v = ivars[j]; |
265 |
sprintf(temp,"v%d",var_sindex(v)); |
266 |
n = agnode(g, reltemp); |
267 |
m = agnode(g, temp); |
268 |
|
269 |
if(id.v2pc[var_sindex(v)]==id.e2pr[rel_sindex(id.rlist[i])]){ |
270 |
e = agedge(g,n,m); /* from rel to var */ |
271 |
}else{ |
272 |
e = agedge(g,m,n); /* from var to rel */ |
273 |
} |
274 |
edgecount++; |
275 |
} |
276 |
} |
277 |
|
278 |
if(nodecount > 300 || edgecount > 300){ |
279 |
ERROR_REPORTER_HERE(ASC_USER_ERROR,"Graph is too complex, will not launch GraphViz (%d nodes, %d edges)", nodecount, edgecount); |
280 |
return 1; |
281 |
} |
282 |
|
283 |
gvLayout(gvc, g, "dot"); |
284 |
gvRender(gvc, g, (char*)format, fp); */ |
285 |
|
286 |
#else |
287 |
// ERROR_REPORTER_HERE(ASC_PROG_ERR,"Function system_write_graph not available (GraphViz not present at build-time)"); |
288 |
// return 1; /* error */ |
289 |
#endif |
290 |
|
291 |
#if 0 |
292 |
int nr,nsr,nv,nsv,niv; |
293 |
int i,j; |
294 |
struct rel_relation **srels; |
295 |
struct var_variable **svars, **ivars; |
296 |
char *relname, *varname; |
297 |
|
298 |
CONSOLE_DEBUG("Writing graph..."); |
299 |
asc_assert(fp!=NULL); |
300 |
|
301 |
CONSOLE_DEBUG("FP = %p",fp); |
302 |
fprintf(fp,"digraph G{\n"); |
303 |
|
304 |
/* first create nodes for the rels */ |
305 |
nr = slv_count_solvers_rels(sys,rfilter); |
306 |
nsr = slv_get_num_solvers_rels(sys); |
307 |
srels = slv_get_solvers_rel_list(sys); |
308 |
fprintf(fp,"\n\n\t/* %d relations */\n\n",nr); |
309 |
for(i=0; i<nsr; ++i){ |
310 |
if(rel_apply_filter(srels[i],rfilter)){ |
311 |
relname = rel_make_name(sys,srels[i]); |
312 |
fprintf(fp,"\tr%d[shape=box,label=\"%s\"]\n",i,relname); |
313 |
ASC_FREE(relname); |
314 |
} |
315 |
} |
316 |
|
317 |
/* and the vars */ |
318 |
nsv = slv_get_num_solvers_vars(sys); |
319 |
nv = slv_count_solvers_vars(sys,vfilter); |
320 |
svars = slv_get_solvers_var_list(sys); |
321 |
fprintf(fp,"\n\n\t/* %d variables */\n\n",nv); |
322 |
for(j=0; j<nsv; ++j){ |
323 |
if(var_apply_filter(svars[j],vfilter)){ |
324 |
varname = var_make_name(sys,svars[j]); |
325 |
if(var_fixed(svars[j])){ |
326 |
fprintf(fp,"s\tv%d[label=\"%s\",style=filled,color=green]\n",j,varname); |
327 |
}else{ |
328 |
fprintf(fp,"\tv%d[label=\"%s\"]\n",j,varname); |
329 |
} |
330 |
ASC_FREE(varname); |
331 |
} |
332 |
} |
333 |
|
334 |
/* now output the edges between them */ |
335 |
fprintf(fp,"\n\n\t/* incidences */\n\n"); |
336 |
for(i=0; i<nsr; ++i){ |
337 |
if(!rel_apply_filter(srels[i],rfilter))continue; |
338 |
|
339 |
ivars = rel_incidence_list(srels[i]); |
340 |
niv = rel_n_incidences(srels[i]); |
341 |
|
342 |
for(j=0; j<niv; ++j){ |
343 |
if(!var_apply_filter(ivars[j],vfilter))continue; |
344 |
if(j==i){ |
345 |
fprintf(fp,"\tr%d->v%d\n",i,var_sindex(ivars[j])); |
346 |
}else{ |
347 |
fprintf(fp,"\tv%d->r%d\n",var_sindex(ivars[j]),i); |
348 |
} |
349 |
} |
350 |
} |
351 |
|
352 |
fprintf(fp,"}\n"); |
353 |
#endif |
354 |
CONSOLE_DEBUG("Completed graph output"); |
355 |
return 0; |
356 |
} |
357 |
|
358 |
|
359 |
|
360 |
|