General heap-based lattice point generator compiles, untested.

Former-commit-id: 8106cf72ad1d96426c2273493499db48d232f642
This commit is contained in:
Marek Nečada 2020-02-25 17:31:22 +02:00
parent 1e765e3cf6
commit f994514aeb
3 changed files with 182 additions and 73 deletions

View File

@ -1,6 +1,9 @@
#include "lattices.h" #include "lattices.h"
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <string.h>
#define MIN(x,y) ((x)<(y)?(x):(y))
// generic converting extractors // generic converting extractors
@ -103,7 +106,7 @@ PGenSph PGen_NAME_new(...) {
} }
// Dectructor // Dectructor
void PGen_NAME_dectructor(PGen *g) { void PGen_NAME_destructor(PGen *g) {
... ...
free(g->stateData); free(g->stateData);
g->stateData = NULL; g->stateData = NULL;
@ -601,8 +604,10 @@ size_t PGen_xyWeb_sizecap(cart2_t b1, cart2_t b2, double rtol, cart2_t offset,
return ((lf & ORTHOGONAL_01) ? 4 : 6) * (last_layer - layer + 1); return ((lf & ORTHOGONAL_01) ? 4 : 6) * (last_layer - layer + 1);
} }
//==== PGen_LatticeRadialHeap ==== //==== PGen_LatticeRadialHeap ====
extern const PGenClassInfo PGen_LatticeRadialHeap; // forward declaration needed by constructor (may be placed in header file instead) extern const PGenClassInfo PGen_LatticeRadialHeap; // forward declaration needed by constructor (may be placed in header file instead)
// Internal state structure // Internal state structure
@ -629,9 +634,11 @@ static inline double nd2norm(const double a[], int d) {
return sqrt(n); return sqrt(n);
} }
// Constructor // General Constructor
PGen PGen_LatticeRadialHeap_new(int ldim, int sdim, double bvectors[], double offset[], double minR, double maxR, PGen_LatticeRadialHeap_StateData *PGen_LatticeRadialHeap_new(int ldim, int sdim, double bvectors[],
double offset[], double minR, double maxR,
bool inc_minR, bool inc_maxR) { bool inc_minR, bool inc_maxR) {
QPMS_UNTESTED;
PGen_LatticeRadialHeap_StateData *s = PGen_LatticeRadialHeap_StateData *s =
malloc(sizeof(PGen_LatticeRadialHeap_StateData) + (ldim + 1) * sdim * sizeof(double)); malloc(sizeof(PGen_LatticeRadialHeap_StateData) + (ldim + 1) * sdim * sizeof(double));
s->ldim = ldim; s->ldim = ldim;
@ -653,7 +660,37 @@ PGen PGen_LatticeRadialHeap_new(int ldim, int sdim, double bvectors[], double of
s->layer_min_r = -INFINITY; s->layer_min_r = -INFINITY;
s->inc_minR = inc_minR; s->inc_maxR = inc_maxR; s->inc_minR = inc_minR; s->inc_maxR = inc_maxR;
PGen g = {&PGen_LatticeRadialHeap, (void *) s}; return s;
}
// 2D constructor
PGen PGen_LatticeRadialHeap2D_new(cart2_t b1, cart2_t b2, cart2_t offset,
double minR, bool inc_minR, double maxR, bool inc_maxR) {
double bvectors[4];
double offset_a[2];
cart2_to_double_array(&bvectors[0], b1);
cart2_to_double_array(&bvectors[2], b2);
cart2_to_double_array(offset_a, offset);
PGen g = {.c = &PGen_LatticeRadialHeap2D,
.stateData = PGen_LatticeRadialHeap_new(2, 2, bvectors, offset_a,
minR, maxR, inc_minR, inc_maxR)};
return g;
}
// 3D constructor
PGen PGen_LatticeRadialHeap3D_new(const cart3_t *b1, const cart3_t *b2, const cart3_t *b3,
const cart3_t *offset, double minR, bool inc_minR, double maxR, bool inc_maxR) {
double bvectors[9];
double offset_a[3];
int ldim = 0;
if (b1) {cart3_to_double_array(&bvectors[3*ldim], *b1); ++ldim;}
if (b2) {cart3_to_double_array(&bvectors[3*ldim], *b2); ++ldim;}
if (b3) {cart3_to_double_array(&bvectors[3*ldim], *b3); ++ldim;}
QPMS_ENSURE(ldim > 0, "At least one basis vector must be specified (non-NULL)");
PGen g = {.c = &PGen_LatticeRadialHeap3D,
.stateData = PGen_LatticeRadialHeap_new(ldim, 3, bvectors,
offset ? (cart3_to_double_array(offset_a, *offset), offset_a) : NULL,
minR, maxR, inc_minR, inc_maxR)};
return g; return g;
} }
@ -697,7 +734,7 @@ static inline double PGen_LatticeRadialHeap_nextlayer(PGen_LatticeRadialHeap_Sta
const int ldim = s->ldim; const int ldim = s->ldim;
const int sdim = s->sdim; const int sdim = s->sdim;
int *counter, *counter_cumsum, *tmp; int *counter, *counter_cumsum, *tmp;
QPMS_CRASHING_CALLOC(counter, s->ldim * 2 * sizeof(*counter)); QPMS_CRASHING_CALLOC(counter, s->ldim * 2, sizeof(*counter));
counter_cumsum = counter + s->ldim; counter_cumsum = counter + s->ldim;
counter[0] = s->layer; counter[0] = s->layer;
counter_cumsum[0] = s->layer; counter_cumsum[0] = s->layer;
@ -742,53 +779,83 @@ static inline double PGen_LatticeRadialHeap_nextlayer(PGen_LatticeRadialHeap_Sta
// sdim-independent generator method // sdim-independent generator method, returns the integer lattice coordinates
// N.B. This ALWAYS produces, not checking against maxR or destructing the generator itself // N.B. This ALWAYS produces, not checking against maxR or destructing the generator itself
// (although it does discard the points with distance smaller (or equal) than minR) // (although it does discard the points with distance smaller (or equal) than minR)
int PGen_LatticeRadialHeap_fillNext(PGen *g, int target[]) { // TODO maybe I want to return (double) r instead of (int) 0
if (g->stateData == NULL) // already destroyed int PGen_LatticeRadialHeap_fillNext_intcoords(PGen_LatticeRadialHeap_StateData *s, int target[]) {
return -1; //TODO some better error code bool hit = false;
else { while(!hit) {
PGen_LatticeRadialHeap_StateData * const s = (PGen_LatticeRadialHeap_StateData *) g->stateData; // Ensure that we have sufficiently filled heap
bool hit = false; while (s->heap_len < 1 || s->r_heap[0] + s->offset_r > s->layer_min_r)
while(!hit) { s->layer_min_r = PGen_LatticeRadialHeap_nextlayer(s);
// Ensure that we have sufficiently filled heap double r = s->r_heap[0];
while (heap_len < 1 || s->r_heap[0] + s->offset_r > s->layer_min_r) hit = (r > s->minR || (s->inc_minR && r == s->minR));
s->layer_min_r = PGen_LatticeRadialHeap_nextlayer(s); if (hit) memcpy(target, s->coord_heap, s->ldim * sizeof(*target));
double r = s->r_heap[0]; // Heap extract anyway
hit = (r > s->minR || (s->inc_minR && r == s->minR)); // Move last element to root
if (hit) memcpy(target, coord_heap, s->ldim * sizeof(*target)); --(s->heap_len);
// Heap extract anyway s->r_heap[0] = s->r_heap[s->heap_len];
// Move last element to root memmove(s->coord_heap, &s->coord_heap[s->ldim * s->heap_len], s->ldim * sizeof(*s->coord_heap));
--(s->heap_len); // Bubble down
s->r_heap[0] = s->r_heap[s->heap_len]; int pos = 0;
memmove(s->coord_heap, &s->coord_heap[ldim * s->heap_len], ldim * sizeof(*s->coord_heap)); while(1) {
// Bubble down int largest = pos, kidL = 2*pos+1, kidR = 2*pos+2;
int pos = 0; if (kidL < s->heap_len && s->r_heap[kidL] > s->r_heap[largest])
while(1) { largest = kidL;
int largest = pos, kidL = 2*pos+1, kidR = 2*pos+2; if (kidR < s->heap_len && s->r_heap[kidR] > s->r_heap[largest])
if (kidL < s->heap_len && s->r_heap[kidL] > s->r_heap[largest]) largest = kidR;
largest = kidL; if (largest == pos)
if (kidR < s->heap_len && s->r_heap[kidR] > s->r_heap[largest]) break;
largest = kidR; else { // swap
if (largest == pos) s->r_heap[pos] = s->r_heap[largest];
break; s->r_heap[largest] = r;
else { // swap memcpy(&s->coord_heap[s->ldim * pos], &s->coord_heap[s->ldim * largest], s->ldim * sizeof(*s->coord_heap));
s->r_heap[pos] = s->r_heap[largest]; memcpy(&s->coord_heap[s->ldim * largest], &s->coord_heap[s->ldim * s->heap_len /*it's still there*/],
s->r_heap[largest] = r; s->ldim * sizeof(*s->coord_heap));
memcpy(&s->coord_heap[ldim * pos], &s->coord_heap[ldim * largest], ldim * sizeof(*s->coord_heap));
memcpy(&s->coord_heap[ldim * largest], &s->coord_heap[ldim * s->heap_len /*it's still there*/],
ldim * sizeof(*s->coord_heap));
}
} }
} }
return 0; }
return 0;
}
// sdim-independent generator method, fills the point's cartesian coordinates, including the offset
// N.B. This ALWAYS produces, returning 0 if maxR not exceeded, else -2
// (it does discard the points with distance smaller (or equal) than minR)
#define LRH_STACKBUFSIZ 3 // Avoid heap allocation for typical dimensions
int PGen_LatticeRadialHeap_fillNext_cart(PGen *g, double target[]) {
if (g->stateData == NULL) // already destroyed
return -1; // LPTODO some other return value?
else {
PGen_LatticeRadialHeap_StateData * const s = g->stateData;
int stackbuf[LRH_STACKBUFSIZ];
int *buf;
if (s->sdim > LRH_STACKBUFSIZ) {
QPMS_CRASHING_MALLOC(buf, s->sdim * sizeof(*buf));
} else
buf = stackbuf;
QPMS_ENSURE_SUCCESS(PGen_LatticeRadialHeap_fillNext_intcoords(s, buf));
// Calculate the actual point
double r = 0;
for(int i = 0; i < s->sdim; ++i) { // calculate r
double component = s->b[s->ldim * s->sdim + i]; // offset
for (int j = 0; j < s->ldim; ++j)
component += s->b[j * s->sdim + i] * buf[j];
r += component * component;
target[i] = component;
}
r = sqrt(r);
if (s->sdim > LRH_STACKBUFSIZ) free(buf);
if (r < s->maxR || (r == s->maxR && s->inc_maxR))
return 0;
else
return -2;
} }
} }
// Destructor // Destructor
void PGen_LatticeRadialHeap_dectructor(PGen *g) { void PGen_LatticeRadialHeap_destructor(PGen *g) {
PGen_LatticeRadialHeap_StateData *s = g->stateData; PGen_LatticeRadialHeap_StateData *s = g->stateData;
free(s->r_heap); free(s->r_heap);
free(s->coord_heap); free(s->coord_heap);
@ -796,34 +863,36 @@ void PGen_LatticeRadialHeap_dectructor(PGen *g) {
g->stateData = NULL; g->stateData = NULL;
} }
// Extractor, spherical coordinate output // Extractor, 2D cartesian coordinate output
PGenSphReturnData PGen_LatticeRadialHeap_next_sph(PGen *g) { PGenCart2ReturnData PGen_LatticeRadialHeap2D_next_cart2(PGen *g) {
if (g->stateData == NULL) // already destroyed if (g->stateData == NULL) // already destroyed
return PGenSphDoneVal; return PGenCart2DoneVal;
else { else {
PGen_LatticeRadialHeap_StateData *s = (PGen_LatticeRadialHeap_StateData *) g->stateData; PGen_LatticeRadialHeap_StateData *s = (PGen_LatticeRadialHeap_StateData *) g->stateData;
if (... /* there are still points to be generated */) { QPMS_ENSURE(s->sdim <= 2, "Attemted to get a 2D point from %nD generator.", (int)(s->sdim));
... double target[2] = {0,0};
PGenSphReturnData retval = {.../*flags*/, .../*thePoint*/}; if (PGen_LatticeRadialHeap_fillNext_cart(g, target) == 0 /* there are still points to be generated */) {
PGenCart2ReturnData retval = {PGEN_COORDS_CART2 | PGEN_NOTDONE, cart2_from_double_array(target)};
return retval; return retval;
} else { } else { // Maybe more checking for errors?
PGen_destroy(g); PGen_destroy(g);
return PGenSphDoneVal; return PGenCart2DoneVal;
} }
} }
} }
// Extractor, 3D cartesian coordinate output // Extractor, 3D cartesian coordinate output
PGenCart3ReturnData PGen_LatticeRadialHeap_next_cart3(PGen *g) { PGenCart3ReturnData PGen_LatticeRadialHeap3D_next_cart3(PGen *g) {
if (g->stateData == NULL) // already destroyed if (g->stateData == NULL) // already destroyed
return PGenCart3DoneVal; return PGenCart3DoneVal;
else { else {
PGen_LatticeRadialHeap_StateData *s = (PGen_LatticeRadialHeap_StateData *) g->stateData; PGen_LatticeRadialHeap_StateData *s = (PGen_LatticeRadialHeap_StateData *) g->stateData;
if (... /* there are still points to be generated */) { QPMS_ENSURE(s->sdim <= 3, "Attemted to get a 3D point from %nD generator.", (int)(s->sdim));
... double target[3] = {0,0,0};
PGenCart3ReturnData retval = {.../*flags*/, .../*thePoint*/}; if (PGen_LatticeRadialHeap_fillNext_cart(g, target) == 0 /* there are still points to be generated */) {
PGenCart3ReturnData retval = {PGEN_COORDS_CART3 | PGEN_NOTDONE, cart3_from_double_array(target)};
return retval; return retval;
} else { } else { // Maybe more checking for errors?
PGen_destroy(g); PGen_destroy(g);
return PGenCart3DoneVal; return PGenCart3DoneVal;
} }
@ -831,23 +900,44 @@ PGenCart3ReturnData PGen_LatticeRadialHeap_next_cart3(PGen *g) {
} }
// Class metadata structure; TODO maybe this can rather be done by macro. // Class metadata structure; TODO maybe this can rather be done by macro.
const PGenClassInfo PGen_LatticeRadialHeap = { const PGenClassInfo PGen_LatticeRadialHeap2D = {
"PGen_LatticeRadialHeap", "PGen_LatticeRadialHeap2D", // 2D labels the space, not lattice dimension
?, //dimensionality 2, //dimensionality
PGEN_COORDS_????, // native coordinate system PGEN_COORDS_CART2, // native coordinate system
// some of the _next_... fun pointers can be NULL // some of the _next_... fun pointers can be NULL
PGen_LatticeRadialHeap_next, NULL, //PGen_LatticeRadialHeap2D_next,
PGen_LatticeRadialHeap_next_z, NULL, //PGen_LatticeRadialHeap2D_next_z,
PGen_LatticeRadialHeap_next_pol, PGen_next_pol_from_cart2, // NULL, //PGen_LatticeRadialHeap2D_next_pol,
PGen_LatticeRadialHeap_next_sph, PGen_next_sph_from_cart2, // NULL, //PGen_LatticeRadialHeap2D_next_sph,
PGen_LatticeRadialHeap_next_cart2, PGen_LatticeRadialHeap2D_next_cart2,
PGen_LatticeRadialHeap_next_cart3, PGen_next_cart3_from_cart2xy, // NULL, //PGen_LatticeRadialHeap2D_next_cart3,
PGen_LatticeRadialHeap_fetch, NULL, //PGen_LatticeRadialHeap2D_fetch,
PGen_LatticeRadialHeap_fetch_z, NULL, //PGen_LatticeRadialHeap2D_fetch_z,
PGen_LatticeRadialHeap_fetch_pol, NULL, //PGen_LatticeRadialHeap2D_fetch_pol,
PGen_LatticeRadialHeap_fetch_sph, NULL, //PGen_LatticeRadialHeap2D_fetch_sph,
PGen_LatticeRadialHeap_fetch_cart2, NULL, //PGen_LatticeRadialHeap2D_fetch_cart2,
PGen_LatticeRadialHeap_fetch_cart3, NULL, //PGen_LatticeRadialHeap2D_fetch_cart3,
PGen_LatticeRadialHeap_destructor
};
// Class metadata structure; TODO maybe this can rather be done by macro.
const PGenClassInfo PGen_LatticeRadialHeap3D = {
"PGen_LatticeRadialHeap3D", // 3D labels the space, not lattice dimension
3, //dimensionality
PGEN_COORDS_CART3, // native coordinate system
// some of the _next_... fun pointers can be NULL
NULL, //PGen_LatticeRadialHeap3D_next,
NULL, //PGen_LatticeRadialHeap3D_next_z,
NULL, //PGen_LatticeRadialHeap3D_next_pol,
PGen_next_sph_from_cart3, // NULL, //PGen_LatticeRadialHeap3D_next_sph,
NULL, //PGen_LatticeRadialHeap3D_next_cart2,
PGen_LatticeRadialHeap3D_next_cart3,
NULL, //PGen_LatticeRadialHeap3D_fetch,
NULL, //PGen_LatticeRadialHeap3D_fetch_z,
NULL, //PGen_LatticeRadialHeap3D_fetch_pol,
NULL, //PGen_LatticeRadialHeap3D_fetch_sph,
NULL, //PGen_LatticeRadialHeap3D_fetch_cart2,
NULL, //PGen_LatticeRadialHeap3D_fetch_cart3,
PGen_LatticeRadialHeap_destructor PGen_LatticeRadialHeap_destructor
}; };

View File

@ -627,6 +627,14 @@ size_t PGen_xyWeb_sizecap(cart2_t b1, cart2_t b2, double rtol, cart2_t offset,
double minR, bool inc_minR, double maxR, bool inc_maxR); double minR, bool inc_minR, double maxR, bool inc_maxR);
extern const PGenClassInfo PGen_LatticeRadialHeap2D;
extern const PGenClassInfo PGen_LatticeRadialHeap3D;
PGen PGen_LatticeRadialHeap2D_new(cart2_t b1, cart2_t b2, cart2_t offset,
double minR, bool inc_minR, double maxR, bool inc_maxR);
PGen PGen_LatticeRadialHeap3D_new(const cart3_t *b1, const cart3_t *b2, const cart3_t *b3,
const cart3_t *offset, double minR, bool inc_minR, double maxR, bool inc_maxR);
/* /*
* THE NICE PART (adaptation of lattices2d.py) * THE NICE PART (adaptation of lattices2d.py)
* =========================================== * ===========================================

View File

@ -885,6 +885,17 @@ static inline cart3_t cart3_from_double_array(const double a[]) {
return b; return b;
} }
/// Converts cart2_t to array of doubles.
static inline void cart2_to_double_array(double a[], cart2_t b) {
a[0] = b.x; a[1] = b.y;
}
/// Converts array of doubles to cart2_t
static inline cart2_t cart2_from_double_array(const double a[]) {
cart2_t b = {.x = a[0], .y = a[1]};
return b;
}
typedef double matrix3d[3][3]; typedef double matrix3d[3][3];
typedef double matrix2d[2][2]; typedef double matrix2d[2][2];