~ubuntu-branches/ubuntu/lucid/igraph/lucid

« back to all changes in this revision

Viewing changes to src/conversion.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Malaterre
  • Date: 2009-11-16 18:12:42 UTC
  • Revision ID: james.westby@ubuntu.com-20091116181242-mzv9p5fz9uj57xd1
Tags: upstream-0.5.3
ImportĀ upstreamĀ versionĀ 0.5.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C -*-  */
 
2
/* 
 
3
   IGraph library.
 
4
   Copyright (C) 2005  Gabor Csardi <csardi@rmki.kfki.hu>
 
5
   MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 
20
   02110-1301 USA
 
21
 
 
22
*/
 
23
 
 
24
#include "igraph.h"
 
25
#include "types.h"
 
26
#include "config.h"
 
27
 
 
28
/**
 
29
 * \ingroup conversion
 
30
 * \function igraph_get_adjacency
 
31
 * \brief Returns the adjacency matrix of a graph
 
32
 * 
 
33
 * </para><para>
 
34
 * The result is an incidence matrix, it contains numbers greater
 
35
 * than one if there are multiple edges in the graph.
 
36
 * \param graph Pointer to the graph to convert
 
37
 * \param res Pointer to an initialized matrix object, it will be
 
38
 *        resized if needed.
 
39
 * \param type Constant giving the type of the adjacency matrix to
 
40
 *        create for undirected graphs. It is ignored for directed
 
41
 *        graphs. Possible values:
 
42
 *        \clist
 
43
 *        \cli IGRAPH_GET_ADJACENCY_UPPER 
 
44
 *          the upper right triangle of the matrix is used.
 
45
 *        \cli IGRAPH_GET_ADJACENCY_LOWER 
 
46
 *          the lower left triangle of the matrix is used.
 
47
 *        \cli IGRAPH_GET_ADJACENCY_BOTH 
 
48
 *          the whole matrix is used, a symmetric matrix is returned.
 
49
 *        \endclist
 
50
 * \return Error code:
 
51
 *        \c IGRAPH_EINVAL invalid type argument.
 
52
 *
 
53
 * \sa igraph_get_adjacency_sparse if you want a sparse matrix representation
 
54
 *
 
55
 * Time complexity: O(|V||V|),
 
56
 * |V| is the 
 
57
 * number of vertices in the graph.
 
58
 */
 
59
 
 
60
int igraph_get_adjacency(const igraph_t *graph, igraph_matrix_t *res,
 
61
                         igraph_get_adjacency_t type) {
 
62
  
 
63
  igraph_eit_t edgeit;
 
64
  long int no_of_nodes=igraph_vcount(graph);
 
65
  igraph_bool_t directed=igraph_is_directed(graph);
 
66
  int retval=0;
 
67
  long int from, to;
 
68
  igraph_integer_t ffrom, fto;
 
69
  
 
70
  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes));
 
71
  igraph_matrix_null(res);
 
72
  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
 
73
  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
 
74
  
 
75
  if (directed) {
 
76
    while (!IGRAPH_EIT_END(edgeit)) {
 
77
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
78
      from=ffrom;
 
79
      to=fto;
 
80
      MATRIX(*res, from, to) += 1;
 
81
      IGRAPH_EIT_NEXT(edgeit);
 
82
    }
 
83
  } else if (type==IGRAPH_GET_ADJACENCY_UPPER) {
 
84
    while (!IGRAPH_EIT_END(edgeit)) {  
 
85
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
86
      from=ffrom;
 
87
      to=fto;
 
88
      if (to < from) {
 
89
        MATRIX(*res, to, from) += 1;
 
90
      } else {
 
91
        MATRIX(*res, from, to) += 1;    
 
92
      }
 
93
      IGRAPH_EIT_NEXT(edgeit);
 
94
    }
 
95
  } else if (type==IGRAPH_GET_ADJACENCY_LOWER) {
 
96
    while (!IGRAPH_EIT_END(edgeit)) {
 
97
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
98
      from=ffrom;
 
99
      to=fto;
 
100
      if (to < from) {
 
101
        MATRIX(*res, from, to) += 1;
 
102
      } else {
 
103
        MATRIX(*res, to, from) += 1;
 
104
      }
 
105
      IGRAPH_EIT_NEXT(edgeit);
 
106
    }
 
107
  } else if (type==IGRAPH_GET_ADJACENCY_BOTH) {
 
108
    while (!IGRAPH_EIT_END(edgeit)) {
 
109
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
110
      from=ffrom;
 
111
      to=fto;
 
112
      MATRIX(*res, from, to) += 1;
 
113
      if (from != to) {
 
114
        MATRIX(*res, to, from) += 1;
 
115
      }
 
116
      IGRAPH_EIT_NEXT(edgeit);
 
117
    }
 
118
  } else {
 
119
    IGRAPH_ERROR("Invalid type argument", IGRAPH_EINVAL);
 
120
  }
 
