Skip to content

Commit

Permalink
number sequence: add libsspec for sequence detection
Browse files Browse the repository at this point in the history
  • Loading branch information
ejv2 committed Sep 6, 2022
1 parent ae1f421 commit a081752
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 0 deletions.
110 changes: 110 additions & 0 deletions sspec.c
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];
}
}
31 changes: 31 additions & 0 deletions sspec.h
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
38 changes: 38 additions & 0 deletions sspec_internal.h
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

0 comments on commit a081752

Please sign in to comment.