sparsemap/tests/common.c

428 lines
9.5 KiB
C
Raw Normal View History

2024-04-08 22:14:47 +00:00
#include <sys/types.h>
#include <assert.h>
#include <pthread.h>
2024-04-11 03:16:06 +00:00
#include <sparsemap.h>
2024-04-08 22:14:47 +00:00
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
2024-04-08 02:20:35 +00:00
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wvariadic-macros"
#define __diag(...) \
do { \
fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#pragma GCC diagnostic pop
2024-04-11 03:16:06 +00:00
uint64_t
tsc(void)
{
uint32_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return ((uint64_t)high << 32) | low;
}
2024-04-11 03:23:02 +00:00
static uint64_t
get_tsc_frequency()
{
uint32_t high, low;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
__asm__ volatile("rdtsc");
return ((uint64_t)high << 32) | low;
2024-04-11 03:16:06 +00:00
}
double
2024-04-11 03:23:02 +00:00
tsc_ticks_to_ns(uint64_t tsc_ticks)
{
static uint64_t tsc_freq = 0;
if (tsc_freq == 0) {
tsc_freq = get_tsc_frequency();
}
return (double)tsc_ticks / (double)tsc_freq * 1e9;
2024-04-11 03:16:06 +00:00
}
void
est_sift_up(uint64_t *heap, int child_index)
{
while (child_index > 0) {
int parent_index = (child_index - 1) / 2;
if (heap[parent_index] > heap[child_index]) {
// Swap parent and child
uint64_t temp = heap[parent_index];
heap[parent_index] = heap[child_index];
heap[child_index] = temp;
child_index = parent_index;
} else {
break; // Heap property satisfied
}
}
}
void
est_sift_down(uint64_t *heap, int heap_size, int parent_index)
{
int child_index = 2 * parent_index + 1; // Left child
while (child_index < heap_size) {
// Right child exists and is smaller than left child
if (child_index + 1 < heap_size && heap[child_index + 1] < heap[child_index]) {
child_index++;
}
// If the smallest child is smaller than the parent, swap them
if (heap[child_index] < heap[parent_index]) {
uint64_t temp = heap[child_index];
heap[child_index] = heap[parent_index];
heap[parent_index] = temp;
parent_index = child_index;
child_index = 2 * parent_index + 1;
} else {
break; // Heap property satisfied
}
}
}
void
est_insert_value(uint64_t *heap, int heap_max_size, int *heap_size, uint64_t value)
{
if (*heap_size < heap_max_size) { // Heap not full, insert value
heap[*heap_size] = value;
est_sift_up(heap, *heap_size);
(*heap_size)++;
} else {
// Heap is full, replace root with new value with a certain probability
// This is a very naive approach to maintain a sample of the input
if (rand() % 2) {
heap[0] = value;
est_sift_down(heap, heap_max_size, 0);
}
}
}
2024-04-08 22:14:47 +00:00
int __xorshift32_state = 0;
2024-04-08 02:20:35 +00:00
// Xorshift algorithm for PRNG
uint32_t
xorshift32()
{
2024-04-08 22:14:47 +00:00
uint32_t x = __xorshift32_state;
2024-04-08 02:35:42 +00:00
if (x == 0)
x = 123456789;
2024-04-08 02:20:35 +00:00
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
2024-04-08 22:14:47 +00:00
__xorshift32_state = x;
2024-04-08 02:20:35 +00:00
return x;
}
void
2024-04-08 02:35:42 +00:00
xorshift32_seed()
{
2024-04-08 22:14:47 +00:00
__xorshift32_state = XORSHIFT_SEED_VALUE;
2024-04-08 02:20:35 +00:00
}
void
2024-04-09 18:46:49 +00:00
shuffle(int *array, size_t n) // TODO working?
2024-04-08 02:20:35 +00:00
{
2024-04-08 22:14:47 +00:00
for (size_t i = n - 1; i > 0; --i) {
size_t j = xorshift32() % (i + 1);
if (i != j) {
array[i] ^= array[j];
array[j] ^= array[i];
array[i] ^= array[j];
2024-04-08 02:20:35 +00:00
}
}
}
int
compare_ints(const void *a, const void *b)
{
return *(const int *)a - *(const int *)b;
}
// Check if there's already a sequence of 'r' sequential integers
2024-04-08 02:35:42 +00:00
int
2024-04-08 22:14:47 +00:00
has_sequential_set(int a[], int l, int r)
2024-04-08 02:35:42 +00:00
{
2024-04-09 18:46:49 +00:00
// Start with a count of 1 for the first number
int count = 1;
2024-04-08 22:14:47 +00:00
for (int i = 1; i < l; ++i) {
2024-04-09 18:46:49 +00:00
// Check if the current and previous elements are sequential
if (a[i] - a[i - 1] == 1) {
2024-04-08 02:20:35 +00:00
count++;
2024-04-09 18:46:49 +00:00
if (count >= r) {
// Found a sequential set of length 'r' starting at 'i'
return i;
}
2024-04-08 02:20:35 +00:00
} else {
2024-04-09 18:46:49 +00:00
// Reset count if the sequence breaks
count = 1;
2024-04-08 02:20:35 +00:00
}
}
2024-04-09 18:46:49 +00:00
// No sequential set of length 'r' found
return -1;
2024-04-08 02:20:35 +00:00
}
// Function to ensure an array contains a set of 'r' sequential integers
2024-04-09 18:46:49 +00:00
int
ensure_sequential_set(int a[], int l, int r)
2024-04-08 02:35:42 +00:00
{
2024-04-09 18:46:49 +00:00
if (!a || l == 0 || r < 1 || r > l) {
return 0;
}
2024-04-08 02:20:35 +00:00
// Sort the array to check for existing sequences
qsort(a, l, sizeof(int), compare_ints);
// Check if a sequential set of length 'r' already exists
2024-04-09 18:46:49 +00:00
int offset = has_sequential_set(a, l, r);
if (offset >= 0) {
return offset; // Sequence already exists, no modification needed
2024-04-08 02:20:35 +00:00
}
// Find the minimum and maximum values in the array
int min_value = a[0];
int max_value = a[l - 1];
// Generate a random value between min_value and max_value
2024-04-08 22:14:47 +00:00
int value = random_uint32() % (max_value - min_value - r + 1);
2024-04-08 02:20:35 +00:00
// Generate a random location between 0 and l - r
2024-04-09 18:46:49 +00:00
offset = random_uint32() % (l - r - 1);
2024-04-08 02:20:35 +00:00
// Adjust the array to include a sequential set of 'r' integers at the random offset
for (int i = 0; i < r; ++i) {
a[i + offset] = value + i;
}
2024-04-09 18:46:49 +00:00
return value;
}
int
create_sequential_set_in_empty_map(sparsemap_t *map, int s, int r)
{
int placed_at;
2024-04-11 03:16:06 +00:00
if (s >= r + 1) {
placed_at = 0;
} else {
placed_at = random_uint32() % (s - r - 1);
}
2024-04-09 18:46:49 +00:00
for (int i = placed_at; i < placed_at + r; i++) {
sparsemap_set(map, i, true);
}
return placed_at;
2024-04-08 02:20:35 +00:00
}
void
2024-04-08 22:14:47 +00:00
print_array(int *array, int l)
2024-04-08 02:20:35 +00:00
{
int a[l];
memcpy(a, array, sizeof(int) * l);
qsort(a, l, sizeof(int), compare_ints);
2024-04-08 22:14:47 +00:00
fprintf(stderr, "int a[] = {");
2024-04-08 02:20:35 +00:00
for (int i = 0; i < l; i++) {
2024-04-08 22:14:47 +00:00
fprintf(stderr, "%d", a[i]);
if (i != l - 1) {
fprintf(stderr, ", ");
2024-04-08 02:20:35 +00:00
}
}
2024-04-08 22:14:47 +00:00
fprintf(stderr, "};\n");
2024-04-08 02:20:35 +00:00
}
bool
2024-04-08 22:14:47 +00:00
has_span(sparsemap_t *map, int *array, int l, int n)
2024-04-08 02:20:35 +00:00
{
if (n == 0 || l == 0 || n > l) {
return false;
}
int sorted[l];
memcpy(sorted, array, sizeof(int) * l);
qsort(sorted, l, sizeof(int), compare_ints);
2024-04-08 22:14:47 +00:00
for (int i = 0; i <= l - n; i++) {
2024-04-08 02:20:35 +00:00
if (sorted[i] + n - 1 == sorted[i + n - 1]) {
2024-04-08 22:14:47 +00:00
for (int j = 0; j < n; j++) {
2024-04-08 02:20:35 +00:00
size_t pos = sorted[j + i];
bool set = sparsemap_is_set(map, pos);
assert(set);
}
2024-04-08 22:14:47 +00:00
__diag("Found span: [%d, %d], length: %d\n", sorted[i], sorted[i + n - 1], n);
2024-04-08 02:20:35 +00:00
return true;
}
}
return false;
}
bool
2024-04-08 22:14:47 +00:00
is_span(int *array, int n, int x, int l)
2024-04-08 02:20:35 +00:00
{
if (n == 0 || l < 0) {
return false;
}
int a[n];
memcpy(a, array, sizeof(int) * n);
qsort(a, n, sizeof(int), compare_ints);
// Iterate through the array to find a span starting at x of length l
2024-04-08 22:14:47 +00:00
for (int i = 0; i < n; i++) {
2024-04-08 02:20:35 +00:00
if (a[i] == x) {
// Check if the span can fit in the array
if (i + l - 1 < n && a[i + l - 1] == x + l - 1) {
return true; // Found the span
}
}
}
return false; // Span not found
}
void
2024-04-08 22:14:47 +00:00
print_spans(int *array, int n)
2024-04-08 02:20:35 +00:00
{
int a[n];
size_t start = 0, end = 0;
if (n == 0) {
fprintf(stderr, "Array is empty\n");
return;
}
memcpy(a, array, sizeof(int) * n);
qsort(a, n, sizeof(int), compare_ints);
2024-04-08 22:14:47 +00:00
for (int i = 1; i < n; i++) {
2024-04-08 02:20:35 +00:00
if (a[i] == a[i - 1] + 1) {
end = i; // Extend the span
} else {
// Print the current span
if (start == end) {
fprintf(stderr, "[%d] ", a[start]);
} else {
fprintf(stderr, "[%d, %d] ", a[start], a[end]);
}
// Move to the next span
start = i;
end = i;
}
}
// Print the last span if needed
if (start == end) {
fprintf(stderr, "[%d]\n", a[start]);
} else {
fprintf(stderr, "[%d, %d]\n", a[start], a[end]);
}
}
bool
2024-04-08 22:14:47 +00:00
is_set(const int array[], int bit)
2024-04-08 02:20:35 +00:00
{
for (int i = 0; i < 1024; i++) {
if (array[i] == (int)bit) {
return true;
}
}
return false;
}
int
2024-04-08 22:14:47 +00:00
is_unique(int a[], int l, int value)
2024-04-08 02:35:42 +00:00
{
2024-04-08 22:14:47 +00:00
for (int i = 0; i < l; ++i) {
2024-04-08 02:20:35 +00:00
if (a[i] == value) {
return 0; // Not unique
}
}
return 1; // Unique
}
void
2024-04-08 22:14:47 +00:00
setup_test_array(int a[], int l, int max_value)
2024-04-08 02:20:35 +00:00
{
2024-04-08 02:35:42 +00:00
if (a == NULL || max_value < 0)
return; // Basic error handling and validation
2024-04-08 02:20:35 +00:00
2024-04-08 22:14:47 +00:00
for (int i = 0; i < l; ++i) {
2024-04-08 02:20:35 +00:00
int candidate;
do {
2024-04-08 22:14:47 +00:00
candidate = random_uint32() % (max_value + 1); // Generate a new value within the specified range
} while (!is_unique(a, i, candidate)); // Repeat until a unique value is found
a[i] = candidate; // Assign the unique value to the array
2024-04-08 02:20:35 +00:00
}
}
2024-04-08 22:14:47 +00:00
void
2024-04-11 03:16:06 +00:00
bitmap_from_uint32(sparsemap_t *map, uint32_t number)
{
for (int i = 0; i < 32; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
2024-04-08 22:14:47 +00:00
}
void
2024-04-11 03:16:06 +00:00
bitmap_from_uint64(sparsemap_t *map, uint64_t number)
{
for (int i = 0; i < 64; i++) {
bool bit = number & (1 << i);
sparsemap_set(map, i, bit);
}
2024-04-08 22:14:47 +00:00
}
2024-04-09 02:01:30 +00:00
uint32_t
rank_uint64(uint64_t number, int n, int p)
{
2024-04-11 03:16:06 +00:00
if (p < n || p > 63) {
return 0;
}
2024-04-09 02:01:30 +00:00
2024-04-11 03:16:06 +00:00
/* Create a mask for the range between n and p.
This works by shifting 1 to the left (p+1) times, subtracting 1 to have
a sequence of p 1's, then shifting n times to the left to position it
starting at n. Finally, subtracting (1 << n) - 1 removes the bits below
n from the mask. */
uint64_t mask = ((uint64_t)1 << (p + 1)) - 1 - (((uint64_t)1 << n) - 1);
/* Apply the mask and count the set bits in the result. */
uint64_t maskedNumber = number & mask;
/* Count the bits set in maskedNumber. */
uint32_t count = 0;
while (maskedNumber) {
count += maskedNumber & 1;
maskedNumber >>= 1;
}
2024-04-09 02:01:30 +00:00
2024-04-11 03:16:06 +00:00
return count;
2024-04-09 02:01:30 +00:00
}
2024-04-09 03:23:22 +00:00
int
whats_set_uint64(uint64_t number, int pos[64])
{
2024-04-11 03:16:06 +00:00
int length = 0;
2024-04-09 03:23:22 +00:00
2024-04-11 03:16:06 +00:00
for (int i = 0; i < 64; i++) {
if (number & ((uint64_t)1 << i)) {
pos[length++] = i;
2024-04-09 03:23:22 +00:00
}
2024-04-11 03:16:06 +00:00
}
2024-04-09 03:23:22 +00:00
2024-04-11 03:16:06 +00:00
return length;
2024-04-09 03:23:22 +00:00
}
2024-04-09 18:46:49 +00:00
void
whats_set(sparsemap_t *map, int m)
{
logf("what's set in the range [0, %d): ", m);
for (int i = 0; i < m; i++) {
if (sparsemap_is_set(map, i)) {
logf("%d ", i);
}
}
logf("\n");
}