4
Copyright (C) 2006 Gabor Csardi <csardi@rmki.kfki.hu>
5
MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
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.
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.
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
25
#include "vertexobject.h"
30
* \ingroup python_interface
31
* \defgroup python_interface_bfsiter BFS iterator object
34
PyTypeObject igraphmodule_BFSIterType;
37
* \ingroup python_interface_bfsiter
38
* \brief Allocate a new BFS iterator object for a given graph and a given root
39
* \param g the graph object being referenced
40
* \param vid the root vertex index
41
* \param advanced whether the iterator should be advanced (returning distance and parent as well)
42
* \return the allocated PyObject
44
PyObject* igraphmodule_BFSIter_new(igraphmodule_GraphObject *g, PyObject *root, igraph_neimode_t mode, igraph_bool_t advanced) {
45
igraphmodule_BFSIterObject* o;
46
long int no_of_nodes, r;
48
o=PyObject_GC_New(igraphmodule_BFSIterObject, &igraphmodule_BFSIterType);
53
if (!PyInt_Check(root) && !PyObject_IsInstance(root, (PyObject*)&igraphmodule_VertexType)) {
54
PyErr_SetString(PyExc_TypeError, "root must be integer or igraph.Vertex");
58
no_of_nodes=igraph_vcount(&g->g);
59
o->visited=(char*)calloc(no_of_nodes, sizeof(char));
60
if (o->visited == 0) {
61
PyErr_SetString(PyExc_MemoryError, "out of memory");
65
if (igraph_dqueue_init(&o->queue, 100)) {
66
PyErr_SetString(PyExc_MemoryError, "out of memory");
69
if (igraph_vector_init(&o->neis, 0)) {
70
PyErr_SetString(PyExc_MemoryError, "out of memory");
71
igraph_dqueue_destroy(&o->queue);
75
if (PyInt_Check(root)) {
78
r=((igraphmodule_VertexObject*)root)->idx;
80
if (igraph_dqueue_push(&o->queue, r) ||
81
igraph_dqueue_push(&o->queue, 0) ||
82
igraph_dqueue_push(&o->queue, -1)) {
83
igraph_dqueue_destroy(&o->queue);
84
igraph_vector_destroy(&o->neis);
85
PyErr_SetString(PyExc_MemoryError, "out of memory");
90
if (!igraph_is_directed(&g->g)) mode=IGRAPH_ALL;
96
RC_ALLOC("BFSIter", o);
102
* \ingroup python_interface_bfsiter
103
* \brief Support for cyclic garbage collection in Python
105
* This is necessary because the \c igraph.BFSIter object contains several
106
* other \c PyObject pointers and they might point back to itself.
108
int igraphmodule_BFSIter_traverse(igraphmodule_BFSIterObject *self,
109
visitproc visit, void *arg) {
112
RC_TRAVERSE("BFSIter", self);
115
vret=visit((PyObject*)self->gref, arg);
116
if (vret != 0) return vret;
123
* \ingroup python_interface_bfsiter
124
* \brief Clears the iterator's subobject (before deallocation)
126
int igraphmodule_BFSIter_clear(igraphmodule_BFSIterObject *self) {
129
PyObject_GC_UnTrack(self);
131
tmp=(PyObject*)self->gref;
135
igraph_dqueue_destroy(&self->queue);
136
igraph_vector_destroy(&self->neis);
144
* \ingroup python_interface_bfsiter
145
* \brief Deallocates a Python representation of a given BFS iterator object
147
void igraphmodule_BFSIter_dealloc(igraphmodule_BFSIterObject* self) {
148
igraphmodule_BFSIter_clear(self);
150
RC_DEALLOC("BFSIter", self);
152
PyObject_GC_Del(self);
155
PyObject* igraphmodule_BFSIter_iter(igraphmodule_BFSIterObject* self) {
157
return (PyObject*)self;
160
PyObject* igraphmodule_BFSIter_iternext(igraphmodule_BFSIterObject* self) {
161
if (!igraph_dqueue_empty(&self->queue)) {
162
long int vid = igraph_dqueue_pop(&self->queue);
163
long int dist = igraph_dqueue_pop(&self->queue);
164
long int parent = igraph_dqueue_pop(&self->queue);
167
if (igraph_neighbors(self->graph, &self->neis, vid, self->mode)) {
168
igraphmodule_handle_igraph_error();
172
for (i=0; i<igraph_vector_size(&self->neis); i++) {
173
long int neighbor=VECTOR(self->neis)[i];
174
if (self->visited[neighbor]==0) {
175
self->visited[neighbor]=1;
176
if (igraph_dqueue_push(&self->queue, neighbor) ||
177
igraph_dqueue_push(&self->queue, dist+1) ||
178
igraph_dqueue_push(&self->queue, vid)) {
179
igraphmodule_handle_igraph_error();
185
if (self->advanced) {
186
PyObject *vertexobj, *parentobj, *result;
187
vertexobj = igraphmodule_Vertex_New(self->gref, (long)vid);
188
if (!vertexobj) return NULL;
190
parentobj = igraphmodule_Vertex_New(self->gref, (long)parent);
191
if (!parentobj) return NULL;
196
result=PyTuple_New(3);
197
PyTuple_SetItem(result, 0, vertexobj);
198
PyTuple_SetItem(result, 1, PyInt_FromLong(dist));
199
PyTuple_SetItem(result, 2, parentobj);
202
return igraphmodule_Vertex_New(self->gref, (long)vid);
209
* \ingroup python_interface_bfsiter
210
* Method table for the \c igraph.BFSIter object
212
PyMethodDef igraphmodule_BFSIter_methods[] = {
216
/** \ingroup python_interface_bfsiter
217
* Python type object referencing the methods Python calls when it performs various operations on
218
* a BFS iterator of a graph
220
PyTypeObject igraphmodule_BFSIterType =
222
PyObject_HEAD_INIT(NULL) //
224
"igraph.BFSIter", // tp_name
225
sizeof(igraphmodule_BFSIterObject), // tp_basicsize
227
(destructor)igraphmodule_BFSIter_dealloc, // tp_dealloc
242
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, // tp_flags
243
"igraph BFS iterator object", // tp_doc
244
(traverseproc) igraphmodule_BFSIter_traverse, /* tp_traverse */
245
(inquiry) igraphmodule_BFSIter_clear, /* tp_clear */
247
0, // tp_weaklistoffset
248
(getiterfunc)igraphmodule_BFSIter_iter, /* tp_iter */
249
(iternextfunc)igraphmodule_BFSIter_iternext, /* tp_iternext */
255
0, /* tp_descr_get */
256
0, /* tp_descr_set */
257
0, /* tp_dictoffset */