121
 
 
122
  igraph_eit_destroy(&edgeit);
 
123
  IGRAPH_FINALLY_CLEAN(1);
 
124
  return retval;
 
125
}
 
126
 
 
127
/**
 
128
 * \ingroup conversion
 
129
 * \function igraph_get_adjacency_sparse
 
130
 * \brief Returns the adjacency matrix of a graph in sparse matrix format
 
131
 * 
 
132
 * </para><para>
 
133
 * The result is an incidence matrix, it contains numbers greater
 
134
 * than one if there are multiple edges in the graph.
 
135
 * \param graph Pointer to the graph to convert
 
136
 * \param res Pointer to an initialized sparse matrix object, it will be
 
137
 *        resized if needed.
 
138
 * \param type Constant giving the type of the adjacency matrix to
 
139
 *        create for undirected graphs. It is ignored for directed
 
140
 *        graphs. Possible values:
 
141
 *        \clist
 
142
 *        \cli IGRAPH_GET_ADJACENCY_UPPER 
 
143
 *          the upper right triangle of the matrix is used.
 
144
 *        \cli IGRAPH_GET_ADJACENCY_LOWER 
 
145
 *          the lower left triangle of the matrix is used.
 
146
 *        \cli IGRAPH_GET_ADJACENCY_BOTH 
 
147
 *          the whole matrix is used, a symmetric matrix is returned.
 
148
 *        \endclist
 
149
 * \return Error code:
 
150
 *        \c IGRAPH_EINVAL invalid type argument.
 
151
 *
 
152
 * \sa igraph_get_adjacency if you would like to get a normal matrix
 
153
 *   ( \ref igraph_matrix_t )
 
154
 *
 
155
 * Time complexity: O(|V||V|),
 
156
 * |V| is the 
 
157
 * number of vertices in the graph.
 
158
 */
 
159
 
 
160
int igraph_get_adjacency_sparse(const igraph_t *graph, igraph_spmatrix_t *res,
 
161
                         igraph_get_adjacency_t type) {
 
162
  
 
163
  igraph_eit_t edgeit;
 
164
  long int no_of_nodes=igraph_vcount(graph);
 
165
  igraph_bool_t directed=igraph_is_directed(graph);
 
166
  int retval=0;
 
167
  long int from, to;
 
168
  igraph_integer_t ffrom, fto;
 
169
  
 
170
  igraph_spmatrix_null(res);
 
171
  IGRAPH_CHECK(igraph_spmatrix_resize(res, no_of_nodes, no_of_nodes));
 
172
  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
 
173
  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
 
174
  
 
175
  if (directed) {
 
176
    while (!IGRAPH_EIT_END(edgeit)) {
 
177
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
178
      from=ffrom;
 
179
      to=fto;
 
180
      igraph_spmatrix_add_e(res, from, to, 1);
 
181
      IGRAPH_EIT_NEXT(edgeit);
 
182
    }
 
183
  } else if (type==IGRAPH_GET_ADJACENCY_UPPER) {
 
184
    while (!IGRAPH_EIT_END(edgeit)) {  
 
185
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
186
      from=ffrom;
 
187
      to=fto;
 
188
      if (to < from) {
 
189
        igraph_spmatrix_add_e(res, to, from, 1);
 
190
      } else {
 
191
        igraph_spmatrix_add_e(res, from, to, 1);
 
192
      }
 
193
      IGRAPH_EIT_NEXT(edgeit);
 
194
    }
 
195
  } else if (type==IGRAPH_GET_ADJACENCY_LOWER) {
 
196
    while (!IGRAPH_EIT_END(edgeit)) {
 
197
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
198
      from=ffrom;
 
199
      to=fto;
 
200
      if (to > from) {
 
201
        igraph_spmatrix_add_e(res, to, from, 1);
 
202
      } else {
 
203
        igraph_spmatrix_add_e(res, from, to, 1);
 
204
      }
 
205
      IGRAPH_EIT_NEXT(edgeit);
 
206
    }
 
207
  } else if (type==IGRAPH_GET_ADJACENCY_BOTH) {
 
208
    while (!IGRAPH_EIT_END(edgeit)) {
 
209
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto);
 
210
      from=ffrom;
 
211
      to=fto;
 
212
      igraph_spmatrix_add_e(res, from, to, 1);
 
213
      if (from != to) {
 
214
        igraph_spmatrix_add_e(res, to, from, 1);
 
215
      }
 
216
      IGRAPH_EIT_NEXT(edgeit);
 
217
    }
 
218
  } else {
 
219
    IGRAPH_ERROR("Invalid type argument", IGRAPH_EINVAL);
 
220
  }
 
