-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
number sequence: add libsspec for sequence detection
- Loading branch information
Showing
3 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* Source: https://github.com/ethanv2/seqspec */ | ||
|
||
/* | ||
* seqspec - analyze and continue arbitrary sequences of any order | ||
* Copyright (C) Ethan Marshall - 2022 | ||
*/ | ||
|
||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <math.h> | ||
|
||
typedef struct { | ||
int diff; | ||
unsigned char order; | ||
|
||
const long* seq; | ||
size_t seqlen; | ||
|
||
struct { | ||
long diffs[255]; | ||
} state; | ||
} sspec_t; | ||
|
||
#include "sspec_internal.h" | ||
|
||
/* | ||
* Recursively solves for the difference between elements. | ||
* Increments iters for each iteration. Space starts at space=len and is | ||
* decremented for each recursion. | ||
*/ | ||
static int analyze_diffs(const long *seq, size_t len, size_t space, unsigned char *iters, int *errf, long *diffbuf) | ||
{ | ||
size_t i; | ||
int recurse = 0; | ||
long diff; | ||
long diffs[space]; | ||
|
||
(*iters)++; | ||
if (*iters > 255 || space < 2) { | ||
*errf = 1; | ||
return 0; | ||
} | ||
|
||
/* start at i=1 and perform difference using i-1, to support any | ||
* array size. | ||
*/ | ||
diff = seq[1] - seq[0]; | ||
for (i = 1; i < len; i++) { | ||
diffs[i - 1] = seq[i] - seq[i - 1]; | ||
if (seq[i] - seq[i - 1] != diff) { | ||
recurse = 1; | ||
} | ||
} | ||
diffbuf[*iters - 1] = diffs[space - 1]; | ||
|
||
if (recurse) | ||
diff = analyze_diffs(diffs, space, space-1, iters, errf, diffbuf); | ||
|
||
return diff; | ||
} | ||
|
||
sspec_t *sspec_analyze(const long *seq, size_t len) | ||
{ | ||
int err = 0; | ||
sspec_t *ret; | ||
|
||
if (!seq || len < 2) | ||
return NULL; | ||
|
||
ret = malloc(sizeof(sspec_t)); | ||
ret->order = 0; | ||
ret->diff = analyze_diffs(seq, len, len - 1, &ret->order, &err, ret->state.diffs); | ||
ret->seq = seq; | ||
ret->seqlen = len; | ||
|
||
if (err) { | ||
free(ret); | ||
return NULL; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
int sspec_diff(sspec_t *spec) | ||
{ | ||
return spec->diff; | ||
} | ||
|
||
unsigned char sspec_ord(sspec_t *spec) | ||
{ | ||
return spec->order; | ||
} | ||
|
||
void sspec_continue(sspec_t* spec, long* buf, size_t buflen) | ||
{ | ||
long last = spec->seq[spec->seqlen - 1]; | ||
size_t i, j; | ||
|
||
if (!spec || !buf) | ||
return; | ||
|
||
for (i = 0; i < buflen; i++) { | ||
for (j = spec->order - 1; j > 0; j--) { | ||
spec->state.diffs[j - 1] = spec->state.diffs[j - 1] + spec->state.diffs[j]; | ||
} | ||
|
||
buf[i] = last + spec->state.diffs[0]; | ||
last = buf[i]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* Source: https://github.com/ethanv2/seqspec */ | ||
|
||
/* | ||
* seqspec - analyze and continue arbitrary sequences of any order | ||
* Copyright (C) Ethan Marshall - 2022 | ||
*/ | ||
|
||
#ifndef SEQSPEC_H | ||
#define SEQSPEC_H | ||
|
||
#include <stdlib.h> | ||
|
||
/* User facing headers | ||
* Library code *SHOULD NEVER* include this directly | ||
*/ | ||
|
||
/* | ||
* Opaque handle to sspec sequence data. | ||
* Whenever returned as a pointer, it is the caller's responsibility to free as | ||
* though any other pointer. | ||
* | ||
* The original sequence buffer as used to obtain this handle *must* remain | ||
* valid until this handle is no longer needed. A reference to the underlying | ||
* buffer may be maintained by the library. | ||
*/ | ||
typedef struct seqspec sspec_t; | ||
|
||
/* Main bulk of the library */ | ||
#include "sspec_internal.h" | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* Source: https://github.com/ethanv2/seqspec */ | ||
|
||
/* | ||
* seqspec - analyze and continue arbitrary sequences of any order | ||
* Copyright (C) Ethan Marshall - 2022 | ||
*/ | ||
|
||
#ifndef SEQSPEC_INTERNAL_H | ||
#define SEQSPEC_INTERNAL_H | ||
|
||
/* | ||
* Analyzes a sequence to find the order and differences. | ||
* If seq is NULL or of length < 2, NULL is returned. | ||
* If the properties of seq could not be determined in 255 iterations, | ||
* NULL is returned. | ||
*/ | ||
sspec_t *sspec_analyze(const long *seq, size_t len); | ||
|
||
/* | ||
* Returns the term difference of the sequence | ||
*/ | ||
int sspec_diff(sspec_t *spec); | ||
|
||
/* | ||
* Returns the logical order of the sequence. | ||
* This is *not* necessarily the same as the order of the nth term formula, | ||
* although it almost always is. | ||
*/ | ||
unsigned char sspec_ord(sspec_t *spec); | ||
|
||
/* | ||
* Fills buf up to buflen with a continuation of the sequence stored in spec. | ||
* The original sequence buffer must remain valid while this function is being | ||
* called. | ||
*/ | ||
void sspec_continue(sspec_t* spec, long* buf, size_t buflen); | ||
|
||
#endif |