star-mc

Parallel estimation of Monte Carlo integrators
git clone git://git.meso-star.fr/star-mc.git
Log | Files | Refs | README | LICENSE

commit 89334116bca62fd013c5f005528459a1da9db518
parent 81b041b45a2fa0bdfe2da2cbceb9c4ffb1c0e76c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 15 Jul 2015 11:42:25 +0200

Add the smc_integrate function

This function performs a raw integration, i.e. the estimation of the
integration must be performed by the caller with respect to accumulated
values provided by the status of the smc_accumulator.

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/smc.h | 50++++++++++++++++++++++++++++++++++++++++++++++++--
Asrc/smc_accumulator.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/smc_type_c.h | 11+++++++++++
4 files changed, 285 insertions(+), 2 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -64,6 +64,7 @@ set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SMC_FILES_SRC + smc_accumulator.c smc_device.c smc_integrator.c smc_type.c) diff --git a/src/smc.h b/src/smc.h @@ -74,10 +74,18 @@ struct smc_type { void (*sqrt)(void* result, const void* value); }; +/* Type for raw integration, i.e. whithout estimator. Experiment results are + * simply accumulated */ +struct smc_type_raw { + void* (*create)(struct mem_allocator* allocator, void* ctx); + void (*destroy)(struct mem_allocator*, void* accum); + void (*clear)(void* accum); + void (*add)(void* result, const void* op0, const void* op1); +}; + static const struct smc_type SMC_TYPE_NULL = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - struct smc_estimator_status { void* E; /* Expected value */ void* V; /* Variance */ @@ -85,18 +93,30 @@ struct smc_estimator_status { size_t N; /* Samples count */ }; +struct smc_accumulator_status { + void* value; /* Accumulated value */ + size_t N; /* Samples count */ +}; + struct smc_integrator { void (*integrand)(void* value, struct ssp_rng* rng, void* ctx); const struct smc_type* type; size_t max_steps; /* Maximum # of experiments */ }; +struct smc_integrator_raw { + void (*integrand)(void* accum, struct ssp_rng* rng, void* ctx); + const struct smc_type_raw* type; + size_t max_steps; /* Maximum # of accumulation */ +}; + static const struct smc_integrator SMC_INTEGRATOR_NULL = { NULL, NULL, SIZE_MAX }; /* Forward declaration of opaque types */ struct smc_device; /* Entry point of the library */ struct smc_estimator; /* Estimator of an integrator */ +struct smc_accumulator; /* Accumulated values of a integration */ BEGIN_DECLS @@ -109,7 +129,7 @@ SMC_API const struct smc_type smc_double; #define SMC_DOUBLE(Val) (*(double*)(Val)) /******************************************************************************* - * API deinition + * Device API ******************************************************************************/ SMC_API res_T smc_device_create @@ -126,6 +146,9 @@ SMC_API res_T smc_device_ref_put (struct smc_device* dev); +/******************************************************************************* + * Integration API + ******************************************************************************/ SMC_API res_T smc_solve (struct smc_device* dev, @@ -155,6 +178,29 @@ smc_estimator_get_status (struct smc_estimator* estimator, struct smc_estimator_status* status); +/******************************************************************************* + * Accumulation API + ******************************************************************************/ +SMC_API res_T +smc_integrate + (struct smc_device* dev, + struct smc_integrator_raw* integrator, + void* ctx, + struct smc_accumulator** accumulator); + +SMC_API res_T +smc_accumulator_ref_get + (struct smc_accumulator* accumulator); + +SMC_API res_T +smc_accumulator_ref_put + (struct smc_accumulator* accumulator); + +SMC_API res_T +smc_accumulator_get_status + (struct smc_accumulator* accumulator, + struct smc_accumulator_status* status); + END_DECLS #endif /* SMC_H */ diff --git a/src/smc_accumulator.c b/src/smc_accumulator.c @@ -0,0 +1,225 @@ +/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) + * + * This software is a computer program whose purpose is to manage the + * statistical estimation of a function. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "smc.h" +#include "smc_device_c.h" +#include "smc_type_c.h" + +#include <rsys/mem_allocator.h> + +#include <omp.h> + +struct smc_accumulator { + struct smc_type_raw type; + struct smc_accumulator_status status; + struct smc_device* dev; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +accumulator_create + (struct smc_device* dev, + const struct smc_type_raw* type, + void* ctx, + struct smc_accumulator** out_accum) +{ + struct smc_accumulator* accum = NULL; + res_T res = RES_OK; + ASSERT(out_accum && dev && type); + + accum = MEM_CALLOC(dev->allocator, 1, sizeof(struct smc_accumulator)); + if(!accum) { + res = RES_MEM_ERR; + goto error; + } + SMC(device_ref_get(dev)); + accum->dev = dev; + ref_init(&accum->ref); + + accum->status.value = type->create(dev->allocator, ctx); + if(!accum->status.value) { + res = RES_MEM_ERR; + goto error; + } + type->clear(accum->status.value); + + accum->status.N = 0; + accum->type = *type; + +exit: + *out_accum = accum; + return res; +error: + if(accum) { + SMC(accumulator_ref_put(accum)); + accum = NULL; + } + goto exit; +} + +static char +check_integrator_raw(struct smc_integrator_raw* integrator) +{ + ASSERT(integrator); + return integrator->integrand + && integrator->type + && integrator->max_steps + && check_type_raw(integrator->type); +} + +static void +accumulator_release(ref_T* ref) +{ + struct smc_accumulator* accum; + struct smc_device* dev; + ASSERT(ref); + + accum = CONTAINER_OF(ref, struct smc_accumulator, ref); + dev = accum->dev; + if(accum->status.value) + accum->type.destroy(dev->allocator, accum->status.value); + MEM_RM(dev->allocator, accum); + SMC(device_ref_put(dev)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +smc_integrate + (struct smc_device* dev, + struct smc_integrator_raw* integrator, + void* ctx, + struct smc_accumulator** out_accum) +{ + struct smc_accumulator* accum = NULL; + int64_t i; + size_t nthreads = 0; + void** vals = NULL; + void** accums = NULL; + size_t* nsamples = NULL; + res_T res = RES_OK; + + if(!dev || !integrator || !out_accum || !check_integrator_raw(integrator)) { + res = RES_BAD_ARG; + goto error; + } + nthreads = device_get_threads_count(dev); + + /* Create and initializdd per thread memory variables */ + nsamples = MEM_CALLOC(dev->allocator, nthreads, sizeof(size_t)); + if(!nsamples) { + res = RES_MEM_ERR; + goto error; + } + vals = MEM_CALLOC(dev->allocator, nthreads, sizeof(void*)); + if(!vals) { res = RES_MEM_ERR; goto error; } + accums = MEM_CALLOC(dev->allocator, nthreads, sizeof(void*)); + FOR_EACH(i, 0, (int64_t)nthreads) { + vals[i] = integrator->type->create(dev->allocator, ctx); + if(!vals[i]) { res = RES_MEM_ERR; goto error; } + accums[i] = integrator->type->create(dev->allocator, ctx); + if(!accums[i]) { res = RES_MEM_ERR; goto error; } + integrator->type->clear(accums[i]); + } + + /* Create the accumulator */ + res = accumulator_create(dev, integrator->type, ctx, &accum); + if(res != RES_OK) goto error; + + /* Parallel evaluation of the integrator */ + #pragma omp parallel for schedule(static) + for(i=0; i < (int64_t)integrator->max_steps; ++i) { + const int ithread = omp_get_thread_num(); + integrator->type->clear(vals[i]); + integrator->integrand(vals[ithread], dev->rngs[ithread], ctx); + integrator->type->add(accums[ithread], accums[ithread], vals[ithread]); + ++nsamples[ithread]; + } + + /* Merge the parallel estimation into the final estimator */ + FOR_EACH(i, 0, (int64_t)nthreads) { + accum->status.N += nsamples[i]; + integrator->type->add(accum->status.value, accum->status.value, accums[i]); + } + +exit: + if(nsamples) MEM_RM(dev->allocator, nsamples); + if(vals) { + FOR_EACH(i, 0, (int64_t)nthreads) + if(vals[i]) integrator->type->destroy(dev->allocator, vals[i]); + MEM_RM(dev->allocator, vals); + } + if(accums) { + FOR_EACH(i, 0, (int64_t)nthreads) + if(accums[i]) integrator->type->destroy(dev->allocator, accums[i]); + MEM_RM(dev->allocator, accums); + } + if(out_accum) *out_accum = accum; + return res; + +error: + if(accum) { + SMC(accumulator_ref_put(accum)); + accum = NULL; + } + goto exit; +} + +res_T +smc_accumulator_ref_get(struct smc_accumulator* accum) +{ + if(!accum) return RES_BAD_ARG; + ref_get(&accum->ref); + return RES_OK; +} + +res_T +smc_accumulator_ref_put(struct smc_accumulator* accum) +{ + if(!accum) return RES_BAD_ARG; + ref_put(&accum->ref, accumulator_release); + return RES_OK; +} + +res_T +smc_accumulator_get_status + (struct smc_accumulator* accum, + struct smc_accumulator_status* status) +{ + if(!accum || !status) return RES_BAD_ARG; + *status = accum->status; + return RES_OK; +} + diff --git a/src/smc_type_c.h b/src/smc_type_c.h @@ -37,6 +37,7 @@ static INLINE char check_type(const struct smc_type* type) { + ASSERT(type); return type->create != NULL && type->destroy != NULL && type->set != NULL @@ -48,5 +49,15 @@ check_type(const struct smc_type* type) && type->sqrt != NULL; } +static INLINE char +check_type_raw(const struct smc_type_raw* type) +{ + ASSERT(type); + return type->create != NULL + && type->destroy != NULL + && type->clear != NULL + && type->add != NULL; +} + #endif /* SMC_TYPE_C_H */