221
 
 
222
  igraph_eit_destroy(&edgeit);
 
223
  IGRAPH_FINALLY_CLEAN(1);
 
224
  return retval;
 
225
}
 
226
 
 
227
/**
 
228
 * \ingroup conversion
 
229
 * \function igraph_get_edgelist
 
230
 * \brief Returns the list of edges in a graph
 
231
 * 
 
232
 * </para><para>The order of the edges is given by the edge ids.
 
233
 * \param graph Pointer to the graph object
 
234
 * \param res Pointer to an initialized vector object, it will be
 
235
 *        resized.
 
236
 * \param bycol Logical, if true, the edges will be returned
 
237
 *        columnwise, eg. the first edge is
 
238
 *        <code>res[0]->res[|E|]</code>, the second is
 
239
 *        <code>res[1]->res[|E|+1]</code>, etc.
 
240
 * \return Error code.
 
241
 * 
 
242
 * Time complexity: O(|E|), the
 
243
 * number of edges in the graph.
 
244
 */
 
245
 
 
246
int igraph_get_edgelist(const igraph_t *graph, igraph_vector_t *res, igraph_bool_t bycol) {
 
247
 
 
248
  igraph_eit_t edgeit;
 
249
  long int no_of_edges=igraph_ecount(graph);
 
250
  long int vptr=0;
 
251
  igraph_integer_t from, to;
 
252
  
 
253
  IGRAPH_CHECK(igraph_vector_resize(res, no_of_edges*2));
 
254
  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID),
 
255
                                 &edgeit));
 
256
  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
 
257
  
 
258
  if (bycol) {
 
259
    while (!IGRAPH_EIT_END(edgeit)) {
 
260
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to);
 
261
      VECTOR(*res)[vptr]=from;
 
262
      VECTOR(*res)[vptr+no_of_edges]=to;
 
263
      vptr++;
 
264
      IGRAPH_EIT_NEXT(edgeit);
 
265
    }
 
266
  } else {
 
267
    while (!IGRAPH_EIT_END(edgeit)) {
 
268
      igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to);
 
269
      VECTOR(*res)[vptr++]=from;
 
270
      VECTOR(*res)[vptr++]=to;
 
271
      IGRAPH_EIT_NEXT(edgeit);
 
272
    }
 
273
  }
 
274
  
 
275
  igraph_eit_destroy(&edgeit);
 
276
  IGRAPH_FINALLY_CLEAN(1);
 
277
  return 0;
 
278
}
 
