6 * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of simple graph loaders.
12 * See header-file simple_graph_load.h for more information.
14 * \author Markus Chimani, Carsten Gutwenger, Karsten Klein
17 * This file is part of the Open Graph Drawing Framework (OGDF).
21 * See README.txt in the root directory of the OGDF installation for details.
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * Version 2 or 3 as published by the Free Software Foundation;
27 * see the file LICENSE.txt included in the packaging of this file
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public
38 * License along with this program; if not, write to the Free
39 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
40 * Boston, MA 02110-1301, USA.
42 * \see http://www.gnu.org/copyleft/gpl.html
43 ***************************************************************/
45 #include <ogdf/fileformats/simple_graph_load.h>
46 #include <ogdf/basic/Logger.h>
47 #include <ogdf/basic/HashArray.h>
48 #include <ogdf/basic/String.h>
52 #define SIMPLE_LOAD_BUFFER_SIZE 2048
56 bool loadRomeGraph(Graph
&G
, const char *fileName
) {
57 ifstream
is(fileName
);
58 if(!is
.good()) return false;
59 return loadRomeGraph(G
, is
);
63 bool loadRomeGraph(Graph
&G
, istream
&is
) {
66 char buffer
[SIMPLE_LOAD_BUFFER_SIZE
];
67 bool readNodes
= true;
68 Array
<node
> indexToNode(1,250,0);
72 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
75 if(buffer
[0] == '#') {
81 sscanf(buffer
, "%d", &index
);
82 if(index
< 1 || index
> 250 || indexToNode
[index
] != 0) {
83 Logger::slout() << "loadRomeGraph: illegal node index!\n";
87 indexToNode
[index
] = G
.newNode();
90 int index
, dummy
, srcIndex
, tgtIndex
;
91 sscanf(buffer
, "%d%d%d%d", &index
, &dummy
, &srcIndex
, &tgtIndex
);
96 if(srcIndex
< 1 || srcIndex
> 250 || tgtIndex
< 1 || tgtIndex
> 250 ||
97 indexToNode
[srcIndex
] == 0 || indexToNode
[tgtIndex
] == 0)
99 Logger::slout() << "loadRomeGraph: illegal node index in edge specification.\n";
103 G
.newEdge(indexToNode
[srcIndex
], indexToNode
[tgtIndex
]);
110 bool loadChacoGraph(Graph
&G
, const char *fileName
) {
111 ifstream
is(fileName
);
112 if(!is
.good()) return false;
113 return loadChacoGraph(G
, is
);
117 //Reads the chaco (graph partitioning) file format (usually a .graph file).
118 bool loadChacoGraph(Graph
&G
, istream
&is
)
121 char buffer
[SIMPLE_LOAD_BUFFER_SIZE
];
122 int numN
= 0, runEdges
= 0, lineNum
= 0;
125 //try to read the first line to get the graph size
128 //contains the size numbers
129 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
130 //char* context = NULL;
131 //now read the number of nodes
132 pch
= strtok(buffer
, " ");//strtok_s(buffer, " ", &context);
133 if (pch
== NULL
) return false;
135 //now read the number of edges
136 pch
= strtok(NULL
, " ");//strtok_s(NULL, " ", &context);
137 if (pch
== NULL
) return false;
138 // extension: check here for weights
142 if (numN
== 0) return true;
144 Array
<node
> indexToNode(1,numN
,0);
145 for (int i
= 1; i
<= numN
; i
++)
147 //we assign new indexes here if they are not consecutive
148 //starting from 1 in the file! Thus, if the file is not in the correct
149 //format, node indices do not correspond to indices from the file.
150 indexToNode
[i
] = G
.newNode();
155 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
156 if (strlen(buffer
) == 0) continue;
160 cerr
<< "File read error: More lines than expected number of nodes "<< lineNum
<<":"<<numN
<<"\n";
163 //char* context = NULL;
164 pch
= strtok(buffer
, " ");//strtok_s(buffer, " ", &context);
168 int wind
= atoi(pch
);
169 if (wind
< 1 || wind
> numN
)
171 cerr
<<"File read error: Illegal node index encountered\n";
178 G
.newEdge( indexToNode
[lineNum
], indexToNode
[wind
] );
182 pch
= strtok(NULL
, " ");//strtok_s(NULL, " ", &context);
183 }//while node entries
185 //cout <<"Read #nodes: "<<numN<<", #edges "<<runEdges<<"\n";
190 bool loadSimpleGraph(Graph
&G
, const char *fileName
) {
191 ifstream
is(fileName
);
192 if(!is
.good()) return false;
193 return loadSimpleGraph(G
, is
);
197 bool loadSimpleGraph(Graph
&G
, istream
&is
) {
200 char buffer
[SIMPLE_LOAD_BUFFER_SIZE
];
203 //try to read the two first lines to get the graph size
208 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
209 pch
= strtok(buffer
, " ");
210 if (strcmp(pch
, "*BEGIN") != 0) return false;
212 { //contains the size of the graph
213 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
214 pch
= strtok(buffer
, " ");
215 if (strcmp(pch
, "*GRAPH") != 0) return false;
216 //now read the number of nodes
217 pch
= strtok(NULL
, " ");
218 if (pch
== NULL
) return false;
220 //now read the number of edges
221 pch
= strtok(NULL
, " ");
222 if (pch
== NULL
) return false;
228 if (numN
== 0) return true;
230 Array
<node
> indexToNode(1,numN
,0);
231 for (int i
= 1; i
<= numN
; i
++)
233 //we assign new indexes here if they are not consecutive
234 //starting from 1 in the file!
235 indexToNode
[i
] = G
.newNode();
240 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
245 int srcIndex
, tgtIndex
;
246 sscanf(buffer
, "%d%d", &srcIndex
, &tgtIndex
);
248 pch
= strtok(buffer
, " ");
249 if ( (strcmp(pch
, "*END") == 0) || (strcmp(pch
, "*CHECKSUM") == 0) )
252 if(srcIndex
< 1 || srcIndex
> numN
|| tgtIndex
< 1 || tgtIndex
> numN
)
254 Logger::slout() << "loadSimpleGraph: illegal node index in edge specification.\n";
258 G
.newEdge(indexToNode
[srcIndex
], indexToNode
[tgtIndex
]);
264 #define YG_NEXTBYTE(x) x = fgetc(lineStream); if(x == EOF || x == '\n') { Logger::slout() << "loadYGraph: line too short!"; return false; } x &= 0x3F;
266 bool loadYGraph(Graph
&G
, FILE *lineStream
) {
278 for(i
= 1; i
<n
; ++i
) {
279 for(j
= 0; j
<i
; ++j
) {
285 G
.newEdge(A
[i
],A
[j
]);
289 c
= fgetc(lineStream
);
290 if(c
!= EOF
&& c
!= '\n') {
291 Logger::slout(Logger::LL_MINOR
) << "loadYGraph: Warning: line too long! ignoring...";
297 bool loadBenchHypergraph(Graph
&G
, List
<node
>& hypernodes
, List
<edge
> *shell
, const char *fileName
) {
298 ifstream
is(fileName
);
299 if(!is
.good()) return false;
300 return loadBenchHypergraph(G
, hypernodes
, shell
, is
);
304 bool loadPlaHypergraph(Graph
&G
, List
<node
>& hypernodes
, List
<edge
> *shell
, const char *fileName
) {
305 ifstream
is(fileName
);
306 if(!is
.good()) return false;
307 return loadPlaHypergraph(G
, hypernodes
, shell
, is
);
311 int extractIdentifierLength(char* from
, int line
) {
313 while(from
[p
]!=',' && from
[p
]!=')' && from
[p
]!=' ' && from
[p
]!='(') {
316 cerr
<< "Loading Hypergraph: Error in line " << line
<<
317 ". Expected comma, bracket or whitespace before EOL; Ignoring.\n";
325 int newStartPos(char* from
, int line
) {
327 while(from
[p
]=='\t' || from
[p
]==' ' || from
[p
]==',') {
330 cerr
<< "Loading Hypergraph: Error in line " << line
<<
331 ". Expected whitespace or delimiter before EOL; Ignoring.\n";
340 int findOpen(char* from
, int line
) {
342 while(from
[p
]!='(') {
345 cerr
<< "Loading Hypergraph: Error in line " << line
<<
346 ". Expected opening bracket before EOL; Ignoring.\n";
354 String
inName(const String
& s
) {
355 size_t n
= s
.length();
356 char *t
= new char[n
+4];
357 ogdf::strcpy(t
,s
.length()+1,s
.cstr());
358 t
[n
] = '%';t
[n
+1] = '$';t
[n
+2] = '@';t
[n
+3] = '\0';
365 bool loadBenchHypergraph(Graph
&G
, List
<node
>& hypernodes
, List
<edge
> *shell
, istream
&is
) {
368 if(shell
) shell
->clear();
371 char buffer
[SIMPLE_LOAD_BUFFER_SIZE
];
373 // Array<node> indexToNode(1,250,0);
375 HashArray
<String
,node
> hm(0);
378 // hypernodes.pushBack( si=G.newNode() );
379 // hypernodes.pushBack( so=G.newNode() );
380 // shell.pushBack( G.newEdge( si, so ) );
381 shell
->pushBack( G
.newEdge( si
=G
.newNode(), so
=G
.newNode() ) );
388 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
389 size_t l
= strlen(buffer
);
390 if( l
> 0 && buffer
[l
-1]=='\r' ) { // DOS line
393 if(!strlen(buffer
) || buffer
[0]==' ' || buffer
[0]=='#') continue;
394 if(!strncmp("INPUT(",buffer
,6)) {
395 String
s(extractIdentifierLength(buffer
+6, line
),buffer
+6);
396 node n
= G
.newNode();
398 hypernodes
.pushBack(n
);
399 if(shell
) shell
->pushBack( G
.newEdge(si
,n
) );
400 // cout << "input: " << s << " -> " << n->index() << "\n";
401 } else if(!strncmp("OUTPUT(",buffer
,7)) {
402 String
s(extractIdentifierLength(buffer
+7, line
),buffer
+7);
403 node n
= G
.newNode();
405 hypernodes
.pushBack(n
);
406 if(shell
) shell
->pushBack( G
.newEdge(n
,so
) );
407 // cout << "output: " << s << " -> " << n->index() << "\n";
409 int p
= extractIdentifierLength(buffer
, line
);
410 String
s(p
,buffer
); // gatename
411 node m
= hm
[s
]; // found as outputname -> refOut
413 m
= hm
[inName(s
)]; // found as innernode input.
414 if(!m
) { // generate it anew.
415 node in
= G
.newNode();
416 node out
= G
.newNode();
419 hypernodes
.pushBack(out
);
424 p
= findOpen(buffer
, line
);
427 p
+= newStartPos(buffer
+p
, line
);
428 int pp
= extractIdentifierLength(buffer
+p
, line
);
429 String
s(pp
,buffer
+p
);
434 node in
= G
.newNode();
435 node out
= G
.newNode();
438 hypernodes
.pushBack(out
);
443 // cout << "Edge: " << s << "(" << hm[s]->index() << ") TO " << m->index() << "\n";
444 } while(buffer
[p
] == ',');
451 bool loadPlaHypergraph(Graph
&G
, List
<node
>& hypernodes
, List
<edge
> *shell
, istream
&is
) {
454 if(shell
) shell
->clear();
460 // cout << "numGates=" << numGates << "\n";
462 Array
<node
> outport(1,numGates
);
463 for(i
= 1; i
<=numGates
; ++i
) {
464 node out
= G
.newNode();
466 hypernodes
.pushBack(out
);
469 for(i
= 1; i
<=numGates
; ++i
) {
470 int id
, type
, numinput
;
471 is
>> id
>> type
>> numinput
;
472 // cout << "Gate=" << i << ", type=" << type << ", numinput=" << numinput << ":";
473 if(id
!= i
) cerr
<< "Error loading PLA hypergraph: ID and linenum does not match\n";
474 node in
= G
.newNode();
475 G
.newEdge(in
,outport
[i
]);
476 for(int j
=0; j
<numinput
; ++j
) {
479 // cout << " " << from;
480 G
.newEdge(outport
[from
],in
);
487 shell
->pushBack( G
.newEdge( si
=G
.newNode(), so
=G
.newNode() ) );
491 if(n
->firstAdj()->theEdge()->source()==n
) { //input
492 shell
->pushBack( G
.newEdge( si
, n
) );
494 shell
->pushBack( G
.newEdge( n
, so
) );
505 bool loadEdgeListSubgraph(Graph
&G
, List
<edge
> &delEdges
, const char *fileName
)
507 ifstream
is(fileName
);
508 if(!is
.good()) return false;
509 return loadEdgeListSubgraph(G
, delEdges
, is
);
513 bool loadEdgeListSubgraph(Graph
&G
, List
<edge
> &delEdges
, istream
&is
)
518 char buffer
[SIMPLE_LOAD_BUFFER_SIZE
];
520 if(is
.eof()) return false;
521 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
523 int n
= 0, m
= 0, m_del
= 0;
524 sscanf(buffer
, "%d%d%d", &n
, &m
, &m_del
);
526 if(n
< 0 || m
< 0 || m_del
< 0)
529 Array
<node
> indexToNode(n
);
530 for(int i
= 0; i
< n
; ++i
)
531 indexToNode
[i
] = G
.newNode();
533 int m_all
= m
+ m_del
;
534 for(int i
= 0; i
< m_all
; ++i
) {
535 if(is
.eof()) return false;
537 is
.getline(buffer
, SIMPLE_LOAD_BUFFER_SIZE
-1);
539 sscanf(buffer
, "%d%d", &src
, &tgt
);
540 if(src
< 0 || src
>= n
|| tgt
< 0 || tgt
>= n
)
543 edge e
= G
.newEdge(indexToNode
[src
], indexToNode
[tgt
]);
546 delEdges
.pushBack(e
);
553 bool saveEdgeListSubgraph(const Graph
&G
, const List
<edge
> &delEdges
, const char *fileName
)
555 ofstream
os(fileName
);
556 return saveEdgeListSubgraph(G
,delEdges
,os
);
560 bool saveEdgeListSubgraph(const Graph
&G
, const List
<edge
> &delEdges
, ostream
&os
)
562 if(!os
.good()) return false;
564 const int m_del
= delEdges
.size();
565 const int n
= G
.numberOfNodes();
566 const int m
= G
.numberOfEdges() - m_del
;
568 os
<< n
<< " " << m
<< " " << m_del
<< "\n";
570 EdgeArray
<bool> markSub(G
,true);
571 for(ListConstIterator
<edge
> it
= delEdges
.begin(); it
.valid(); ++it
)
572 markSub
[*it
] = false;
574 NodeArray
<int> index(G
);
583 os
<< index
[e
->source()] << " " << index
[e
->target()] << "\n";
585 for(ListConstIterator
<edge
> it
= delEdges
.begin(); it
.valid(); ++it
)
586 os
<< index
[(*it
)->source()] << " " << index
[(*it
)->target()] << "\n";
593 bool loadChallengeGraph(Graph
&G
, GridLayout
&gl
, const char *fileName
)
595 ifstream
is(fileName
);
596 if(!is
.good()) return false;
597 return loadChallengeGraph(G
, gl
, is
);
601 #define CHALLENGE_LOAD_BUFFER_SIZE 4096
603 bool loadChallengeGraph(Graph
&G
, GridLayout
&gl
, istream
&is
)
606 char buffer
[CHALLENGE_LOAD_BUFFER_SIZE
];
610 if(is
.eof()) return false;
611 is
.getline(buffer
,CHALLENGE_LOAD_BUFFER_SIZE
);
612 if(buffer
[0] != '#') {
613 sscanf(buffer
, "%d", &n
);
614 if(n
< 0) return false;
618 Array
<node
> indexToNode(n
);
619 for(int i
= 0; i
< n
; ) {
620 if(is
.eof()) return false;
621 is
.getline(buffer
,CHALLENGE_LOAD_BUFFER_SIZE
);
623 if(buffer
[0] != '#') {
624 node v
= G
.newNode();
625 sscanf(buffer
, "%d%d", &gl
.x(v
), &gl
.y(v
));
626 indexToNode
[i
++] = v
;
631 is
.getline(buffer
,CHALLENGE_LOAD_BUFFER_SIZE
);
633 if(buffer
[0] != '#' && buffer
[0] != 0) {
634 std::stringstream
ss(buffer
);
635 int srcIndex
, tgtIndex
;
637 if(ss
.eof()) return false;
639 if(srcIndex
< 0 || srcIndex
>= n
) return false;
641 if(ss
.eof()) return false;
643 if(tgtIndex
< 0 || tgtIndex
>= n
) return false;
645 node src
= indexToNode
[srcIndex
];
646 node tgt
= indexToNode
[tgtIndex
];
647 edge e
= G
.newEdge(src
,tgt
);
650 if(ss
.eof()) return false;
652 if(symbol
!= "[") return false;
654 IPolyline
&ipl
= gl
.bends(e
);;
656 if(ss
.eof()) return false;
658 if(symbol
== "]") break;
661 ip
.m_x
= atoi(symbol
.c_str());
662 if(ss
.eof()) return false;
673 bool saveChallengeGraph(const Graph
&G
, const GridLayout
&gl
, const char *fileName
)
675 ofstream
os(fileName
);
676 return saveChallengeGraph(G
, gl
, os
);
680 bool saveChallengeGraph(const Graph
&G
, const GridLayout
&gl
, ostream
&os
)
682 if(!os
.good()) return false;
684 os
<< "# Number of Nodes\n";
685 os
<< G
.numberOfNodes() << "\n";
688 NodeArray
<int> index(G
);
692 os
<< gl
.x(v
) << " " << gl
.y(v
) << "\n";
699 os
<< index
[e
->source()] << " " << index
[e
->target()] << " [";
700 const IPolyline
&ipl
= gl
.bends(e
);
701 for(ListConstIterator
<IPoint
> it
= ipl
.begin(); it
.valid(); ++it
)
702 os
<< " " << (*it
).m_x
<< " " << (*it
).m_y
;