Commit 834a6e42 authored by Éric Thiébaut's avatar Éric Thiébaut
Browse files

Generalize layouts to non-mirror things

parent b812d324
......@@ -11,6 +11,7 @@
#include "tao-alpao.h"
#include "tao-errors.h"
#include "tao-layouts.h"
#include "tao-generic.h"
#include <asdkWrapper.h>
......@@ -194,7 +195,7 @@ uint8_t* alpao_mirror_mask_create_by_name(
dims[0] = dim;
dims[1] = dim;
}
return tao_mirror_mask_create(dim, dim, nacts);
return tao_layout_mask_create(dim, dim, nacts);
}
}
}
......@@ -226,7 +227,7 @@ uint8_t* alpao_mirror_mask_create_by_nacts(
dims[0] = dim;
dims[1] = dim;
}
return tao_mirror_mask_create(dim, dim, nacts);
return tao_layout_mask_create(dim, dim, nacts);
}
// OPERATIONS ON MIRROR INSTANCES ---------------------------------------------
......
......@@ -10,6 +10,7 @@
// Copyright (C) 2021-2022, Éric Thiébaut.
#include "tao-alpao.h"
#include "tao-layouts.h"
#include "tao-errors.h"
#include "tao-generic.h"
#include "tao-remote-mirrors-private.h"
......
......@@ -56,6 +56,7 @@ include_HEADERS = \
tao-errors.h \
tao-fits.h \
tao-generic.h \
tao-layouts.h \
tao-macros.h \
tao-options.h \
tao-pixels.h \
......@@ -87,6 +88,7 @@ libtao_la_SOURCES = \
copy.c \
encodings.c \
errors.c \
layouts.c \
logmsg.c \
options.c \
pixels.c \
......
// tao-layouts.c -
//
// Implementation of 2-dimensional layouts of active elements in TAO.
//
//-----------------------------------------------------------------------------
//
// This file if part of TAO real-time software licensed under the MIT license
// (https://git-cral.univ-lyon1.fr/tao/tao-rt).
//
// Copyright (C) 2022, Éric Thiébaut.
#include <string.h>
#include "tao-utils.h"
#include "tao-layouts.h"
#include "tao-errors.h"
#include "tao-generic.h"
// Macros to access 2-D arrays in column-major order.
#define MSK(i1,i2) msk[(i1) + dim1*(i2)]
#define INDS(j1,j2) inds[(j1) + dim1*(j2)]
long tao_indexed_layout_build(
long* inds,
const uint8_t* msk,
long dim1,
long dim2,
unsigned int orient)
{
long k = 0;
if (msk == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return -1L;
}
if (dim1 < 1 || dim2 < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return -1L;
}
if (inds == NULL) {
// Just count the number of active sites.
long ntot = dim1*dim2;
for (long i = 0; i < ntot; ++i) {
if (msk[i] != 0) {
++k;
}
}
} else {
// What is the direction of the numbering?
bool reverse_1 = (orient & 1) != 0;
bool reverse_2 = (orient & 2) != 0;
bool swap_axes = (orient & 4) != 0;
// Fill array of indices according to direction of numbering.
if (swap_axes) {
// Numbering is in row-major order.
for (long i1 = 0; i1 < dim1; ++i1) {
long j1 = (reverse_1 ? (dim1 - 1) - i1 : i1);
for (long i2 = 0; i2 < dim2; ++i2) {
long j2 = (reverse_2 ? (dim2 - 1) - i2 : i2);
if (MSK(i1,i2) != 0) {
INDS(j1,j2) = k;
++k;
} else {
INDS(j1,j2) = -1;
}
}
}
} else {
// Numbering is in column-major order.
for (long i2 = 0; i2 < dim2; ++i2) {
long j2 = (reverse_2 ? (dim2 - 1) - i2 : i2);
for (long i1 = 0; i1 < dim1; ++i1) {
long j1 = (reverse_1 ? (dim1 - 1) - i1 : i1);
if (MSK(i1,i2) != 0) {
INDS(j1,j2) = k;
++k;
} else {
INDS(j1,j2) = -1;
}
}
}
}
}
return k;
}
#undef MSK
#undef INDS
long tao_indexed_layout_check(
const long* inds,
long dim1,
long dim2)
{
if (inds == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return -1;
}
if (dim1 < 1 || dim2 < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return -1;
}
long length = dim1*dim2;
long count = 0;
for (long i = 0; i < length; ++i) {
if (inds[i] >= 0) {
++count;
}
}
for (long i = 0; i < length; ++i) {
if (inds[i] >= count) {
tao_store_error(__func__, TAO_OUT_OF_RANGE);
return -1;
}
}
return count;
}
uint8_t* tao_layout_mask_create_from_text(
char const* shape[],
long nrows,
long dims[2])
{
// Check arguments.
if (shape == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
if (nrows == -1) {
// Count number of rows.
nrows = 0;
while (shape[nrows] != NULL) {
++nrows;
}
}
if (nrows < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
// Count number of columns.
long ncols = 0;
for (long i = 0; i < nrows; ++i) {
long n = (shape[i] == NULL) ? 0 : strlen(shape[i]);
if (i == 0) {
ncols = n;
} else if (n != ncols) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
}
if (ncols < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
// Convert the shape into a mask (the shape is in row-major storage order,
// the mask is in column-major storage order).
uint8_t* msk = tao_malloc(ncols*nrows*sizeof(uint8_t));
if (msk == NULL) {
return NULL;
}
for (long i = 0; i < nrows; ++i) {
const char* row = shape[i];
for (long j = 0; j < ncols; ++j) {
msk[i*ncols + j] = (row[j] == ' ' ? 0 : 1);
}
}
// Return results.
if (dims != NULL) {
dims[0] = ncols;
dims[1] = nrows;
}
return msk;
}
uint8_t* tao_layout_mask_create(
long dim1,
long dim2,
long nacts)
{
if (dim1 < 1 || dim2 < 1 || nacts < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
long len = dim1*dim2;
uint8_t* mask = tao_malloc(len*sizeof(uint8_t));
if (mask == NULL) {
return NULL;
}
return tao_layout_mask_instanciate(mask, dim1, dim2, nacts, NULL);
}
uint8_t* tao_layout_mask_instanciate(
uint8_t* mask,
long dim1,
long dim2,
long nacts,
long* work)
{
if (dim1 < 1 || dim2 < 1 || nacts < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
if (mask == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
long len = dim1*dim2;
if (nacts > len) {
for (long i = 0; i < len; ++i) {
mask[i] = true;
}
return mask;
}
bool own_work = (work == NULL);
if (own_work) {
// Allocate workspace.
work = tao_malloc(len*sizeof(long));
if (work == NULL) {
return NULL;
}
}
// Instantiate workspace with f(i1,i2) and compute its extreme values.
long q1 = dim1 - 1;
long q2 = dim2 - 1;
for (long i2 = 0; i2 < dim2; ++i2) {
long f2 = (q2 - i2)*i2;
for (long i1 = 0; i1 < dim1; ++i1) {
long f1 = (q1 - i1)*i1;
work[i1 + dim1*i2] = f1 + f2;
}
}
long fmin = work[0], fmax = work[0];
for (long i = 1; i < len; ++i) {
long f = work[i];
fmin = tao_min(fmin, f);
fmax = tao_max(fmax, f);
}
// Build the tightest bracket t1 ≥ t2 such that n1 ≤ nacts ≤ n2, with
// n1 = count(msk ≥ t1) and similarly for n2 and t2.
long t1 = fmin, n1 = len;
long t2 = fmin, n2 = len;
while (n1 > nacts) {
t2 = t1;
n2 = n1;
t1 = fmax;
n1 = 0;
for (long i = 0; i < len; ++i) {
long f = work[i];
if ((t2 < f) & (f < t1)) {
// Strictly between the disks defined by t1 and t2.
t1 = f;
}
n1 += (f >= t1);
}
}
long t = (nacts - n1 < n2 - nacts ? t1 : t2);
long n = (t == t1 ? n1 : n2);
if (n != nacts) {
fprintf(stderr, "WARNING: Only found an approximation with %ld "
"active elements instead of %ld.\n", n, nacts);
}
for (long i = 0; i < len; ++i) {
mask[i] = (work[i] >= t);
}
if (own_work) {
tao_free(work);
}
return mask;
}
......@@ -647,229 +647,3 @@ tao_status tao_remote_mirror_run_loop(
}
return status;
}
//-----------------------------------------------------------------------------
// UTILITIES
// Macros to access 2-D arrays in column-major order.
#define MSK(i1,i2) msk[(i1) + dim1*(i2)]
#define INDS(j1,j2) inds[(j1) + dim1*(j2)]
long tao_indexed_layout_build(
long* inds,
const uint8_t* msk,
long dim1,
long dim2,
unsigned int orient)
{
long k = 0;
if (msk == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return -1L;
}
if (dim1 < 1 || dim2 < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return -1L;
}
if (inds == NULL) {
// Just count the number of active sites.
long ntot = dim1*dim2;
for (long i = 0; i < ntot; ++i) {
if (msk[i] != 0) {
++k;
}
}
} else {
// What is the direction of the numbering?
bool reverse_1 = (orient & 1) != 0;
bool reverse_2 = (orient & 2) != 0;
bool swap_axes = (orient & 4) != 0;
// Fill array of indices according to direction of numbering.
if (swap_axes) {
// Numbering is in row-major order.
for (long i1 = 0; i1 < dim1; ++i1) {
long j1 = (reverse_1 ? (dim1 - 1) - i1 : i1);
for (long i2 = 0; i2 < dim2; ++i2) {
long j2 = (reverse_2 ? (dim2 - 1) - i2 : i2);
if (MSK(i1,i2) != 0) {
INDS(j1,j2) = k;
++k;
} else {
INDS(j1,j2) = -1;
}
}
}
} else {
// Numbering is in column-major order.
for (long i2 = 0; i2 < dim2; ++i2) {
long j2 = (reverse_2 ? (dim2 - 1) - i2 : i2);
for (long i1 = 0; i1 < dim1; ++i1) {
long j1 = (reverse_1 ? (dim1 - 1) - i1 : i1);
if (MSK(i1,i2) != 0) {
INDS(j1,j2) = k;
++k;
} else {
INDS(j1,j2) = -1;
}
}
}
}
}
return k;
}
#undef MSK
#undef INDS
uint8_t* tao_mirror_mask_create(
long dim1,
long dim2,
long nacts)
{
if (dim1 < 1 || dim2 < 1 || nacts < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
long len = dim1*dim2;
uint8_t* mask = tao_malloc(len*sizeof(uint8_t));
if (mask == NULL) {
return NULL;
}
return tao_mirror_mask_instanciate(mask, dim1, dim2, nacts, NULL);
}
uint8_t* tao_mirror_mask_instanciate(
uint8_t* mask,
long dim1,
long dim2,
long nacts,
long* work)
{
if (dim1 < 1 || dim2 < 1 || nacts < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
if (mask == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
long len = dim1*dim2;
if (nacts > len) {
for (long i = 0; i < len; ++i) {
mask[i] = true;
}
return mask;
}
bool own_work = (work == NULL);
if (own_work) {
// Allocate workspace.
work = tao_malloc(len*sizeof(long));
if (work == NULL) {
return NULL;
}
}
// Instantiate workspace with f(i1,i2) and compute its extreme values.
long q1 = dim1 - 1;
long q2 = dim2 - 1;
for (long i2 = 0; i2 < dim2; ++i2) {
long f2 = (q2 - i2)*i2;
for (long i1 = 0; i1 < dim1; ++i1) {
long f1 = (q1 - i1)*i1;
work[i1 + dim1*i2] = f1 + f2;
}
}
long fmin = work[0], fmax = work[0];
for (long i = 1; i < len; ++i) {
long f = work[i];
fmin = tao_min(fmin, f);
fmax = tao_max(fmax, f);
}
// Build the tightest bracket t1 ≥ t2 such that n1 ≤ nacts ≤ n2, with
// n1 = count(msk ≥ t1) and similarly for n2 and t2.
long t1 = fmin, n1 = len;
long t2 = fmin, n2 = len;
while (n1 > nacts) {
t2 = t1;
n2 = n1;
t1 = fmax;
n1 = 0;
for (long i = 0; i < len; ++i) {
long f = work[i];
if ((t2 < f) & (f < t1)) {
// Strictly between the disks defined by t1 and t2.
t1 = f;
}
n1 += (f >= t1);
}
}
long t = (nacts - n1 < n2 - nacts ? t1 : t2);
long n = (t == t1 ? n1 : n2);
if (n != nacts) {
fprintf(stderr, "WARNING: Only found an approximation with %ld "
"actuators instead of %ld.\n", n, nacts);
}
for (long i = 0; i < len; ++i) {
mask[i] = (work[i] >= t);
}
if (own_work) {
tao_free(work);
}
return mask;
}
uint8_t* tao_mirror_mask_create_from_text(
char const* shape[],
long nrows,
long dims[2])
{
// Check arguments.
if (shape == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
if (nrows <= 0) {
// Count number of rows.
nrows = 0;
while (shape[nrows] != NULL) {
++nrows;
}
}
// Count number of columns.
long ncols = 0;
for (long i = 0; i < nrows; ++i) {
long n = (shape[i] == NULL) ? 0 : strlen(shape[i]);
if (i == 0) {
ncols = n;
} else if (n != ncols) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
}
if (ncols < 1 || nrows < 1) {
tao_store_error(__func__, TAO_BAD_SIZE);
return NULL;
}
// Convert the shape into a mask (the shape is in row-major storage order,
// the mask is in column-major storage order).
uint8_t* msk = tao_malloc(ncols*nrows*sizeof(uint8_t));
if (msk == NULL) {
return NULL;
}
for (long i = 0; i < nrows; ++i) {
const char* row = shape[i];
for (long j = 0; j < ncols; ++j) {
msk[i*ncols + j] = (row[j] == ' ' ? 0 : 1);
}
}
// Return results.
if (dims != NULL) {
dims[0] = ncols;
dims[1] = nrows;
}
return msk;
}
......@@ -10,6 +10,7 @@
// Copyright (C) 2021-2022, Éric Thiébaut.
#include "tao-basics.h"
#include "tao-layouts.h"
#include "tao-remote-mirrors-private.h"
#include "tao-generic.h"
#include "tao-errors.h"
......@@ -232,7 +233,7 @@ int main(
progname);
return EXIT_FAILURE;
}
if (tao_mirror_mask_instanciate(msk, dim, dim, nacts, inds) == NULL) {
if (tao_layout_mask_instanciate(msk, dim, dim, nacts, inds) == NULL) {
fprintf(stderr, "%s: failed to instantiate mirror mask\n",
progname);
return EXIT_FAILURE;
......
// tao-layouts.h -
//
// Definitions and API for 2-dimensional layouts of active nodes in TAO.
//
//-----------------------------------------------------------------------------
//
// This file if part of TAO real-time software licensed under the MIT license
// (https://git-cral.univ-lyon1.fr/tao/tao-rt).
//
// Copyright (C) 2022, Éric Thiébaut.
#ifndef TAO_LAYOUTS_H_
#define TAO_LAYOUTS_H_ 1
#include <tao-basics.h>
TAO_BEGIN_DECLS
/**
* @addtogroup Laoyuts Two-dimensional layouts of active nodes.
*
* @ingroup Utilities
*
* @brief Common types and methods for 2-dimensional layouts of active nodes.
*
* @{
*/
/**
* Build an indexed layout given a mask.
*
* This function computes the number and the indices of active nodes in a 2-D
* array.
*
* The input mask `msk` is a `dim1` by `dim2` array of bytes where active nodes
* have a non-zero value.
*
* The destination array is a `dim1` by `dim2` array of integers where active
* nodes are set with their nonnegative indices while inactive nodes are set to
* `-1`. The active indices are unique and vary from `0` to `n - 1` with `n`
* the number of active nodes.
*
* The least significant bits of `orient` specify how to order the numbering of
* the active nodes:
*
* - If the 1st bit of `orient` is set, the numbering is decreasing along the
* 1st dimension; otherwise, the numbering is increasing along the 1st
* dimension.