279
 
 
280
/**
 
281
 * \function igraph_to_directed
 
282
 * \brief Convert an undirected graph to a directed one
 
283
 * 
 
284
 * </para><para>
 
285
 * If the supplied graph is directed, this function does nothing.
 
286
 * \param graph The graph object to convert.
 
287
 * \param mode Constant, specifies the details of how exactly the
 
288
 *        conversion is done. Possible values: \c
 
289
 *        IGRAPH_TO_DIRECTED_ARBITRARY: the number of edges in the
 
290
 *        graph stays the same, an arbitrarily directed edge is
 
291
 *        created for each undirected edge; 
 
292
 *         \c IGRAPH_TO_DIRECTED_MUTUAL: two directed edges are
 
293
 *        created for each undirected edge, one in each direction.
 
294
 * \return Error code.
 
295
 * 
 
296
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 
297
 * of edges.
 
298
 */
 
299
 
 
300
int igraph_to_directed(igraph_t *graph,
 
301
                       igraph_to_directed_t mode) {
 
302
 
 
303
  if (mode != IGRAPH_TO_DIRECTED_ARBITRARY &&
 
304
      mode != IGRAPH_TO_DIRECTED_MUTUAL) {
 
305
    IGRAPH_ERROR("Cannot directed graph, invalid mode", IGRAPH_EINVAL);
 
306
  }
 
307
 
 
308
  if (igraph_is_directed(graph)) {
 
309
    return 0;
 
310
  }
 
311
 
 
312
  if (mode==IGRAPH_TO_DIRECTED_ARBITRARY) {
 
313
 
 
314
    igraph_t newgraph;
 
315
    igraph_vector_t edges;
 
316
    long int no_of_edges=igraph_ecount(graph);
 
317
    long int no_of_nodes=igraph_vcount(graph);
 
318
    long int size=no_of_edges*2;
 
319
    IGRAPH_VECTOR_INIT_FINALLY(&edges, size);
 
320
    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
 
321
 
 
322
    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes,
 
323
                               IGRAPH_DIRECTED));
 
324
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
 
325
    igraph_vector_destroy(&edges);
 
326
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
 
327
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
 
328
    IGRAPH_FINALLY_CLEAN(2);
 
329
    igraph_destroy(graph);
 
330
    *graph=newgraph;
 
331
 
 
332
  } else if (mode==IGRAPH_TO_DIRECTED_MUTUAL) {
 
333
    
 
334
    igraph_t newgraph;
 
335
    igraph_vector_t edges;
 
336
    igraph_vector_t index;
 
337
    long int no_of_edges=igraph_ecount(graph);
 
338
    long int no_of_nodes=igraph_vcount(graph);
 
339
    long int size=no_of_edges*4;
 
340
    long int i;
 
341
    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
 
342
    IGRAPH_CHECK(igraph_vector_reserve(&edges, size));
 
343
    IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));
 
344
    IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4));
 
345
    IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges*2);
 
346
    for (i=0; i<no_of_edges; i++) {
 
347
      VECTOR(edges)[no_of_edges*2+i*2]  =VECTOR(edges)[i*2+1];
 
348
      VECTOR(edges)[no_of_edges*2+i*2+1]=VECTOR(edges)[i*2];
 
349
      VECTOR(index)[i] = VECTOR(index)[no_of_edges+i] = i+1;
 
350
    }
 
351
 
 
352
    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes,
 
353
                               IGRAPH_DIRECTED));
 
354
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
 
355
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
 
356
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
 
357
    IGRAPH_CHECK(igraph_i_attribute_permute_edges(&newgraph, &index));
 
358
    
 
359
    igraph_vector_destroy(&index);
 
360
    igraph_vector_destroy(&edges);
 
361
    igraph_destroy(graph);
 
362
    IGRAPH_FINALLY_CLEAN(3);
 
363
    *graph=newgraph;
 
364
  }
 
365
  
 
366
  return 0;
 
367
}
 
368
 
 
369
/**
 
370
 * \function igraph_to_undirected
 
371
 * \brief Convert a directed graph to an undirected one.
 
372
 * 
 
373
 * </para><para>
 
374
 * If the supplied graph is undirected, this function does nothing.
 
375
 * \param graph The graph object to convert.
 
376
 * \param mode Constant, specifies the details of how exactly the
 
377
 *        convesion is done. Possible values: \c 
 
378
 *        IGRAPH_TO_UNDIRECTED_EACH: the number of edges remains
 
379
 *        constant, an undirected edge is created for each directed
 
380
 *        one, this version might create graphs with multiple edges; 
 
381
 *        \c IGRAPH_TO_UNDIRECTED_COLLAPSE: one undirected edge will
 
382
 *        be created for each pair of vertices which are connected
 
383
 *        with at least one directed edge, no multiple edges will be
 
384
 *        created. 
 
385
 * \return Error code.
 
386
 * 
 
387
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 
388
 * of edges. 
 
389
 */
 
