implement Encoder, Decoder and Pathfinder

This commit is contained in:
2022-06-24 18:46:17 +09:00
parent 6ffde38590
commit 920f69e4f0
9 changed files with 487 additions and 99 deletions

View File

@@ -11,6 +11,8 @@ target_sources(liblocky
liblocky.h
PRIVATE
block.c
decoder.c
encoder.c
extractor.c
image.c
pathfinder.c

51
liblocky/decoder.c Normal file
View File

@@ -0,0 +1,51 @@
#include "liblocky.h"
#include <assert.h>
bool blky_decoder_feed(blky_decoder_t* de, uint32_t block_index) {
assert(de->block_num > 0);
assert(de->feat_bits > 0);
assert(de->seed > 0);
const uint64_t seed = blky_numeric_xorshift64(de->seed);
if (de->count++) {
const uint32_t feat_max = 1 << de->feat_bits;
assert(feat_max < de->block_num);
uint32_t feat = 0;
for (; feat < feat_max; ++feat) {
if (blky_numeric_hop(de->block_index, feat, seed)%de->block_num == block_index) {
break;
}
}
if (feat >= feat_max) return false;
assert(de->scrap_bits+8 <= 32);
de->scrap |= feat << de->scrap_bits;
de->scrap_bits += de->feat_bits;
}
de->seed = seed;
de->block_index = block_index;
return true;
}
bool blky_decoder_pop(blky_decoder_t* de, uint8_t* b, bool force) {
if (force) {
if (de->scrap_bits > 0) return false;
} else {
if (de->scrap_bits < 8) return false;
}
*b = (uint8_t) (de->scrap & 0xFF);
de->scrap >>= 8;
if (de->scrap_bits >= 8) {
de->scrap_bits -= 8;
} else {
de->scrap_bits = 0;
}
return true;
}

41
liblocky/encoder.c Normal file
View File

@@ -0,0 +1,41 @@
#include "liblocky.h"
#include <assert.h>
#include <stdio.h>
void blky_encoder_feed(blky_encoder_t* enc, uint8_t data) {
assert(enc);
assert(enc->block_num > 0);
assert(enc->feat_bits > 0);
assert(enc->feat_bits <= sizeof(enc->scrap)*8);
assert(enc->seed > 0);
if (enc->count++ == 0) enc->scrap_bits = 1;
assert(enc->scrap_bits+8 <= 32);
enc->scrap |= data << enc->scrap_bits;
enc->scrap_bits += 8;
}
bool blky_encoder_pop(blky_encoder_t* enc, uint32_t* feat, bool force) {
assert(enc);
assert(feat);
if (force) {
if (enc->scrap_bits > 0) return false;
} else {
if (enc->scrap_bits < enc->feat_bits) return false;
}
const uint32_t feat_max = 1 << enc->feat_bits;
assert(feat_max < enc->block_num);
enc->seed = blky_numeric_xorshift64(enc->seed);
*feat = blky_numeric_hop(enc->block_index, enc->scrap%feat_max, enc->seed)%enc->block_num;
enc->block_index = *feat;
enc->scrap >>= enc->feat_bits;
enc->scrap_bits -= enc->feat_bits;
return true;
}

View File

@@ -97,22 +97,19 @@ blky_extractor_feed(
const uint8_t* img, uint32_t w, uint32_t h, const double verts[8]);
/* ---- pathfinder ---- */
/* ---- Pathfinder ---- */
typedef struct blky_pathfinder_step_t {
struct blky_pathfinder_step_t* next;
struct blky_pathfinder_step_t* prev;
uint32_t indices[1];
} blky_pathfinder_step_t;
typedef struct blky_pathfinder_t {
// must be filled before init()
uint32_t block_num;
uint32_t step_branch;
uint32_t feat_bits;
uint64_t seed;
uint8_t hopping_algo;
# define BLKY_PATHFINDER_HOPPING_ALGO_XORSHFIT 0
// internal state
blky_pathfinder_step_t* step_first;
blky_pathfinder_step_t* step_last;
uint64_t steps;
@@ -136,6 +133,58 @@ blky_pathfinder_feed(
const double* probs);
/* ---- Encoder ----
* converts byte to feature */
typedef struct blky_encoder_t {
uint32_t block_num;
uint32_t block_index;
uint8_t feat_bits;
uint64_t seed;
uint64_t count;
uint32_t scrap;
uint8_t scrap_bits;
} blky_encoder_t;
void
blky_encoder_feed(
blky_encoder_t* enc,
uint8_t data);
bool
blky_encoder_pop(
blky_encoder_t* enc,
uint32_t* feat,
bool force);
/* ---- Decoder ----
* converts block indices to byte */
typedef struct blky_decoder_t {
uint32_t block_num;
uint8_t feat_bits;
uint64_t seed;
uint64_t count;
uint32_t block_index;
uint32_t scrap;
uint8_t scrap_bits;
} blky_decoder_t;
bool
blky_decoder_feed(
blky_decoder_t* de,
uint32_t block_index);
bool
blky_decoder_pop(
blky_decoder_t* de,
uint8_t* b,
bool force);
/* ---- Image utility ---- */
void blky_image_convert_to_normalized_coord(
const double verts[8], double* x, double* y);
@@ -145,27 +194,13 @@ uint64_t blky_image_offset(
/* ---- numeric utility ---- */
static inline uint64_t blky_numeric_xorrshift64_rev(uint64_t x, uint8_t n) {
for (int16_t i = 64-n; i >= 0; --i) {
x ^= (1 << i) & (x >> n);
}
return x;
}
static inline uint64_t blky_numeric_xorlshift64_rev(uint64_t x, uint8_t n) {
for (uint8_t i = n; i < 64; ++i) {
x ^= (1 << i) & (x << n);
}
return x;
}
static inline uint64_t blky_numeric_xorshift64(uint64_t x) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
static inline uint64_t blky_numeric_xorshift64_rev(uint64_t x) {
x = blky_numeric_xorlshift64_rev(x, 13);
x = blky_numeric_xorrshift64_rev(x, 7);
x = blky_numeric_xorlshift64_rev(x, 17);
return x;
static inline uint32_t blky_numeric_hop(uint32_t prev, uint32_t offset, uint64_t seed) {
seed = (seed^blky_numeric_xorshift64(prev+seed)) + (offset << 4);
return (uint32_t) ((seed & 0xFFFFFFFF) ^ (seed >> 32));
}

View File

@@ -5,14 +5,13 @@
void blky_pathfinder_init(blky_pathfinder_t* pf) {
assert(pf->block_num > 0);
assert(pf->step_branch > 0);
assert(pf->seed > 0);
assert(pf->block_num > 0);
assert(pf->feat_bits > 0);
assert(pf->feat_bits < 32);
assert(pf->seed > 0);
assert(pf->block_num >= pf->step_branch);
assert(pf->hopping_algo == BLKY_PATHFINDER_HOPPING_ALGO_XORSHFIT);
assert(pf->block_num > (uint32_t) (1 << pf->feat_bits));
pf->step_first = NULL;
pf->step_last = NULL;
pf->step_bytes =
@@ -29,40 +28,47 @@ void blky_pathfinder_init(blky_pathfinder_t* pf) {
void blky_pathfinder_deinit(blky_pathfinder_t* pf) {
free(pf->probs);
free(pf->probs_prev);
blky_pathfinder_step_t* step = pf->step_last;
while (step) {
blky_pathfinder_step_t* temp = step->prev;
free(step);
step = temp;
}
}
void blky_pathfinder_feed(blky_pathfinder_t* pf, const double* probs) {
double* temp = pf->probs;
pf->probs = pf->probs_prev;
pf->probs_prev = temp;
blky_pathfinder_step_t* step = NULL;
if (++pf->steps > 1) {
step = calloc(pf->step_bytes, 1);
assert(step);
}
const uint32_t feat_max = 1 << pf->feat_bits;
assert(feat_max < pf->block_num);
pf->seed = blky_numeric_xorshift64(pf->seed);
for (uint32_t bi = 0; bi < pf->block_num; ++bi) {
const double prob = probs[bi];
const uint64_t pbase = blky_numeric_xorshift64_rev(bi);
for (uint32_t si = 0; si < pf->step_branch; ++si) {
const uint64_t prev_seed = pbase - si*pf->block_num/pf->step_branch;
const uint32_t prev_bi = (uint32_t) (prev_seed % pf->block_num);
const double prev_prob = pf->probs_prev[prev_bi];
const double sum = prev_prob + prob;
if (pf->probs[bi] < sum) {
pf->probs[bi] = sum;
if (step) step->indices[prev_bi] = bi;
const double prob = probs[bi];
for (uint32_t pbi = 0; pbi < pf->block_num; ++pbi) {
for (uint32_t fi = 0; fi < feat_max; ++fi) {
if (blky_numeric_hop(pbi, fi, pf->seed)%pf->block_num != bi) continue;
const double sum = pf->probs_prev[pbi] + prob;
if (pf->probs[bi] < sum) {
pf->probs[bi] = sum;
if (step) step->indices[bi] = pbi;
}
}
}
}
if (step) {
if (pf->step_last) {
pf->step_last->next = step;
pf->step_last = step;
} else {
pf->step_first = pf->step_last = step;
}
step->prev = pf->step_last;
pf->step_last = step;
}
double* temp = pf->probs;
pf->probs = pf->probs_prev;
pf->probs_prev = temp;
}