Untitled
unknown
c_cpp
2 years ago
6.6 kB
25
Indexable
#ifndef _WINDOW_BIT_COUNT_APX_
#define _WINDOW_BIT_COUNT_APX_
#define max(a, b) (((a) > (b)) ? (a) : (b))
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
uint64_t N_MERGES = 0; // keep track of how many bucket merges occur
/*
TODO: You can add code here.
*/
typedef struct Bucket {
uint32_t count; // Count of 1's in the bucket
uint32_t ts; // ts or index of the most recent bit in the bucket
} Bucket;
typedef struct {
// TODO: Fill me.
Bucket *buckets; // Array of buckets
uint32_t maxBuckets; // Maximum number of buckets
uint32_t bucketCount; // Current number of buckets
uint32_t wndSize; // Size of the window
uint32_t *bitBuffer; // Circular buffer for bits
uint32_t bufferIndex; // Current index in the circular bit buffer
uint32_t k; // 1/eps, controls precision
uint32_t totalBitsProcessed;
} StateApx;
// k = 1/eps
// if eps = 0.01 (relative error 1%) then k = 100
// if eps = 0.001 (relative error 0.1%) the k = 1000
uint64_t wnd_bit_count_apx_new(StateApx *self, uint32_t wnd_size, uint32_t k) {
assert(wnd_size >= 1);
assert(k >= 1);
// TODO: Fill me.
int numSizes = ceil(log2((double)self->wndSize));
self->maxBuckets = numSizes * self->k;
// TODO:
// The function should return the total number of bytes allocated on the heap.
size_t bucketsSize = sizeof(Bucket) * self->maxBuckets;
size_t bufferSize = sizeof(uint32_t) * wnd_size;
uint8_t *allocatedMemory = (uint8_t *)malloc(bucketsSize + bufferSize);
if (!allocatedMemory) // Handle allocation failure
return 0;
self->buckets = (Bucket *)(allocatedMemory);
self->bitBuffer = (uint32_t *)(allocatedMemory + bucketsSize);
self->bucketCount = 0;
self->wndSize = wnd_size;
self->bufferIndex = 0;
self->totalBitsProcessed = 0;
self->k = k;
// Return total bytes allocated
return bucketsSize + bufferSize;
}
void wnd_bit_count_apx_destruct(StateApx *self) {
// TODO: Fill me.
// Make sure you free the memory allocated on the heap.
free(self);
return;
}
void wnd_bit_count_apx_print(StateApx *self) {
printf("Total bits: %u\n", self->totalBitsProcessed);
printf("Window Size: %u\n", self->wndSize);
printf("Bucket Count: %u\n", self->bucketCount);
printf("Buckets:\n");
// Print details of each bucket
for (uint32_t i = 0; i < self->bucketCount; ++i) {
printf(" Bucket %u: Count = %u, Timestamp = %u\n", i,
self->buckets[i].count, self->buckets[i].ts);
}
// Optionally, print the bit buffer if it's not too large
// Uncomment the following lines if you want to include the bit buffer
// contents in the debug output
/*
printf("Bit Buffer:\n ");
for (uint32_t i = 0; i < self->wndSize; ++i) {
printf("%u", self->bitBuffer[i]);
if ((i + 1) % 50 == 0) // Break line every 50 bits for readability
printf("\n ");
}
printf("\n");
*/
printf("\n"); // Add an extra newline for readability
}
void discardOldBuckets(StateApx *self) {
// This loop will check all buckets and discard those that are too old
while (self->bucketCount > 0) {
// Calculate the age of the oldest bucket
uint64_t ageOfOldestBucket = self->totalBitsProcessed - self->buckets[0].ts;
// If the oldest bucket is outside of our window of interest, we discard it
if (ageOfOldestBucket >= self->wndSize) {
// Shift all buckets to the left to discard the oldest one
for (uint32_t i = 1; i < self->bucketCount; ++i) {
self->buckets[i - 1] = self->buckets[i];
}
self->bucketCount--; // Decrease the bucket count
} else {
// If the oldest bucket is still within the window, we stop discarding
break;
}
}
}
uint32_t wnd_bit_count_apx_next(StateApx *self, bool item) {
// Update the circular buffer with the incoming bit
self->bitBuffer[self->bufferIndex] = item;
uint32_t ts = self->totalBitsProcessed;
self->bufferIndex = (self->bufferIndex + 1) % self->wndSize;
self->totalBitsProcessed++;
// printf("buffer Index = %d\n", self->bufferIndex);
if (item) {
// Add a new bucket for the "1" bit if space allows
if (self->bucketCount < self->maxBuckets) {
self->buckets[self->bucketCount++] = (Bucket){1, ts};
}
// Merge buckets as necessary
uint32_t size = 1;
while (size <= self->wndSize) {
int bucketIndex = -1;
int count = 0;
// Find the oldest buckets of the current size
for (uint32_t i = 0; i < self->bucketCount; ++i) {
if (self->buckets[i].count == size) {
if (bucketIndex == -1 ||
self->buckets[i].ts < self->buckets[bucketIndex].ts) {
bucketIndex = i;
}
count++;
}
}
if (count > self->k && bucketIndex != -1) {
int secondOldestIndex = -1;
// Find the second oldest bucket of the current size
for (uint32_t i = 0; i < self->bucketCount; ++i) {
if (self->buckets[i].count == size && i != bucketIndex) {
if (secondOldestIndex == -1 ||
self->buckets[i].ts < self->buckets[secondOldestIndex].ts) {
secondOldestIndex = i;
}
}
}
// Merge the two oldest buckets
if (secondOldestIndex != -1) {
self->buckets[bucketIndex].count *= 2;
self->buckets[bucketIndex].ts = self->buckets[secondOldestIndex].ts;
// Move the last bucket to the position of the second oldest and
// reduce the bucket count
self->buckets[secondOldestIndex] = self->buckets[--self->bucketCount];
}
} else {
break;
}
size *= 2; // Move to the next size of buckets
}
}
discardOldBuckets(self);
// Estimate the count of "1"s in the last N bits
uint32_t countVal = 0;
for (uint32_t i = 1; i < self->bucketCount; i++) {
countVal = countVal + self->buckets[i].count;
// printf("Name: %u", self->bucketCount);
}
uint32_t startOfWindow = (self->totalBitsProcessed - self->wndSize);
if (startOfWindow < 0) startOfWindow = 0;
if (self->bucketCount > 0 &&
(self->buckets[0].ts - startOfWindow) < self->buckets[0].count)
countVal = countVal + 1;
else
countVal = countVal + self->buckets[0].count;
return countVal;
}
#endif // _WINDOW_BIT_COUNT_APX_
Editor is loading...
Leave a Comment