xboa
Bunchcore.c
Go to the documentation of this file.
1 //This file is a part of xboa
2 //
3 //xboa is free software: you can redistribute it and/or modify
4 //it under the terms of the GNU General Public License as published by
5 //the Free Software Foundation, either version 3 of the License, or
6 //(at your option) any later version.
7 //
8 //xboa is distributed in the hope that it will be useful,
9 //but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 //GNU General Public License for more details.
12 //
13 //You should have received a copy of the GNU General Public License
14 //along with xboa in the doc folder. If not, see
15 //<http://www.gnu.org/licenses/>.
16 //
17 
18 #include <Python.h>
19 #include <structmember.h>
20 #include <string.h>
21 
22 #include "Bunchcore.h"
23 
24 
25 //////////// CONSTRUCTORS AND DESTRUCTORS ////////////
26 static int Bunchcore_init_python(Bunchcore* self, PyObject *args, PyObject *kwds)
27 {
28  // int length=-1;
29  // if( PyArg_ParseTuple(args, "i", &length) != 0)
30  // return Bunchcore_init(self, 0);
31  // PyErr_Clear();
32  return Bunchcore_init(self, 0);
33 }
34 
36 {
37  Bunchcore* copy;
38  copy = malloc(sizeof(Bunchcore));
39  if(copy == NULL)
40  {
41  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
42  return NULL;
43  }
44  copy->vec = vector_alloc(sizeof(Bunchcore_hit), self->vec->data_length);
45  int i=0;
46  for(i=0; i<self->vec->data_length; i++)
47  {
48  Bunchcore_hit* bc_hit_copy = vector_el(copy->vec, i);
49  Bunchcore_hit* bc_hit_self = vector_el(self->vec, i);
50  bc_hit_copy->hit = bc_hit_self->hit;
51  bc_hit_copy->hitcore = bc_hit_self->hitcore;
52  Py_INCREF(bc_hit_copy->hit);
53  }
54  return copy;
55 }
56 
57 static Bunchcore* bc_realloc(Bunchcore* self, int new_length)
58 {
59  int i, old_length = length(self);
60  if(vector_realloc(self->vec, new_length) == NULL) { return NULL;}
61  for(i=old_length; i<new_length; i++)
62  {
63  Bunchcore_hit * bc_hit = vector_el(self->vec, i);
64  bc_hit->hit = NULL;
65  bc_hit->hitcore = NULL;
66  }
67  return self;
68 }
69 
70 static int Bunchcore_init(Bunchcore* self, int len)
71 {
72  //python does the malloc for Bunchcore
73  //I need to make sure children of Bunchcore are initialised
74  self->vec = vector_alloc(sizeof(Bunchcore_hit), 0);
75  if(self->vec == NULL) return -1;
76  return 0;
77 }
78 
79 static void Bunchcore_dealloc(Bunchcore * self)
80 {
81  size_t i;
82  for(i=0; i<vector_size(self->vec); i++)
83  {
84  Bunchcore_hit* bc_hit = vector_el(self->vec, i);
85  if (bc_hit->hit != NULL)
86  Py_DECREF(bc_hit->hit);
87  if (bc_hit->hitcore != NULL)
88  Py_DECREF(bc_hit->hitcore);
89  }
90  vector_free(self->vec);
91 }
92 
93 
94 ///////// SEQUENCE METHODS /////////////
95 //Sequence methods are the ones that make the Bunchcore look like a python-style list
96 //So these are all the things like referencing objects in the list, concatenations, etc
97 //Not sure I need all these methods, might be better to leave some out and do them at
98 //Bunch level...
99 //
100 //First C methods ignoring python API
101 //WARNING - bound checking, index slicing etc is done in python API calls
102 //so segmentation errors abound!
103 
104 //There's a whole load of stuff commented out at the end - probably works, not checked
105 
106 //set item - if required, caller must handle Py_INCREF on hit and do bound checking
107 static void set_item_bc_hit(Bunchcore* self, PyObject* a_hit, Hitcore* a_hitcore, int pos, int* ierr)
108 {
109  if(pos >= length(self) )
110  if(bc_realloc(self, pos+1) == NULL) {*ierr = -1; return;}
111  Bunchcore_hit* new = vector_el_bc(self->vec, pos);
112  new->hitcore = a_hitcore;
113  if(new->hit != NULL) {
114  Py_DECREF(new->hit);
115  Py_DECREF(new->hitcore);
116  }
117  new->hit = a_hit;
118  if (new->hit != NULL)
119  Py_INCREF(new->hitcore);
120  Py_INCREF(new->hit);
121 }
122 
123 static PyObject* length_python(PyObject* self, PyObject* args)
124 {
125  Bunchcore * bc = (Bunchcore*)self;
126  int len = 0;
127  if(bc->vec->object_size > 0)
128  len = (int)(bc->vec->data_length/bc->vec->object_size);
129  return Py_BuildValue("i", len);
130 }
131 
132 static Py_ssize_t len_python(PyObject* self) //len() function wants Py_ssize_t in return
133 {
134  Py_ssize_t len = 0;
135  Bunchcore * bc = (Bunchcore*)self;
136  if(bc->vec->object_size > 0) len = bc->vec->data_length/bc->vec->object_size;
137  return len;
138 }
139 
140 //Now Python wrappers for (some of) above functions
141 //Set item - call sign is (self, Hit, Hitcore, int)
142 static PyObject* set_item_python(PyObject* self, PyObject* args)
143 {
144  int pos;
145  PyObject* a_hit;
146  Hitcore* a_hitcore;
147  Bunchcore* me = (Bunchcore*)self;
148  if( PyArg_ParseTuple(args, "OOi", &a_hit, &a_hitcore, &pos) != 0)
149  {
150  if(pos < 0) pos = pos + length(me);
151  set_item_bc_hit(me, a_hit, a_hitcore, pos, &pos); //Py_INCREF handled here
152  if(pos == -1)
153  {
154  PyErr_SetString(PyExc_IndexError, "Internal error in Bunchcore.set_item - out of memory?");
155  return NULL;
156  }
157  Py_INCREF(Py_None);
158  return Py_None;
159  }
160  PyErr_SetString(PyExc_KeyError, "Failed to parse variable in function Bunchcore.set_item");
161  return NULL; //raise an exception
162 }
163 
164 static PyObject* get_item_python(PyObject* self, PyObject* args)
165 {
166  int pos;
167  Bunchcore* me = (Bunchcore*)self;
168  if( PyArg_ParseTuple(args, "i", &pos) != 0)
169  {
170  if(pos < 0) pos += length(me);
171  Bunchcore_hit* bc_hit = vector_el_bc(me->vec, pos);
172  if(bc_hit == NULL)
173  {
174  PyErr_SetString(PyExc_IndexError, "Index out of range in Bunchcore.set_item");
175  return NULL;
176  }
177  if(bc_hit->hit == NULL) {Py_INCREF(Py_None); Py_INCREF(Py_None); return Py_BuildValue("(OO)", Py_None, Py_None);}
178  return Py_BuildValue("(OO)", bc_hit->hit, bc_hit->hitcore);
179  }
180  PyErr_SetString(PyExc_KeyError, "Failed to parse variable in function Bunchcore.set_item");
181  return NULL; //raise an exception
182 }
183 
184 //////////////// MOMENTS //////////////////////
185 static double get_moment_char(Bunchcore* self, const char** axes, double* means, int n_axes, int* ierr)
186 {
187  //turn list of axes into a list of function calls
188  hc_get_dbl_function functions[n_axes];
190  int i=0, j=0;
191  for(i=0; i<n_axes; i++)
192  {
193  functions[i] = hc_get_dbl_function_by_string(axes[i]);
194  if(functions[i] == NULL) {*ierr = -1; return 0.;}
195  }
196 
197  //extract weights
198  double w = 0.;
199  for(i=0; i<length(self); i++)
200  w += hc_get_total_weight( ((Bunchcore_hit*)vector_el(self->vec, i) )->hitcore );
201 
202  //extract moments
203  double m = 0.;
204  for(i=0; i<length(self); i++)
205  {
206  double my_m = hc_get_total_weight( ((Bunchcore_hit*)vector_el(self->vec, i) )->hitcore ) / w;
207  for(j=0; j<n_axes; j++) //could save a function look-up for duped axes...
208  my_m *= functions[j]( ((Bunchcore_hit*)vector_el(self->vec, i) )->hitcore ) - means[j];
209  m += my_m;
210  }
211  return m;
212 }
213 
214 static void covariance_matrix_char(Bunchcore* self, const char* axes[], double* means, int n_axes, double* target, int* ierr)
215 {
217  int i=0, j=0, k=0;
218  hc_get_dbl_function functions[n_axes];
219  int n_hits = length(self);
220  Hitcore* hits[n_hits];
221  for(i=0; i<n_hits; i++)
222  hits[i] = ((Bunchcore_hit*)vector_el_bc(self->vec, i) )->hitcore;
223 
224  for(i=0; i<n_axes; i++)
225  {
226  functions[i] = hc_get_dbl_function_by_string(axes[i]);
227  if(functions[i] == NULL) {*ierr = -1; return;}
228  }
229 
230  double w = 0.;
231  for(i=0; i<n_hits; i++)
232  w += hc_get_total_weight( hits[i] );
233 
234  for(j=0; j<n_axes; j++) //could save a function look-up for duped axes...
235  for(k=0; k<n_axes; k++)
236  target[j+k*n_axes] = 0.;
237 
238  for(i=0; i<n_hits; i++)
239  {
240  for(j=0; j<n_axes; j++) //could save a function look-up for duped axes...
241  {
242  double my_m = hc_get_total_weight( hits[i] )*(functions[j]( hits[i] )-means[j])/w;
243  for(k=0; k<n_axes; k++)
244  target[j+k*n_axes] += my_m*(functions[k]( hits[i] ) - means[j]);
245  }
246  }
247 }
248 
249 static void make_array_from_char_list(PyObject* py_list, const char*** string_list, int* list_size)
250 {
251  //gotta love C - level 3 pointer! (must have Fireball spell by now?)
252  if(!py_list || !PyList_Check(py_list))
253  {
254  PyErr_SetString(PyExc_KeyError, "Failed to parse argument list of strings in Bunchcore");
255  *string_list = NULL;
256  return;
257  }
258 
259  int i;
260  *list_size = PyList_Size(py_list);
261  *string_list = malloc(sizeof(const char*[*list_size]));
262  if(*string_list == NULL)
263  {
264  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
265  return;
266  }
267  for(i=0; i<*list_size; i++)
268  {
269  PyObject* my_string = PyList_GetItem(py_list, i);
270  if( PyString_Check(my_string) ) (*string_list)[i] = PyString_AsString(my_string);
271  else
272  {
273  PyErr_SetString(PyExc_KeyError, "Failed to parse argument list of strings in Bunchcore");
274  free(*string_list);
275  *string_list = NULL;
276  return;
277  }
278  }
279 }
280 
281 static void make_array_from_float_list(PyObject* py_list, double** double_list, int* list_size)
282 {
283  //gotta love C - level 3 pointer! (must have Fireball spell by now?)
284  if(!py_list || !PyList_Check(py_list))
285  {
286  PyErr_SetString(PyExc_KeyError, "Failed to parse argument list of strings in Bunchcore");
287  *double_list = NULL;
288  return;
289  }
290 
291  int i;
292  *list_size = PyList_Size(py_list);
293  *double_list = malloc(sizeof(double[*list_size]));
294  if(*double_list == NULL)
295  {
296  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
297  return;
298  }
299 
300  for(i=0; i<*list_size; i++)
301  {
302  PyObject* my_float = PyList_GetItem(py_list, i);
303  if(PyFloat_Check(my_float)) (*double_list)[i] = PyFloat_AsDouble(my_float) ;
304  else
305  {
306  PyErr_SetString(PyExc_KeyError, "Failed to parse argument list of floats in Bunchcore");
307  free(*double_list);
308  *double_list = NULL;
309  return;
310  }
311  }
312 }
313 
314 
315 static PyObject* make_lists_from_double_array(double values[], int list_size)
316 {
317  int i=0,j=0,k=0,err=0;
318  PyObject* the_list = PyList_New(list_size);
319  for(i=0; i<list_size; i++)
320  {
321  PyObject* a_list = PyList_New(list_size);
322  err = PyList_SetItem(the_list, i, a_list);
323  for(j=0; j<list_size; j++)
324  {
325  PyObject* a_float = Py_BuildValue("d", values[k]);
326  err = PyList_SetItem(a_list, j, a_float);
327  k++;
328  }
329  }
330  if (err == 0) {} // kill gcc warning
331  return the_list;
332 }
333 
334 static PyObject* get_moment_python(PyObject* self, PyObject* args)
335 {
336  PyErr_SetString(PyExc_KeyError, "Failed while calculating moment in Bunchcore::get_moment");
337  PyObject* py_list_axes, *py_list_means;
338  int list_size1, list_size2, i=0;
339  const char*** string_list = malloc(sizeof(const char**));
340  double** double_list = malloc(sizeof(double*));
341  if(string_list == NULL || double_list == NULL)
342  {
343  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
344  return NULL;
345  }
346 
347  if( PyArg_ParseTuple(args, "OO", &py_list_axes, &py_list_means) == 0) return NULL;
348  make_array_from_char_list (py_list_axes, string_list, &list_size1); //allocates string_list
349  if(*string_list == NULL) {free(string_list); free(double_list); return NULL;}
350  make_array_from_float_list(py_list_means, double_list, &list_size2);
351  if(*double_list == NULL) { free(*string_list); free(string_list); free(double_list); return NULL;}
352  if(list_size1 != list_size2) { free(*string_list); free(*double_list); free(string_list); free(double_list); return NULL;}
353  double moment = get_moment_char( (Bunchcore*)self, *string_list, *double_list, list_size1, &i);
354  free(*double_list); free(*string_list); free(string_list); free(double_list);
355  if(i < 0) return NULL;
356  PyErr_Clear();
357  return Py_BuildValue("d", moment);
358 }
359 
360 static PyObject* covariance_matrix_python(PyObject* self, PyObject* args)
361 {
362  PyErr_SetString(PyExc_KeyError, "Failed while calculating moment in Bunchcore::get_covariance_matrix");
363  PyObject* py_list_axes, *py_list_means;
364  int list_size1, list_size2, i=0;
365  const char*** string_list = malloc(sizeof(const char**));
366  double** double_list = malloc(sizeof(double*));
367  if(string_list == NULL || double_list == NULL)
368  {
369  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
370  return NULL;
371  }
372 
373  if( PyArg_ParseTuple(args, "OO", &py_list_axes, &py_list_means) == 0) return NULL;
374  make_array_from_char_list (py_list_axes, string_list, &list_size1); //allocates string_list
375  if(*string_list == NULL) {free(string_list); free(double_list); return NULL;}
376 
377  make_array_from_float_list(py_list_means, double_list, &list_size2); //allocates double_list or returns NULL
378  if(*double_list == NULL) { free(*string_list); free(string_list); free(double_list); return NULL;}
379  if(list_size1 != list_size2) { free(*string_list); free(*double_list); free(string_list); free(double_list); return NULL;}
380 
381  double* target = malloc(sizeof(double[list_size1*list_size1]));
382  if(target == NULL)
383  {
384  PyErr_SetString(PyExc_KeyError, "Failed to allocate memory in Bunchcore");
385  return NULL;
386  }
387  covariance_matrix_char( (Bunchcore*)self, *string_list, *double_list, list_size1, target, &i);
388  PyObject* cov_matrix = make_lists_from_double_array(target, list_size1);
389 
390  free(*double_list); free(*string_list); free(string_list); free(double_list);
391  if(i < 0) return NULL;
392  free(target);
393  PyErr_Clear();
394 
395  return cov_matrix;
396 }
397 
398 static PyObject* _cut_double_python(PyObject* self, PyObject* args) {
399  char* get_variable = NULL;
400  PyObject* comp = NULL;
401  double cut_value = 0.;
402  char* weight_variable = NULL;
403  if (PyArg_ParseTuple(args, "sOds", &get_variable, &comp, &cut_value, &weight_variable) == 0)
404  return NULL;
405  int is_local = strcmp("local_weight", weight_variable);
406  if (is_local == 0)
407  if (strcmp("global_weight", weight_variable) == 0) {
408  PyErr_SetString(PyExc_ValueError, "Attempting to cut with odd set value");
409  return NULL;
410  }
411  if (_cut_double((Bunchcore*)self, get_variable, comp, cut_value, is_local) == 0) {
412  PyErr_SetString(PyExc_ValueError, "Failed to apply cut");
413  return NULL;
414  }
415  Py_INCREF(Py_None);
416  return Py_None;
417 }
418 
419 static int _cut_double(Bunchcore* self, const char* get_variable,
420  PyObject* comp, const double cut_value,
421  const int is_local) {
422  hc_get_dbl_function get_var = hc_get_dbl_function_by_string(get_variable);
423  if (get_var == NULL) {
424  return 0;
425  }
426  int my_length = length(self);
427  int i = 0;
428  for (i = 0; i < my_length; ++i) {
429  Hitcore* hit = ((Bunchcore_hit*)vector_el(self->vec, i) )->hitcore;
430  double variable = get_var(hit);
431  PyObject* comp_out = PyObject_CallFunction(comp, "dd", variable, cut_value);
432  if (comp_out == NULL) {
433  return 0;
434  }
435  int comp = 0;
436  int ok = PyArg_Parse(comp_out, "i", &comp);
437  if (!ok) {
438  return 0;
439  }
440  if (comp == 1) {
441  if (is_local == 0)
442  hc_set_local_weight(hit, 0.);
443  else
444  hc_set_global_weight(hit, 0.);
445  }
446  }
447  return 1;
448 }
449 
450 // hit_value_list = self.list_get_hit_variable([variable])[0]
451 // for i in range ( len(hit_value_list) ):
452 // if comparator(hit_value_list[i], cut_value):
453 // self.__hits[i].set(set_var, 0)
454 
455 //////////////// PYTHON TYPE DEFINITION ///////////////
456 static PyMemberDef Bunchcore_members[] = {
457 {NULL},
458 };
459 
460 static PyMethodDef Bunchcore_methods[] = {
461 {"set_item", (PyCFunction)set_item_python, METH_VARARGS, "Set i^th item"},
462 {"get_item", (PyCFunction)get_item_python, METH_VARARGS, "Get i^th item"},
463 {"length", (PyCFunction)length_python, METH_VARARGS, "Report the length of the Bunchcore"},
464 {"moment", (PyCFunction)get_moment_python, METH_VARARGS, "Get moment from a list of strings"},
465 {"covariance_matrix", (PyCFunction)covariance_matrix_python, METH_VARARGS, "Get covariance matrix from a list of strings"},
466 {"_cut_double", (PyCFunction)_cut_double_python, METH_VARARGS, "Apply cut inner loop. Returns NULL on error or if get_variable is an int"},
467 {NULL}
468 };
469 
470 static PySequenceMethods Bunchcore_as_seq = {
471  (lenfunc)len_python, //lenfunc PySequenceMethods.sq_length
472  0, //binaryfunc PySequenceMethods.sq_concat
473  0, //ssizeargfunc PySequenceMethods.sq_repeat
474  0, //ssizeargfunc PySequenceMethods.sq_item
475  0, //ssizeobjargproc PySequenceMethods.sq_ass_item
476  0, //objobjproc PySequenceMethods.sq_contains
477  0, //binaryfunc PySequenceMethods.sq_inplace_concat
478  0, //ssizeargfunc PySequenceMethods.sq_inplace_repeat
479 };
480 
481 static PyTypeObject BunchcoreType = {
482  PyObject_HEAD_INIT(NULL)
483  0, /*ob_size*/
484  "Bunchcore.Bunchcore", /*tp_name*/
485  sizeof(Bunchcore), /*tp_basicsize*/
486  sizeof(Bunchcore_hit), /*tp_itemsize*/
487  (destructor)Bunchcore_dealloc, /*tp_dealloc*/
488  0, /*tp_print*/
489  0, /*tp_getattr*/
490  0, /*tp_setattr*/
491  0, /*tp_compare*/
492  0, /*tp_repr*/
493  0, /*tp_as_number*/
494  &Bunchcore_as_seq, /*tp_as_sequence*/
495  0, /*tp_as_mapping*/
496  0, /*tp_hash */
497  0, /*tp_call*/
498  0, /*tp_str*/
499  0, /*tp_getattro*/
500  0, /*tp_setattro*/
501  0, /*tp_as_buffer*/
502  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
503  "Bunchcore objects", /* tp_doc */
504  0, /* tp_traverse */
505  0, /* tp_clear */
506  0, /* tp_richcompare */
507  0, /* tp_weaklistoffset */
508  0, /* tp_iter */
509  0, /* tp_iternext */
510  Bunchcore_methods, /* tp_methods */
511  Bunchcore_members, /* tp_members */
512  0, /* tp_getset */
513  0, /* tp_base */
514  0, /* tp_dict */
515  0, /* tp_descr_get */
516  0, /* tp_descr_set */
517  0, /* tp_dictoffset */
518  (initproc)Bunchcore_init_python, /* tp_init */
519  0, /* tp_alloc */
520  0, /* tp_new */
521 };
522 
523 PyMODINIT_FUNC initBunchcore(void)
524 {
525  import_hitcore();
526 
527  BunchcoreType.tp_new = PyType_GenericNew;
528  if (PyType_Ready(&BunchcoreType) < 0) return;
529 
530  PyObject* m = Py_InitModule3("Bunchcore", NULL, "Core module wrapped by Bunch");
531  if (m == NULL) return;
532 
533  Py_INCREF(&BunchcoreType);
534  PyModule_AddObject(m, "Bunchcore", (PyObject *)&BunchcoreType);
535 }
536 
537 void import_hitcore(void) {
538  PyObject* hc_module = PyImport_ImportModule("xboa.core.Hitcore");
539  if(hc_module == NULL) {return;}
540  else
541  {
542  PyObject *module_dict = PyModule_GetDict(hc_module);
543  PyObject *c_api_object = PyDict_GetItemString(module_dict, "HITCORE_C_API");
544  if (PyCObject_Check(c_api_object))
545  {
546  hitcore_api = (void **)PyCObject_AsVoidPtr(c_api_object);
554  vector_el = hitcore_api[7];
557  vector_free = hitcore_api[10];
558  }
559  }
560 }
561 
562 //Dummy function to remove compiler warnings
563 //sorry
564 void no_warn(void)
565 {
566  return;
568 }
569 
570 /*
571 static Bunchcore* concat(Bunchcore* a, Bunchcore* b)
572 {
573  Bunchcore* bc = malloc(sizeof(Bunchcore));
574  Bunchcore_init(bc, a->length+b->length);
575  int i;
576  for(i=0; i<a->length; i++)
577  set_item_bc_hit(bc, a->first[i].hit, a->first[i].hitcore, i);
578  for(i=0; i<b->length; i++)
579  set_item_bc_hit(bc, b->first[i].hit, b->first[i].hitcore, i+a->length);
580  return bc;
581 }
582 
583 static void inplace_concat(Bunchcore* a, Bunchcore* b) //pretty sure this does not work!
584 {
585  Bunchcore* copy = Bunchcore_shallow_copy(a);
586  Bunchcore_init(a, a->length+b->length);
587  int i;
588  for(i=0; i<copy->length; i++)
589  set_item_bc_hit(a, a->first[i].hit, a->first[i].hitcore, i);
590  for(i=0; i<copy->length; i++)
591  set_item_bc_hit(a, b->first[i].hit, b->first[i].hitcore, i+a->length);
592  Bunchcore_dealloc(copy);
593 }
594 
595 //Return a Bunchcore with nrepeats copies of a
596 static Bunchcore* repeat(Bunchcore* a, int nrepeats)
597 {
598  Bunchcore* bc = malloc(sizeof(Bunchcore));
599  Bunchcore_init(bc, a->length*nrepeats);
600  int i,j,k=0;
601  for(i=0; i<a->length; i++)
602  for(j=0; j<nrepeats; j++)
603  {
604  set_item_bc_hit(a, a->first[k].hit, a->first[k].hitcore, i);
605  k++;
606  }
607  return bc;
608 }
609 
610 //Rebuild a as a Bunch with nrepeats copies of a before function call
611 static void inplace_repeat(Bunchcore* a, int nrepeats) //pretty sure this does not work!
612 {
613  Bunchcore* copy = Bunchcore_shallow_copy(a);
614  Bunchcore_init(a, a->length*nrepeats);
615  int i,j,k=0;
616  for(i=0; i<copy->length; i++)
617  for(j=0; j<nrepeats; j++)
618  {
619  set_item_bc_hit(a, a->first[k].hit, a->first[k].hitcore, i);
620  k++;
621  }
622 }
623 
624 //Return the hit at index *blah* (no bound checking)
625 static PyObject* get_hit(Bunchcore* self, int index)
626 {return ( (Bunchcore_hit*)self->first+index*BunchcoreType.tp_itemsize )->hit;}
627 
628 //Return the hitcore associated with the hit at index
629 static Hitcore* get_hitcore(Bunchcore* self, int index)
630 {return ( (Bunchcore_hit*)self->first+index*BunchcoreType.tp_itemsize )->hitcore;}
631 
632 //Return 0 if self contains hit, else return -1
633 static int contains_hit(Bunchcore* self, PyObject* hit)
634 {
635  int i;
636  for(i=0; i<self->length; i++)
637  if( ((Bunchcore_hit*)self->first+i*BunchcoreType.tp_itemsize )->hit == hit) return 0;
638  return -1;
639 }
640 */
641