#ifndef MORRIS_COUNTER_H #define MORRIS_COUNTER_H static float byte_to_float(byte); static byte float_to_byte(float); #pragma pack(1) typedef struct { PyObject_HEAD byte* X; // counter byte version_flag : 2; byte epsilon : 7; byte delta : 7; } Morris; static void Morris_dealloc(Morris*); static PyObject *Morris_new(PyTypeObject*, PyObject *, PyObject *); static int Morris_init(Morris *, PyObject *, PyObject *); static int Morris_init_helper(Morris *, uint64_t, byte); static PyObject *Morris_update(Morris *); static PyObject *Morris_update_helper(Morris *, uint64_t); static int comp(const void *, const void *); static uint64_t output_helper(uint64_t); static PyObject *Morris_output(Morris *); static PyObject* get_version(Morris* , void* ); static PyObject* get_epsilon(Morris* , void* ); static PyObject*get_delta(Morris*, void* ); static PyObject*get_shape(Morris*, void* ); static PyObject*get_raw_counts(Morris*, void* ); static PyObject* get_version(Morris* self, void* closure) { const char* s; if(self->version_flag == 0){ s = "Morris"; } else if(self->version_flag == 1){ s = "Morris+"; } else{ s = "Morris++"; } return Py_BuildValue("s#", s, strlen(s)); } static PyObject* get_epsilon(Morris* self, void* closure) { if(self->version_flag == 1 || self->version_flag == 2){ return PyFloat_FromDouble( byte_to_float(self->epsilon) ); } const char* s = "Epsilon not set for version Morris"; return Py_BuildValue("s#", s, strlen(s)); } static PyObject* get_delta(Morris* self, void* closure) { if(self->version_flag == 1 || self->version_flag == 2){ return PyFloat_FromDouble(byte_to_float(self->delta) ); } const char* s = "Delta not set for version Morris"; return Py_BuildValue("s#", s, strlen(s)); } static PyObject* get_shape(Morris* self, void* closure){ PyObject* shape; float epsilon, delta; uint32_t s,t; if(self->version_flag == 0){ if( (shape = PyTuple_Pack(1, PyLong_FromUnsignedLong((unsigned long) 1))) == NULL){ PyErr_NoMemory(); return Py_None; } return shape; } epsilon = byte_to_float(self->epsilon); delta = byte_to_float(self->delta); if(self->version_flag == 1){ s = (uint32_t) ceil( 1/((float) 2 * pow(epsilon, 2) * delta)); if( (shape = PyTuple_Pack(2, PyLong_FromUnsignedLong((unsigned long) 1), PyLong_FromUnsignedLong((unsigned long) s))) == NULL){ PyErr_NoMemory(); return Py_None; } return shape; } s = (uint32_t) ceil( 3/( (float) 2 * pow(epsilon, 2) )); t = (uint32_t) ceil( 18 * log(1/ (float) delta)); if( (shape = PyTuple_Pack(2, PyLong_FromUnsignedLong((unsigned long) t), PyLong_FromUnsignedLong((unsigned long) s))) == NULL){ PyErr_NoMemory(); return Py_None; } return shape; } static PyObject* get_raw_counts(Morris* self, void* closure){ PyObject* list; float epsilon, delta; uint32_t s,t; if(self->version_flag == 0){ list = PyList_New(1); PyList_SetItem(list, 0, Py_BuildValue("i", self->X[0])); return list; } epsilon = byte_to_float(self->epsilon); delta = byte_to_float(self->delta); if(self->version_flag == 1){ s = (uint32_t) ceil( 1/((float) 2 * pow(epsilon, 2) * delta)); list = PyList_New(s); for(uint32_t i = 0; i < s; i++){ PyList_SetItem(list, i, Py_BuildValue("i", self->X[i])); } return list; } s = (uint32_t) ceil( 3/( (float) 2 * pow(epsilon, 2) )); t = (uint32_t) ceil( 18 * log(1/ (float) delta)); list = PyList_New(t); for(uint32_t i = 0; i < t; i++){ PyObject* temp = PyList_New(s); for(uint32_t j = 0; j < s; j++){ PyList_SetItem(temp, j, Py_BuildValue("i", self->X[i*t + j])); } PyList_SetItem(list, i, temp); } return list; } PyGetSetDef get_Morris_sets[] = { {"version", /* name */ (getter) get_version, NULL, NULL, /* doc */ NULL /* closure */}, {"epsilon", /* name */ (getter) get_epsilon, NULL, NULL, /* doc */ NULL /* closure */}, {"delta", /* name */ (getter) get_delta, NULL, NULL, /* doc */ NULL /* closure */}, {"shape", /* name */ (getter) get_shape, NULL, NULL, /* doc */ NULL /* closure */}, {"raw_counts", /* name */ (getter) get_raw_counts, NULL, NULL, /* doc */ NULL /* closure */}, {NULL} }; static PyMethodDef Morris_methods[] = { {"update", (PyCFunction) Morris_update, METH_NOARGS, "Probabilistically update the morris counter" }, {"output", (PyCFunction) Morris_output, METH_NOARGS, "Output the counter estimate" }, {NULL} /* Sentinel */ }; static PyTypeObject Morris_type = { PyVarObject_HEAD_INIT(NULL,0) .tp_name = "counters.Morris", .tp_doc = "Morris counter", .tp_basicsize = sizeof(Morris), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = Morris_new, .tp_init = (initproc) Morris_init, .tp_dealloc = (destructor) Morris_dealloc, .tp_getset = get_Morris_sets, .tp_methods = Morris_methods, }; #endif // MORRIS_COUNTER_H