/** * \ingroup python_interface_vertexseq * \brief Copies a vertex sequence object * \return the copied PyObject */ igraphmodule_VertexSeqObject* igraphmodule_VertexSeq_copy(igraphmodule_VertexSeqObject* o) { igraphmodule_VertexSeqObject *copy; copy=(igraphmodule_VertexSeqObject*)PyType_GenericNew(Py_TYPE(o), 0, 0); if (copy == NULL) return NULL; if (igraph_vs_type(&o->vs) == IGRAPH_VS_VECTOR) { igraph_vector_t v; if (igraph_vector_copy(&v, o->vs.data.vecptr)) { igraphmodule_handle_igraph_error(); return 0; } if (igraph_vs_vector_copy(©->vs, &v)) { igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return 0; } igraph_vector_destroy(&v); } else { copy->vs = o->vs; } copy->gref = o->gref; if (o->gref) Py_INCREF(o->gref); RC_ALLOC("VertexSeq(copy)", copy); return copy; }
/* * Converts a Java VertexSet to an igraph_vs_t * @return: zero if everything went fine, 1 if a null pointer was passed */ int Java_net_sf_igraph_VertexSet_to_igraph_vs(JNIEnv *env, jobject jobj, igraph_vs_t *result) { jint typeHint; jobject idArray; if (jobj == 0) { IGRAPH_CHECK(igraph_vs_all(result)); return IGRAPH_SUCCESS; } typeHint = (*env)->CallIntMethod(env, jobj, net_sf_igraph_VertexSet_getTypeHint_mid); if (typeHint != 1 && typeHint != 2) { IGRAPH_CHECK(igraph_vs_all(result)); return IGRAPH_SUCCESS; } idArray = (*env)->CallObjectMethod(env, jobj, net_sf_igraph_VertexSet_getIdArray_mid); if ((*env)->ExceptionCheck(env)) { return IGRAPH_EINVAL; } if (typeHint == 1) { /* Single vertex */ jlong id[1]; (*env)->GetLongArrayRegion(env, idArray, 0, 1, id); IGRAPH_CHECK(igraph_vs_1(result, (igraph_integer_t)id[0])); } else if (typeHint == 2) { /* List of vertices */ jlong* ids; igraph_vector_t vec; long i, n; ids = (*env)->GetLongArrayElements(env, idArray, 0); n = (*env)->GetArrayLength(env, idArray); IGRAPH_VECTOR_INIT_FINALLY(&vec, n); for (i = 0; i < n; i++) VECTOR(vec)[i] = ids[i]; IGRAPH_CHECK(igraph_vs_vector_copy(result, &vec)); igraph_vector_destroy(&vec); IGRAPH_FINALLY_CLEAN(1); (*env)->ReleaseLongArrayElements(env, idArray, ids, JNI_ABORT); } (*env)->DeleteLocalRef(env, idArray); return IGRAPH_SUCCESS; }
/** * \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_vertexseq * \brief Selects a subset of the vertex sequence based on some criteria */ PyObject* igraphmodule_VertexSeq_select(igraphmodule_VertexSeqObject *self, PyObject *args) { igraphmodule_VertexSeqObject *result; igraphmodule_GraphObject *gr; long i, j, n, m; gr=self->gref; result=igraphmodule_VertexSeq_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_vs_destroy(&result->vs); igraph_vs_none(&result->vs); /* We can simply bail out here */ return (PyObject*)result; } else if (PyCallable_Check(item)) { /* Call the callable for every vertex 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 *vertex = PySequence_GetItem((PyObject*)result, j); PyObject *call_result; if (vertex == 0) { Py_DECREF(result); igraph_vector_destroy(&v); return NULL; } call_result = PyObject_CallFunctionObjArgs(item, vertex, NULL); if (call_result == 0) { Py_DECREF(vertex); Py_DECREF(result); igraph_vector_destroy(&v); return NULL; } if (PyObject_IsTrue(call_result)) igraph_vector_push_back(&v, igraphmodule_Vertex_get_index_long((igraphmodule_VertexObject*)vertex)); else was_excluded=1; Py_DECREF(call_result); Py_DECREF(vertex); } if (was_excluded) { igraph_vs_destroy(&result->vs); if (igraph_vs_vector_copy(&result->vs, &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 vertex set. Integers are interpreted as indices on the * vertex set and NOT on the original, untouched vertex 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_vs_as_vector(&gr->g, self->vs, &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, "vertex 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, "vertex 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_vs_destroy(&result->vs); if (igraph_vs_vector_copy(&result->vs, &v)) { Py_DECREF(result); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return NULL; } igraph_vector_destroy(&v); } else { /* Iterators, slices and everything that was not handled directly */ PyObject *iter=0, *item2; igraph_vector_t v, v2; /* Allocate stuff */ if (igraph_vector_init(&v, 0)) { igraphmodule_handle_igraph_error(); Py_DECREF(result); return 0; } if (igraph_vector_init(&v2, 0)) { igraph_vector_destroy(&v); Py_DECREF(result); igraphmodule_handle_igraph_error(); return 0; } if (igraph_vs_as_vector(&gr->g, self->vs, &v2)) { igraph_vector_destroy(&v); igraph_vector_destroy(&v2); Py_DECREF(result); 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 vertex 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, "vertex 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_vs_destroy(&result->vs); if (igraph_vs_vector_copy(&result->vs, &v)) { Py_DECREF(result); igraphmodule_handle_igraph_error(); igraph_vector_destroy(&v); return NULL; } igraph_vector_destroy(&v); } } return (PyObject*)result; }