390
 
 
391
int igraph_to_undirected(igraph_t *graph,
 
392
                         igraph_to_undirected_t mode) {
 
393
  long int no_of_nodes=igraph_vcount(graph);
 
394
  long int no_of_edges=igraph_ecount(graph);
 
395
  igraph_vector_t edges;
 
396
  igraph_t newgraph;
 
397
  
 
398
  if (mode != IGRAPH_TO_UNDIRECTED_EACH &&
 
399
      mode != IGRAPH_TO_UNDIRECTED_COLLAPSE) {
 
400
    IGRAPH_ERROR("Cannot undirect graph, invalid mode", IGRAPH_EINVAL);
 
401
  }
 
402
  
 
403
  if (!igraph_is_directed(graph)) {
 
404
    return 0;
 
405
  }
 
406
 
 
407
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
 
408
  
 
409
  if (mode==IGRAPH_TO_UNDIRECTED_EACH) {
 
410
    igraph_es_t es;
 
411
    igraph_eit_t eit;
 
412
 
 
413
    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
 
414
    IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
 
415
    IGRAPH_FINALLY(igraph_es_destroy, &es);
 
416
    IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
 
417
    IGRAPH_FINALLY(igraph_eit_destroy, &eit);
 
418
    
 
419
    while (!IGRAPH_EIT_END(eit)) {
 
420
      long int edge=IGRAPH_EIT_GET(eit);
 
421
      igraph_integer_t from, to;
 
422
      igraph_edge(graph, edge, &from, &to);
 
423
      IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
 
424
      IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
 
425
      IGRAPH_EIT_NEXT(eit);
 
426
    }
 
427
    
 
428
    igraph_eit_destroy(&eit);
 
429
    igraph_es_destroy(&es);
 
430
    IGRAPH_FINALLY_CLEAN(2);
 
431
    
 
432
    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED));
 
433
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
 
434
    igraph_vector_destroy(&edges);
 
435
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
 
436
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1);
 
437
    IGRAPH_FINALLY_CLEAN(2);
 
438
    igraph_destroy(graph);
 
439
    *graph=newgraph;
 
440
    
 
441
  } else if (mode==IGRAPH_TO_UNDIRECTED_COLLAPSE) {
 
442
    igraph_vector_t seen, nei;
 
443
    long int i,j;
 
444
    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
 
445
    IGRAPH_VECTOR_INIT_FINALLY(&seen, no_of_nodes);
 
446
    IGRAPH_VECTOR_INIT_FINALLY(&nei, 0);
 
447
    
 
448
    for (i=0; i<no_of_nodes; i++) {
 
449
      IGRAPH_CHECK(igraph_neighbors(graph, &nei, i, IGRAPH_ALL));
 
450
      for (j=0; j<igraph_vector_size(&nei); j++) {
 
451
        long int node=VECTOR(nei)[j];
 
452
        if (VECTOR(seen)[node] != i+1 && node >= i) {
 
453
          IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
 
454
          IGRAPH_CHECK(igraph_vector_push_back(&edges, node));
 
455
          VECTOR(seen)[node]=i+1;
 
456
        }
 
457
      }
 
458
    }
 
459
 
 
460
    igraph_vector_destroy(&nei);
 
461
    igraph_vector_destroy(&seen);
 
462
    IGRAPH_FINALLY_CLEAN(2);
 
463
 
 
464
    IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED));
 
465
    IGRAPH_FINALLY(igraph_destroy, &newgraph);
 
466
    igraph_vector_destroy(&edges);
 
467
    IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph);
 
468
    IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */
 
469
    IGRAPH_FINALLY_CLEAN(2);
 
470
    igraph_destroy(graph);
 
471
    *graph=newgraph;
 
472
  }
 
473
 
 
474
  return 0;
 
475
}