implement Encoder, Decoder and Pathfinder
This commit is contained in:
@@ -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
51
liblocky/decoder.c
Normal 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
41
liblocky/encoder.c
Normal 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;
|
||||
}
|
@@ -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));
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user