Пример #1
0
/**
 * \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(&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;
}
Пример #2
0
/**
 * \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);
}
Пример #3
0
/**
 * \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);
}
Пример #4
0
/**
 * \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;
}
Пример #5
0
/**
 * \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;
}
Пример #6
0
/**
 * \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;
}
Пример #7
0
/**
 * \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);
}
Пример #8
0
/**
 * \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;
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
0
/** \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;
}
Пример #12
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;
}