/** * \ingroup python_interface_edgeseq * \brief Copies an edge sequence object * \return the copied PyObject */ igraphmodule_EdgeSeqObject* igraphmodule_EdgeSeq_copy(igraphmodule_EdgeSeqObject* o) { igraphmodule_EdgeSeqObject *copy; copy=(igraphmodule_EdgeSeqObject*)PyType_GenericNew(Py_TYPE(o), 0, 0); if (copy == NULL) return NULL; if (igraph_es_type(&o->es) == IGRAPH_ES_VECTOR) { igraph_vector_t v; if (igraph_vector_copy(&v, o->es.data.vecptr)) { igraphmodule_handle_igraph_error(); return 0; } if (igraph_es_vector_copy(©->es, &v)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return 0; } igraph_vector_destroy(&v); } else { copy->es = o->es; } copy->gref = o->gref; if (o->gref) Py_INCREF(o->gref); RC_ALLOC("EdgeSeq(copy)", copy); return copy; }
/** * \ingroup python_interface_edge * Returns the target node index of an edge */ PyObject* igraphmodule_Edge_get_tuple(igraphmodule_EdgeObject* self, void* closure) { igraphmodule_GraphObject *o = self->gref; igraph_integer_t from, to; if (igraph_edge(&o->g, self->idx, &from, &to)) { igraphmodule_handle_igraph_error(); return NULL; } return Py_BuildValue("(ii)", (long)from, (long)to); }
/** * \ingroup python_interface_edge * Returns the target node index of an edge */ PyObject* igraphmodule_Edge_get_to(igraphmodule_EdgeObject* self, void* closure) { igraphmodule_GraphObject *o = self->gref; igraph_integer_t from, to; if (igraph_edge(&o->g, self->idx, &from, &to)) { igraphmodule_handle_igraph_error(); return NULL; } return PyInt_FromLong((long)to); }
/** * \ingroup python_interface_edgeseq * \brief Returns the length of the sequence (i.e. the number of edges in the graph) */ int igraphmodule_EdgeSeq_sq_length(igraphmodule_EdgeSeqObject* self) { igraph_t *g; igraph_integer_t result; g=&GET_GRAPH(self); if (igraph_es_size(g, &self->es, &result)) { igraphmodule_handle_igraph_error(); return -1; } return (int)result; }
/** * \ingroup python_interface_vertexseq * \brief Returns the length of the sequence */ int igraphmodule_VertexSeq_sq_length(igraphmodule_VertexSeqObject* self) { igraph_t *g; igraph_integer_t result; if (!self->gref) return -1; g=&GET_GRAPH(self); if (igraph_vs_size(g, &self->vs, &result)) { igraphmodule_handle_igraph_error(); return -1; } return (int)result; }
/** * \ingroup python_interface_edgeseq * Returns the indices of the edges in this edge sequence */ PyObject* igraphmodule_EdgeSeq_get_indices(igraphmodule_EdgeSeqObject* self, void* closure) { igraphmodule_GraphObject *gr = self->gref; igraph_vector_t es; PyObject *result; if (igraph_vector_init(&es, 0)) { igraphmodule_handle_igraph_error(); return 0; } if (igraph_es_as_vector(&gr->g, self->es, &es)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&es); return 0; } result = igraphmodule_vector_t_to_PyList(&es, IGRAPHMODULE_TYPE_INT); igraph_vector_destroy(&es); return result; }
/** * \ingroup python_interface_edge * Returns the source node index of an edge */ PyObject* igraphmodule_Edge_get_from(igraphmodule_EdgeObject* self, void* closure) { igraphmodule_GraphObject *o = self->gref; igraph_integer_t from, to; if (!igraphmodule_Edge_Validate((PyObject*)self)) return NULL; if (igraph_edge(&o->g, self->idx, &from, &to)) { igraphmodule_handle_igraph_error(); return NULL; } return PyInt_FromLong((long int)from); }
/** * \ingroup python_interface_edgeseq * \brief Initialize a new edge sequence object for a given graph * \return the initialized PyObject */ int igraphmodule_EdgeSeq_init(igraphmodule_EdgeSeqObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "graph", "edges", NULL }; PyObject *g, *esobj=Py_None; igraph_es_t es; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O", kwlist, &igraphmodule_GraphType, &g, &esobj)) return -1; if (esobj == Py_None) { /* If es is None, we are selecting all the edges */ igraph_es_all(&es, IGRAPH_EDGEORDER_ID); } else if (PyInt_Check(esobj)) { /* We selected a single edge */ long int idx = PyInt_AsLong(esobj); if (idx < 0 || idx >= igraph_ecount(&((igraphmodule_GraphObject*)g)->g)) { PyErr_SetString(PyExc_ValueError, "edge index out of range"); return -1; } igraph_es_1(&es, (igraph_integer_t)idx); } else { /* We selected multiple edges */ igraph_vector_t v; igraph_integer_t n = igraph_ecount(&((igraphmodule_GraphObject*)g)->g); if (igraphmodule_PyObject_to_vector_t(esobj, &v, 1)) return -1; if (!igraph_vector_isininterval(&v, 0, n-1)) { igraph_vector_destroy(&v); PyErr_SetString(PyExc_ValueError, "edge index out of range"); return -1; } if (igraph_es_vector_copy(&es, &v)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return -1; } igraph_vector_destroy(&v); } self->es = es; Py_INCREF(g); self->gref = (igraphmodule_GraphObject*)g; return 0; }
/** * \ingroup python_interface_vertexseq * \brief Initialize a new vertex sequence object for a given graph * \return the initialized PyObject */ int igraphmodule_VertexSeq_init(igraphmodule_VertexSeqObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "graph", "vertices", NULL }; PyObject *g, *vsobj=Py_None; igraph_vs_t vs; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O", kwlist, &igraphmodule_GraphType, &g, &vsobj)) return -1; if (vsobj == Py_None) { /* If vs is None, we are selecting all the vertices */ igraph_vs_all(&vs); } else if (PyInt_Check(vsobj)) { /* We selected a single vertex */ long int idx = PyInt_AsLong(vsobj); if (idx < 0 || idx >= igraph_vcount(&((igraphmodule_GraphObject*)g)->g)) { PyErr_SetString(PyExc_ValueError, "vertex index out of range"); return -1; } igraph_vs_1(&vs, (igraph_integer_t)idx); } else { igraph_vector_t v; igraph_integer_t n = igraph_vcount(&((igraphmodule_GraphObject*)g)->g); if (igraphmodule_PyObject_to_vector_t(vsobj, &v, 1)) return -1; if (!igraph_vector_isininterval(&v, 0, n-1)) { igraph_vector_destroy(&v); PyErr_SetString(PyExc_ValueError, "vertex index out of range"); return -1; } if (igraph_vs_vector_copy(&vs, &v)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return -1; } igraph_vector_destroy(&v); } self->vs = vs; Py_INCREF(g); self->gref = (igraphmodule_GraphObject*)g; return 0; }
/** * \ingroup python_interface_edgeseq * \brief Selects a subset of the edge sequence based on some criteria */ PyObject* igraphmodule_EdgeSeq_select(igraphmodule_EdgeSeqObject *self, PyObject *args) { igraphmodule_EdgeSeqObject *result; igraphmodule_GraphObject *gr; long i, j, n, m; gr=self->gref; result=igraphmodule_EdgeSeq_copy(self); if (result == 0) return NULL; /* First, filter by positional arguments */ n = PyTuple_Size(args); for (i=0; i<n; i++) { PyObject *item = PyTuple_GET_ITEM(args, i); if (item == Py_None) { /* None means: select nothing */ igraph_es_destroy(&result->es); igraph_es_none(&result->es); /* We can simply bail out here */ return (PyObject*)result; } else if (PyCallable_Check(item)) { /* Call the callable for every edge in the current sequence to * determine what's up */ igraph_bool_t was_excluded = 0; igraph_vector_t v; if (igraph_vector_init(&v, 0)) { igraphmodule_handle_igraph_error(); return 0; } m = PySequence_Size((PyObject*)result); for (j=0; j<m; j++) { PyObject *edge = PySequence_GetItem((PyObject*)result, j); PyObject *call_result; if (edge == 0) { Py_DECREF(result); igraph_vector_destroy(&v); return NULL; } call_result = PyObject_CallFunctionObjArgs(item, edge, NULL); if (call_result == 0) { Py_DECREF(edge); Py_DECREF(result); igraph_vector_destroy(&v); return NULL; } if (PyObject_IsTrue(call_result)) igraph_vector_push_back(&v, igraphmodule_Edge_get_index_long((igraphmodule_EdgeObject*)edge)); else was_excluded=1; Py_DECREF(call_result); Py_DECREF(edge); } if (was_excluded) { igraph_es_destroy(&result->es); if (igraph_es_vector_copy(&result->es, &v)) { Py_DECREF(result); igraph_vector_destroy(&v); igraphmodule_handle_igraph_error(); return NULL; } } igraph_vector_destroy(&v); } else if (PyInt_Check(item)) { /* Integers are treated specially: from now on, all remaining items * in the argument list must be integers and they will be used together * to restrict the edge set. Integers are interpreted as indices on the * edge set and NOT on the original, untouched edge sequence of the * graph */ igraph_vector_t v, v2; if (igraph_vector_init(&v, 0)) { igraphmodule_handle_igraph_error(); return 0; } if (igraph_vector_init(&v2, 0)) { igraph_vector_destroy(&v); igraphmodule_handle_igraph_error(); return 0; } if (igraph_es_as_vector(&gr->g, self->es, &v2)) { igraph_vector_destroy(&v); igraph_vector_destroy(&v2); igraphmodule_handle_igraph_error(); return 0; } m = igraph_vector_size(&v2); for (; i<n; i++) { PyObject *item2 = PyTuple_GET_ITEM(args, i); long idx; if (!PyInt_Check(item2)) { Py_DECREF(result); PyErr_SetString(PyExc_TypeError, "edge indices expected"); igraph_vector_destroy(&v); igraph_vector_destroy(&v2); return NULL; } idx = PyInt_AsLong(item2); if (idx >= m || idx < 0) { PyErr_SetString(PyExc_ValueError, "edge index out of range"); igraph_vector_destroy(&v); igraph_vector_destroy(&v2); return NULL; } if (igraph_vector_push_back(&v, VECTOR(v2)[idx])) { Py_DECREF(result); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); igraph_vector_destroy(&v2); return NULL; } } igraph_vector_destroy(&v2); igraph_es_destroy(&result->es); if (igraph_es_vector_copy(&result->es, &v)) { Py_DECREF(result); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return NULL; } igraph_vector_destroy(&v); } else { /* Iterators and everything that was not handled directly */ PyObject *iter, *item2; igraph_vector_t v, v2; /* Allocate stuff */ if (igraph_vector_init(&v, 0)) { igraphmodule_handle_igraph_error(); return 0; } if (igraph_vector_init(&v2, 0)) { igraph_vector_destroy(&v); igraphmodule_handle_igraph_error(); return 0; } if (igraph_es_as_vector(&gr->g, self->es, &v2)) { igraph_vector_destroy(&v); igraph_vector_destroy(&v2); igraphmodule_handle_igraph_error(); return 0; } m = igraph_vector_size(&v2); /* Create an appropriate iterator */ if (PySlice_Check(item)) { /* Create an iterator from the slice (which is not iterable by default )*/ Py_ssize_t start, stop, step, sl; PyObject* range; igraph_bool_t ok; /* Casting to void* because Python 2.x expects PySliceObject* * but Python 3.x expects PyObject* */ ok = (PySlice_GetIndicesEx((void*)item, igraph_vector_size(&v2), &start, &stop, &step, &sl) == 0); if (ok) { range = igraphmodule_PyRange_create(start, stop, step); ok = (range != 0); } if (ok) { iter = PyObject_GetIter(range); Py_DECREF(range); ok = (iter != 0); } if (!ok) { igraph_vector_destroy(&v); igraph_vector_destroy(&v2); PyErr_SetString(PyExc_TypeError, "error while converting slice to iterator"); Py_DECREF(result); return 0; } } else { /* Simply create the iterator corresponding to the object */ iter = PyObject_GetIter(item); } /* Did we manage to get an iterator? */ if (iter == 0) { igraph_vector_destroy(&v); igraph_vector_destroy(&v2); PyErr_SetString(PyExc_TypeError, "invalid edge filter among positional arguments"); Py_DECREF(result); return 0; } /* Do the iteration */ while ((item2=PyIter_Next(iter)) != 0) { if (PyInt_Check(item2)) { long idx = PyInt_AsLong(item2); Py_DECREF(item2); if (idx >= m || idx < 0) { PyErr_SetString(PyExc_ValueError, "edge index out of range"); Py_DECREF(result); Py_DECREF(iter); igraph_vector_destroy(&v); igraph_vector_destroy(&v2); return NULL; } if (igraph_vector_push_back(&v, VECTOR(v2)[idx])) { Py_DECREF(result); Py_DECREF(iter); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); igraph_vector_destroy(&v2); return NULL; } } else { /* We simply ignore elements that we don't know */ Py_DECREF(item2); } } /* Deallocate stuff */ igraph_vector_destroy(&v2); Py_DECREF(iter); if (PyErr_Occurred()) { igraph_vector_destroy(&v); Py_DECREF(result); return 0; } igraph_es_destroy(&result->es); if (igraph_es_vector_copy(&result->es, &v)) { Py_DECREF(result); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return NULL; } igraph_vector_destroy(&v); } } return (PyObject*)result; }
/** \ingroup python_interface_edgeseq * \brief Sets the list of values for a given attribute */ int igraphmodule_EdgeSeq_set_attribute_values_mapping(igraphmodule_EdgeSeqObject* self, PyObject* attrname, PyObject* values) { PyObject *dict, *list, *item; igraphmodule_GraphObject *gr; igraph_vector_t es; long i, j, n, no_of_edges; gr = self->gref; dict = ATTR_STRUCT_DICT(&gr->g)[ATTRHASH_IDX_EDGE]; if (!igraphmodule_attribute_name_check(attrname)) return -1; if (values == 0) { if (igraph_es_type(&self->es) == IGRAPH_ES_ALL) return PyDict_DelItem(dict, attrname); PyErr_SetString(PyExc_TypeError, "can't delete attribute from an edge sequence not representing the whole graph"); return -1; } if (PyString_Check(values) || !PySequence_Check(values)) { /* If values is a string or not a sequence, we construct a list with a * single element (the value itself) and then call ourselves again */ int result; PyObject *newList = PyList_New(1); if (newList == 0) return -1; Py_INCREF(values); PyList_SET_ITEM(newList, 0, values); /* reference stolen here */ result = igraphmodule_EdgeSeq_set_attribute_values_mapping(self, attrname, newList); Py_DECREF(newList); return result; } n=PySequence_Size(values); if (n<0) return -1; if (igraph_es_type(&self->es) == IGRAPH_ES_ALL) { no_of_edges = (long)igraph_ecount(&gr->g); if (n == 0 && no_of_edges > 0) { PyErr_SetString(PyExc_ValueError, "sequence must not be empty"); return -1; } /* Check if we already have attributes with the given name */ list = PyDict_GetItem(dict, attrname); if (list != 0) { /* Yes, we have. Modify its items to the items found in values */ for (i=0, j=0; i<no_of_edges; i++, j++) { if (j == n) j = 0; item = PySequence_GetItem(values, j); if (item == 0) return -1; /* No need to Py_INCREF(item), PySequence_GetItem returns a new reference */ if (PyList_SetItem(list, i, item)) { Py_DECREF(item); return -1; } /* PyList_SetItem stole a reference to the item automatically */ } } else if (values != 0) { /* We don't have attributes with the given name yet. Create an entry * in the dict, create a new list and copy everything */ list = PyList_New(no_of_edges); if (list == 0) return -1; for (i=0, j=0; i<no_of_edges; i++, j++) { if (j == n) j = 0; item = PySequence_GetItem(values, j); if (item == 0) { Py_DECREF(list); return -1; } /* No need to Py_INCREF(item), PySequence_GetItem returns a new reference */ PyList_SET_ITEM(list, i, item); /* PyList_SET_ITEM stole a reference to the item automatically */ } if (PyDict_SetItem(dict, attrname, list)) { Py_DECREF(list); return -1; } Py_DECREF(list); /* compensating for PyDict_SetItem */ } } else { /* We are working with a subset of the graph. Convert the sequence to a * vector and loop through it */ if (igraph_vector_init(&es, 0)) { igraphmodule_handle_igraph_error(); return -1; } if (igraph_es_as_vector(&gr->g, self->es, &es)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&es); return -1; } no_of_edges = (long)igraph_vector_size(&es); if (n == 0 && no_of_edges > 0) { PyErr_SetString(PyExc_ValueError, "sequence must not be empty"); igraph_vector_destroy(&es); return -1; } /* Check if we already have attributes with the given name */ list = PyDict_GetItem(dict, attrname); if (list != 0) { /* Yes, we have. Modify its items to the items found in values */ for (i=0, j=0; i<no_of_edges; i++, j++) { if (j == n) j = 0; item = PySequence_GetItem(values, j); if (item == 0) { igraph_vector_destroy(&es); return -1; } /* No need to Py_INCREF(item), PySequence_GetItem returns a new reference */ if (PyList_SetItem(list, (long)VECTOR(es)[i], item)) { Py_DECREF(item); igraph_vector_destroy(&es); return -1; } /* PyList_SetItem stole a reference to the item automatically */ } igraph_vector_destroy(&es); } else if (values != 0) { /* We don't have attributes with the given name yet. Create an entry * in the dict, create a new list, fill with None for vertices not in the * sequence and copy the rest */ long n2 = igraph_ecount(&gr->g); list = PyList_New(n2); if (list == 0) { igraph_vector_destroy(&es); return -1; } for (i=0; i<n2; i++) { Py_INCREF(Py_None); PyList_SET_ITEM(list, i, Py_None); } for (i=0, j=0; i<no_of_edges; i++, j++) { if (j == n) j = 0; item = PySequence_GetItem(values, j); if (item == 0) { igraph_vector_destroy(&es); Py_DECREF(list); return -1; } /* No need to Py_INCREF(item), PySequence_GetItem returns a new reference */ PyList_SET_ITEM(list, (long)VECTOR(es)[i], item); /* PyList_SET_ITEM stole a reference to the item automatically */ } igraph_vector_destroy(&es); if (PyDict_SetItem(dict, attrname, list)) { Py_DECREF(list); return -1; } Py_DECREF(list); /* compensating for PyDict_SetItem */ } } return 0; }
/** * \ingroup python_interface_vertexseq * \brief Selects a single vertex from the vertex sequence based on some criteria */ PyObject* igraphmodule_VertexSeq_find(igraphmodule_VertexSeqObject *self, PyObject *args) { PyObject *item; igraph_integer_t i; Py_ssize_t n; igraph_vit_t vit; if (!PyArg_ParseTuple(args, "O", &item)) return NULL; if (PyCallable_Check(item)) { /* Call the callable for every vertex in the current sequence and return * the first one for which it evaluates to True */ n = PySequence_Size((PyObject*)self); for (i=0; i<n; i++) { PyObject *vertex = PySequence_GetItem((PyObject*)self, i); PyObject *call_result; if (vertex == 0) return NULL; call_result = PyObject_CallFunctionObjArgs(item, vertex, NULL); if (call_result == 0) { Py_DECREF(vertex); return NULL; } if (PyObject_IsTrue(call_result)) { Py_DECREF(call_result); return vertex; /* reference passed to caller */ } Py_DECREF(call_result); Py_DECREF(vertex); } } else if (PyInt_Check(item)) { /* Integers are interpreted as indices on the vertex set and NOT on the * original, untouched vertex sequence of the graph */ return PySequence_GetItem((PyObject*)self, PyInt_AsLong(item)); } else if (PyBaseString_Check(item)) { /* Strings are interpreted as vertex names */ if (igraphmodule_get_vertex_id_by_name(&self->gref->g, item, &i)) return NULL; /* We now have the ID of the vertex in the graph. If the vertex sequence * itself represents the full vertex sequence of the graph, we can return * here. If not, we have to check whether the vertex sequence contains this * ID or not. */ if (igraph_vs_is_all(&self->vs)) return PySequence_GetItem((PyObject*)self, i); if (igraph_vit_create(&self->gref->g, self->vs, &vit)) { igraphmodule_handle_igraph_error(); return NULL; } for (n = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), n++) { if (IGRAPH_VIT_GET(vit) == i) { igraph_vit_destroy(&vit); return PySequence_GetItem((PyObject*)self, n); } } igraph_vit_destroy(&vit); PyErr_SetString(PyExc_ValueError, "vertex with the given name exists but not in the current sequence"); return NULL; } PyErr_SetString(PyExc_IndexError, "no such vertex"); return NULL; }