From 47105483e4eecf5be15e6a566cd4e43a296b1cb3 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 10:33:31 -0700 Subject: [PATCH 1/9] Clean up build on OS X --- CMakeLists.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a32bf00..7d10394 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,11 @@ set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_V message(STATUS "inform version: ${${PROJECT_NAME}_VERSION}") -if (UNIX) - add_definitions("-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu1x") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -pg") -endif() - -if (APPLE) +add_definitions("-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu1x") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g") +if (UNIX AND NOT APPLE) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg") +elseif (APPLE) set(CMAKE_MACOSX_RPATH ON) endif() From 5ced1e57c41d228f7a8aaccdaab03dbd4c346378 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 10:53:26 -0700 Subject: [PATCH 2/9] Modify the package.sh script to support OSX --- dist/package.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dist/package.sh b/dist/package.sh index fafce3d..8b5dfdc 100755 --- a/dist/package.sh +++ b/dist/package.sh @@ -5,7 +5,6 @@ version=${version#"-- inform version: "} target=inform-$version prefix=dist/$target -tarball=$target"_linux-x86_64.tar.gz" cmake -H. -Bbuild/production -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$prefix > /dev/null make -C build/production all test @@ -14,6 +13,19 @@ cp dist/install.sh $prefix > /dev/null cp LICENSE $prefix > /dev/null cp README.md $prefix > /dev/null +system=`uname -s` +hardware=`uname -m` + +if [[ "$system" == "Darwin" ]]; then + platform="macosx" +elif [[ "$system" == "Linux" ]]; then + platform="linux" +else + echo "unsupported platform: $system" +fi + +tarball=$target"_"$platform"-"$hardware".tar.gz" + cd dist echo "Creating tarball: dist/$tarball" tar czf $tarball $target From 947bc4c9ea78363e30640a57f8e5bdf25381971e Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 11:04:45 -0700 Subject: [PATCH 3/9] Fix the build on windows --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d10394..8d5c1d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,12 @@ set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_V message(STATUS "inform version: ${${PROJECT_NAME}_VERSION}") -add_definitions("-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu1x") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g") if (UNIX AND NOT APPLE) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg") + add_definitions("-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu1x") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -pg") elseif (APPLE) + add_definitions("-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu1x") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g") set(CMAKE_MACOSX_RPATH ON) endif() From ba4f07ba81acaea65857e5764204f0fd081da547 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 12:20:33 -0700 Subject: [PATCH 4/9] Remove unused headers --- src/mutual_info.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mutual_info.c b/src/mutual_info.c index 7961f79..3f9e144 100644 --- a/src/mutual_info.c +++ b/src/mutual_info.c @@ -84,8 +84,6 @@ inline static void free_all(inform_dist **x, inform_dist **y, inform_dist **xy) inform_dist_free(*xy); } -#include - double inform_mutual_info(int const *xs, int const *ys, size_t n, int bx, int by, double b, inform_error *err) { From 185fdbdcdab7de650c1ad931228b7da017f3f566 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 12:20:59 -0700 Subject: [PATCH 5/9] Implement conditional entropy on timeseries. The implementation strongly mirrors the implementation of mutual information. --- include/inform/conditional_entropy.h | 29 +++ src/CMakeLists.txt | 1 + src/conditional_entropy.c | 121 +++++++++++ test/unittests/CMakeLists.txt | 1 + test/unittests/conditional_entropy.c | 297 +++++++++++++++++++++++++++ test/unittests/main.c | 2 + 6 files changed, 451 insertions(+) create mode 100644 include/inform/conditional_entropy.h create mode 100644 src/conditional_entropy.c create mode 100644 test/unittests/conditional_entropy.c diff --git a/include/inform/conditional_entropy.h b/include/inform/conditional_entropy.h new file mode 100644 index 0000000..d64a6d2 --- /dev/null +++ b/include/inform/conditional_entropy.h @@ -0,0 +1,29 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. +#pragma once + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Compute the conditional entropy between two timeseries, using the + * first as the condition. + */ +EXPORT double inform_conditional_entropy(int const *xs, int const *ys, + size_t n, int bx, int by, double b, inform_error *err); + +/** + * Compute the local conditional entropy between two timeseries, using the + * first as the condition. + */ +EXPORT double *inform_local_conditional_entropy(int const *xs, int const *ys, + size_t n, int bx, int by, double b, double *mi, inform_error *err); + +#ifdef __cplusplus +} +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d3997c..8beda50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ set(${PROJECT_NAME}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/active_info.c ${CMAKE_CURRENT_SOURCE_DIR}/block_entropy.c + ${CMAKE_CURRENT_SOURCE_DIR}/conditional_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/dist.c ${CMAKE_CURRENT_SOURCE_DIR}/entropy_rate.c ${CMAKE_CURRENT_SOURCE_DIR}/error.c diff --git a/src/conditional_entropy.c b/src/conditional_entropy.c new file mode 100644 index 0000000..c6205d1 --- /dev/null +++ b/src/conditional_entropy.c @@ -0,0 +1,121 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. +#include +#include + +static bool check_arguments(int const *xs, int const *ys, size_t n, int bx, + int by, inform_error *err) +{ + if (xs == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ETIMESERIES, true); + } + else if (ys == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ETIMESERIES, true); + } + else if (n < 1) + { + INFORM_ERROR_RETURN(err, INFORM_ESHORTSERIES, true); + } + else if (bx < 2) + { + INFORM_ERROR_RETURN(err, INFORM_EBASE, true); + } + else if (by < 2) + { + INFORM_ERROR_RETURN(err, INFORM_EBASE, true); + } + for (size_t i = 0; i < n; ++i) + { + if (xs[i] < 0 || ys[i] < 0) + { + INFORM_ERROR_RETURN(err, INFORM_ENEGSTATE, true); + } + else if (bx <= xs[i] || by <= ys[i]) + { + INFORM_ERROR_RETURN(err, INFORM_EBADSTATE, true); + } + } + return false; +} + +inline static bool allocate(int bx, int by, inform_dist **x, inform_dist **xy, + inform_error *err) +{ + if ((*x = inform_dist_alloc(bx)) == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, true); + } + if ((*xy = inform_dist_alloc(bx * by)) == NULL) + { + inform_dist_free(*x); + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, true); + } + return false; +} + +inline static void accumulate(int const *xs, int const *ys, size_t n, int by, + inform_dist *x, inform_dist *xy) +{ + x->counts = n; + xy->counts = n; + + for (size_t i = 0; i < n; ++i) + { + x->histogram[xs[i]]++; + xy->histogram[xs[i]*by + ys[i]]++; + } +} + +inline static void free_all(inform_dist **x, inform_dist **xy) +{ + inform_dist_free(*x); + inform_dist_free(*xy); +} + +double inform_conditional_entropy(int const *xs, int const *ys, size_t n, + int bx, int by, double b, inform_error *err) +{ + if (check_arguments(xs, ys, n, bx, by, err)) return NAN; + + inform_dist *x = NULL, *xy = NULL; + if (allocate(bx, by, &x, &xy, err)) return NAN; + + accumulate(xs, ys, n, by, x, xy); + + double ce = inform_shannon_ce(xy, x, (double) b); + + free_all(&x, &xy); + + return ce; +} + +double *inform_local_conditional_entropy(int const *xs, int const *ys, + size_t n, int bx, int by, double b, double *ce, inform_error *err) +{ + if (check_arguments(xs, ys, n, bx, by, err)) return NULL; + + if (ce == NULL) + { + ce = malloc(n * sizeof(double)); + if (ce == NULL) + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, NULL); + } + + inform_dist *x = NULL, *xy = NULL; + if (allocate(bx, by, &x, &xy, err)) return NULL; + + accumulate(xs, ys, n, by, x, xy); + + for (size_t i = 0; i < n; ++i) + { + int z = xs[i]*by + ys[i]; + ce[i] = inform_shannon_pce(xy, x, z, xs[i], (double) b); + } + + free_all(&x, &xy); + + return ce; +} \ No newline at end of file diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index a258b06..82ca300 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -2,6 +2,7 @@ set(${PROJECT_NAME}_UNITTEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/active_info.c ${CMAKE_CURRENT_SOURCE_DIR}/block_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/canary.c + ${CMAKE_CURRENT_SOURCE_DIR}/conditional_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/dist.c ${CMAKE_CURRENT_SOURCE_DIR}/entropy_rate.c ${CMAKE_CURRENT_SOURCE_DIR}/main.c diff --git a/test/unittests/conditional_entropy.c b/test/unittests/conditional_entropy.c new file mode 100644 index 0000000..5775dbf --- /dev/null +++ b/test/unittests/conditional_entropy.c @@ -0,0 +1,297 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. +#include "util.h" +#include +#include +#include + +UNIT(ConditionalEntropyNULLSeries) +{ + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(NULL, NULL, 3, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy((int[]){0,0,1}, NULL, 3, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); +} + +UNIT(ConditionalEntropySeriesTooShort) +{ + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, xs, 0, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ESHORTSERIES, err); +} + +UNIT(ConditionalEntropyInvalidBase) +{ + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + for (int i = 0; i < 2; ++i) + { + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, xs, 8, i, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, xs, 8, 2, i, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + } +} + +UNIT(ConditionalEntropyNegativeState) +{ + int const xs[] = {1,1,0,0,-1,0,0,1}; + int const ys[] = {1,1,0,0, 1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, ys, 8, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(ys, xs, 8, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); +} + +UNIT(ConditionalEntropyBadState) +{ + int const xs[] = {1,2,0,0,1,0,0,1}; + int const ys[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, ys, 8, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_conditional_entropy(xs, ys, 8, 2, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); +} + +UNIT(ConditionalEntropy) +{ + inform_error err = INFORM_SUCCESS; + + ASSERT_DBL_NEAR_TOL(0.899985, inform_conditional_entropy((int[]){0,0,1,1,1,1,0,0,0}, + (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.972765, inform_conditional_entropy((int[]){1,0,0,1,0,0,1,0,0}, + (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.000000, inform_conditional_entropy((int[]){0,0,0,0,1,1,1,1}, + (int[]){1,1,1,1,0,0,0,0}, 8, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.000000, inform_conditional_entropy((int[]){0,0,1,1,1,1,0,0,0}, + (int[]){1,1,0,0,0,0,1,1,1}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.918296, inform_conditional_entropy((int[]){1,1,0,1,0,1,1,1,0}, + (int[]){1,1,0,0,0,1,0,1,1}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.918296, inform_conditional_entropy((int[]){0,0,0,0,0,0,0,0,0}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.845516, inform_conditional_entropy((int[]){1,1,1,1,0,0,0,0,1}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.899985, inform_conditional_entropy((int[]){1,1,0,0,1,1,0,0,1}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.000000, inform_conditional_entropy((int[]){0,1,0,1,0,1,0,1}, + (int[]){0,2,0,2,0,2,0,2}, 8, 2, 3, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.918296, + inform_conditional_entropy((int[]){0,0,0,0,0,0,1,1,1,1,1,1}, + (int[]){0,0,0,0,1,1,1,1,2,2,2,2}, 12, 2, 3, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.444444, inform_conditional_entropy((int[]){0,0,1,1,2,1,1,0,0}, + (int[]){0,0,0,1,1,1,0,0,0}, 9, 3, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.666667, inform_conditional_entropy((int[]){0,1,0,0,1,0,0,1,0}, + (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.606844, inform_conditional_entropy((int[]){1,0,0,1,0,0,1,0}, + (int[]){2,0,1,2,0,1,2,0}, 8, 2, 3, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); +} + +UNIT(LocalConditionalEntropyNULLSeries) +{ + double ce[8]; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(NULL, NULL, 3, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy((int[]){0,0,1}, NULL, 3, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); +} + +UNIT(LocalConditionalEntropySeriesTooShort) +{ + double ce[8]; + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, xs, 0, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ESHORTSERIES, err); +} + +UNIT(LocalConditionalEntropyInvalidBase) +{ + double ce[8]; + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + for (int i = 0; i < 2; ++i) + { + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, xs, 8, i, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, xs, 8, 2, i, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + } +} + +UNIT(LocalConditionalEntropyNegativeState) +{ + double ce[8]; + int const xs[] = {1,1,0,0,-1,0,0,1}; + int const ys[] = {1,1,0,0, 1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, ys, 8, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(ys, xs, 8, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); +} + +UNIT(LocalConditionalEntropyBadState) +{ + double ce[8]; + int const xs[] = {1,2,0,0,1,0,0,1}; + int const ys[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, ys, 8, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_conditional_entropy(xs, ys, 8, 2, 2, 2, ce, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); +} + +UNIT(LocalConditionalEntropyAllocatesOutput) +{ + int const xs[] = {0,0,1,1,1,1,0,0,0}; + int const ys[] = {1,1,0,0,0,0,1,1,1}; + inform_error err = INFORM_SUCCESS; + double *ce = inform_local_conditional_entropy(xs, ys, 9, 2, 2, 2, NULL, &err); + ASSERT_NOT_NULL(ce); + ASSERT_EQUAL(INFORM_SUCCESS, err); + free(ce); +} + +UNIT(LocalConditionalEntropy) +{ + inform_error err = INFORM_SUCCESS; + double ce_8[8]; + double ce_9[9]; + double ce_12[12]; + + inform_local_conditional_entropy((int[]){0,0,1,1,1,1,0,0,0}, (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.899985, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){1,0,0,1,0,0,1,0,0}, (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.972765, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,0,0,0,1,1,1,1}, (int[]){1,1,1,1,0,0,0,0}, 8, 2, 2, 2, ce_8, &err); + ASSERT_DBL_NEAR_TOL(0.000000, AVERAGE(ce_8), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,0,1,1,1,1,0,0,0}, (int[]){1,1,0,0,0,0,1,1,1}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.000000, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){1,1,0,1,0,1,1,1,0}, (int[]){1,1,0,0,0,1,0,1,1}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.918296, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,0,0,0,0,0,0,0,0}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.918296, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){1,1,1,1,0,0,0,0,1}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.845516, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){1,1,0,0,1,1,0,0,1}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.899985, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,1,0,1,0,1,0,1}, (int[]){0,2,0,2,0,2,0,2}, 8, 2, 3, 2, ce_8, &err); + ASSERT_DBL_NEAR_TOL(0.000000, AVERAGE(ce_8), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,0,0,0,0,0,1,1,1,1,1,1}, (int[]){0,0,0,0,1,1,1,1,2,2,2,2}, 12, 2, 3, 2, ce_12, &err); + ASSERT_DBL_NEAR_TOL(0.918296, AVERAGE(ce_12), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,0,1,1,2,1,1,0,0}, (int[]){0,0,0,1,1,1,0,0,0}, 9, 3, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.444444, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){0,1,0,0,1,0,0,1,0}, (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, 2, ce_9, &err); + ASSERT_DBL_NEAR_TOL(0.666667, AVERAGE(ce_9), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_conditional_entropy((int[]){1,0,0,1,0,0,1,0}, (int[]){2,0,1,2,0,1,2,0}, 8, 2, 3, 2, ce_8, &err); + ASSERT_DBL_NEAR_TOL(0.606844, AVERAGE(ce_8), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); +} + +BEGIN_SUITE(ConditionalEntropy) + ADD_UNIT(ConditionalEntropyNULLSeries) + ADD_UNIT(ConditionalEntropySeriesTooShort) + ADD_UNIT(ConditionalEntropyInvalidBase) + ADD_UNIT(ConditionalEntropyNegativeState) + ADD_UNIT(ConditionalEntropyBadState) + ADD_UNIT(ConditionalEntropy) + ADD_UNIT(LocalConditionalEntropyNULLSeries) + ADD_UNIT(LocalConditionalEntropySeriesTooShort) + ADD_UNIT(LocalConditionalEntropyInvalidBase) + ADD_UNIT(LocalConditionalEntropyNegativeState) + ADD_UNIT(LocalConditionalEntropyBadState) + ADD_UNIT(LocalConditionalEntropyAllocatesOutput) + ADD_UNIT(LocalConditionalEntropy) +END_SUITE diff --git a/test/unittests/main.c b/test/unittests/main.c index f1f894c..fb4f982 100644 --- a/test/unittests/main.c +++ b/test/unittests/main.c @@ -6,6 +6,7 @@ IMPORT_SUITE(ActiveInformation); IMPORT_SUITE(BlockEntropy); IMPORT_SUITE(Canary); +IMPORT_SUITE(ConditionalEntropy); IMPORT_SUITE(Distribution); IMPORT_SUITE(Entropy); IMPORT_SUITE(EntropyRate); @@ -17,6 +18,7 @@ BEGIN_REGISTRATION REGISTER(ActiveInformation) REGISTER(BlockEntropy) REGISTER(Canary) + REGISTER(ConditionalEntropy) REGISTER(Distribution) REGISTER(Entropy) REGISTER(EntropyRate) From c1bea55ad3d06b2eb87421780e5b91f0f7ed5c85 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 13:07:21 -0700 Subject: [PATCH 6/9] Implement relative entropy for timeseries --- include/inform/relative_entropy.h | 22 +++++ src/CMakeLists.txt | 1 + src/relative_entropy.c | 89 +++++++++++++++++++ test/unittests/CMakeLists.txt | 1 + test/unittests/main.c | 2 + test/unittests/relative_entropy.c | 139 ++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+) create mode 100644 include/inform/relative_entropy.h create mode 100644 src/relative_entropy.c create mode 100644 test/unittests/relative_entropy.c diff --git a/include/inform/relative_entropy.h b/include/inform/relative_entropy.h new file mode 100644 index 0000000..a391e9a --- /dev/null +++ b/include/inform/relative_entropy.h @@ -0,0 +1,22 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. +#pragma once + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Compute the relative entropy between two timeseries, each considered as + * a timeseries of samples from two distributions. + */ +EXPORT double inform_relative_entropy(int const *xs, int const *ys, size_t n, + int b, double base, inform_error *err); + +#ifdef __cplusplus +} +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8beda50..548965f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ set(${PROJECT_NAME}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/entropy_rate.c ${CMAKE_CURRENT_SOURCE_DIR}/error.c ${CMAKE_CURRENT_SOURCE_DIR}/mutual_info.c + ${CMAKE_CURRENT_SOURCE_DIR}/relative_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/shannon.c ${CMAKE_CURRENT_SOURCE_DIR}/transfer_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/utilities/binning.c diff --git a/src/relative_entropy.c b/src/relative_entropy.c new file mode 100644 index 0000000..cbcd45c --- /dev/null +++ b/src/relative_entropy.c @@ -0,0 +1,89 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. +#include +#include + +static bool check_arguments(int const *xs, int const *ys, size_t n, int b, + inform_error *err) +{ + if (xs == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ETIMESERIES, true); + } + else if (ys == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ETIMESERIES, true); + } + else if (n < 1) + { + INFORM_ERROR_RETURN(err, INFORM_ESHORTSERIES, true); + } + else if (b < 2) + { + INFORM_ERROR_RETURN(err, INFORM_EBASE, true); + } + for (size_t i = 0; i < n; ++i) + { + if (xs[i] < 0 || ys[i] < 0) + { + INFORM_ERROR_RETURN(err, INFORM_ENEGSTATE, true); + } + else if (b <= xs[i] || b <= ys[i]) + { + INFORM_ERROR_RETURN(err, INFORM_EBADSTATE, true); + } + } + return false; +} + +inline static bool allocate(int b, inform_dist **x, inform_dist **y, + inform_error *err) +{ + if ((*x = inform_dist_alloc(b)) == NULL) + { + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, true); + } + if ((*y = inform_dist_alloc(b)) == NULL) + { + inform_dist_free(*x); + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, true); + } + return false; +} + +inline static void accumulate(int const *xs, int const *ys, size_t n, + inform_dist *x, inform_dist *y) +{ + x->counts = n; + y->counts = n; + + for (size_t i = 0; i < n; ++i) + { + x->histogram[xs[i]]++; + y->histogram[ys[i]]++; + } +} + +inline static void free_all(inform_dist **x, inform_dist **y) +{ + inform_dist_free(*x); + inform_dist_free(*y); +} + +double inform_relative_entropy(int const *xs, int const *ys, size_t n, int b, + double base, inform_error *err) +{ + if (check_arguments(xs, ys, n, b, err)) return NAN; + + inform_dist *x = NULL, *y = NULL; + if (allocate(b, &x, &y, err)) return NAN; + + accumulate(xs, ys, n, x, y); + + double re = inform_shannon_re(x, y, base); + + free_all(&x, &y); + + return re; +} diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 82ca300..22b529a 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -7,6 +7,7 @@ set(${PROJECT_NAME}_UNITTEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/entropy_rate.c ${CMAKE_CURRENT_SOURCE_DIR}/main.c ${CMAKE_CURRENT_SOURCE_DIR}/mutual_info.c + ${CMAKE_CURRENT_SOURCE_DIR}/relative_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/shannon.c ${CMAKE_CURRENT_SOURCE_DIR}/transfer_entropy.c ${CMAKE_CURRENT_SOURCE_DIR}/util.c diff --git a/test/unittests/main.c b/test/unittests/main.c index fb4f982..85e7077 100644 --- a/test/unittests/main.c +++ b/test/unittests/main.c @@ -11,6 +11,7 @@ IMPORT_SUITE(Distribution); IMPORT_SUITE(Entropy); IMPORT_SUITE(EntropyRate); IMPORT_SUITE(MutualInfo); +IMPORT_SUITE(RelativeEntropy); IMPORT_SUITE(TransferEntropy); IMPORT_SUITE(Utilities); @@ -23,6 +24,7 @@ BEGIN_REGISTRATION REGISTER(Entropy) REGISTER(EntropyRate) REGISTER(MutualInfo) + REGISTER(RelativeEntropy) REGISTER(TransferEntropy) REGISTER(Utilities) END_REGISTRATION diff --git a/test/unittests/relative_entropy.c b/test/unittests/relative_entropy.c new file mode 100644 index 0000000..9557e14 --- /dev/null +++ b/test/unittests/relative_entropy.c @@ -0,0 +1,139 @@ +// Copyright 2016 ELIFE. All rights reserved. +// Use of this source code is governed by a reT +// license that can be found in the LICENSE file. +#include "util.h" +#include +#include +#include + +UNIT(RelativeEntropyNULLSeries) +{ + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(NULL, NULL, 3, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy((int[]){0,0,1}, NULL, 3, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); +} + +UNIT(RelativeEntropySeriesTooShort) +{ + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(xs, xs, 0, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ESHORTSERIES, err); +} + +UNIT(RelativeEntropyInvalidBase) +{ + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + for (int i = 0; i < 2; ++i) + { + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(xs, xs, 8, i, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + } +} + +UNIT(RelativeEntropyNegativeState) +{ + int const xs[] = {1,1,0,0,-1,0,0,1}; + int const ys[] = {1,1,0,0, 1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(xs, ys, 8, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(ys, xs, 8, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); +} + +UNIT(RelativeEntropyBadState) +{ + int const xs[] = {1,2,0,0,1,0,0,1}; + int const ys[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(xs, ys, 8, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_TRUE(isnan(inform_relative_entropy(xs, ys, 8, 2, 2, &err))); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); +} + +UNIT(RelativeEntropy) +{ + inform_error err = INFORM_SUCCESS; + + ASSERT_DBL_NEAR_TOL(0.038330, inform_relative_entropy((int[]){0,0,1,1,1,1,0,0,0}, + (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, &err), 1e-6); // == 0.038330 + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.037010, inform_relative_entropy((int[]){1,0,0,1,0,0,1,0,0}, + (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, &err), 1e-6); // == 0.037010 + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.000000, inform_relative_entropy((int[]){0,0,0,0,1,1,1,1}, + (int[]){1,1,1,1,0,0,0,0}, 8, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.035770, inform_relative_entropy((int[]){0,0,1,1,1,1,0,0,0}, + (int[]){1,1,0,0,0,0,1,1,1}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.037010, inform_relative_entropy((int[]){1,1,0,1,0,1,1,1,0}, + (int[]){1,1,0,0,0,1,0,1,1}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(1.584963, inform_relative_entropy((int[]){0,0,0,0,0,0,0,0,0}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.038331, inform_relative_entropy((int[]){1,1,1,1,0,0,0,0,1}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.038331, inform_relative_entropy((int[]){1,1,0,0,1,1,0,0,1}, + (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_TRUE(isnan(inform_relative_entropy((int[]){0,1,0,1,0,1,0,1}, + (int[]){0,2,0,2,0,2,0,2}, 8, 3, 2, &err))); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.584963, + inform_relative_entropy((int[]){0,0,0,0,0,0,1,1,1,1,1,1}, + (int[]){0,0,0,0,1,1,1,1,2,2,2,2}, 12, 3, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_TRUE(isnan(inform_relative_entropy((int[]){0,0,1,1,2,1,1,0,0}, + (int[]){0,0,0,1,1,1,0,0,0}, 9, 3, 2, &err))); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.000000, inform_relative_entropy((int[]){0,1,0,0,1,0,0,1,0}, + (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + ASSERT_DBL_NEAR_TOL(0.679964, inform_relative_entropy((int[]){1,0,0,1,0,0,1,0}, + (int[]){2,0,1,2,0,1,2,0}, 8, 3, 2, &err), 1e-6); + ASSERT_EQUAL(INFORM_SUCCESS, err); +} + +BEGIN_SUITE(RelativeEntropy) + ADD_UNIT(RelativeEntropyNULLSeries) + ADD_UNIT(RelativeEntropySeriesTooShort) + ADD_UNIT(RelativeEntropyInvalidBase) + ADD_UNIT(RelativeEntropyNegativeState) + ADD_UNIT(RelativeEntropyBadState) + ADD_UNIT(RelativeEntropy) +END_SUITE From b615cde0b9c98dec43d570a4bec6cac0a8f4ceec Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 14:37:13 -0700 Subject: [PATCH 7/9] Fix sign of pointwise relative entropy --- src/shannon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shannon.c b/src/shannon.c index e5baafb..fed1706 100644 --- a/src/shannon.c +++ b/src/shannon.c @@ -98,7 +98,7 @@ double inform_shannon_pre(inform_dist const *p, inform_dist const *q, { double u = inform_dist_prob(p, event); double v = inform_dist_prob(q, event); - return -log2(u/v) / log2(base); + return log2(u/v) / log2(base); } return NAN; } From fd4d81a59b974e0fb39d6a6ee0ddd95b387a4e86 Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 14:38:04 -0700 Subject: [PATCH 8/9] Implement local relative entropy for timeseries --- include/inform/relative_entropy.h | 7 ++ src/relative_entropy.c | 27 +++++ test/unittests/relative_entropy.c | 181 +++++++++++++++++++++++++++++- 3 files changed, 212 insertions(+), 3 deletions(-) diff --git a/include/inform/relative_entropy.h b/include/inform/relative_entropy.h index a391e9a..a9b0084 100644 --- a/include/inform/relative_entropy.h +++ b/include/inform/relative_entropy.h @@ -17,6 +17,13 @@ extern "C" EXPORT double inform_relative_entropy(int const *xs, int const *ys, size_t n, int b, double base, inform_error *err); +/** + * Compute the pointwise relative entropy between two timeseries, each + * considered as a timeseries of samples from two distributions. + */ +EXPORT double *inform_local_relative_entropy(int const *xs, int const *ys, + size_t n, int b, double base, double *re, inform_error *err); + #ifdef __cplusplus } #endif diff --git a/src/relative_entropy.c b/src/relative_entropy.c index cbcd45c..0964016 100644 --- a/src/relative_entropy.c +++ b/src/relative_entropy.c @@ -87,3 +87,30 @@ double inform_relative_entropy(int const *xs, int const *ys, size_t n, int b, return re; } + +double *inform_local_relative_entropy(int const *xs, int const *ys, size_t n, + int b, double base, double *re, inform_error *err) +{ + if (check_arguments(xs, ys, n, b, err)) return NULL; + + if (re == NULL) + { + re = malloc(n * sizeof(double)); + if (re == NULL) + INFORM_ERROR_RETURN(err, INFORM_ENOMEM, NULL); + } + + inform_dist *x = NULL, *y = NULL; + if (allocate(b, &x, &y, err)) return NULL; + + accumulate(xs, ys, n, x, y); + + for (size_t i = 0; i < (size_t) b; ++i) + { + re[i] = inform_shannon_pre(x, y, i, base); + } + + free_all(&x, &y); + + return re; +} \ No newline at end of file diff --git a/test/unittests/relative_entropy.c b/test/unittests/relative_entropy.c index 9557e14..875e9c1 100644 --- a/test/unittests/relative_entropy.c +++ b/test/unittests/relative_entropy.c @@ -1,5 +1,5 @@ // Copyright 2016 ELIFE. All rights reserved. -// Use of this source code is governed by a reT +// Use of this source code is governed by a MIT // license that can be found in the LICENSE file. #include "util.h" #include @@ -76,11 +76,11 @@ UNIT(RelativeEntropy) inform_error err = INFORM_SUCCESS; ASSERT_DBL_NEAR_TOL(0.038330, inform_relative_entropy((int[]){0,0,1,1,1,1,0,0,0}, - (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, &err), 1e-6); // == 0.038330 + (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, &err), 1e-6); ASSERT_EQUAL(INFORM_SUCCESS, err); ASSERT_DBL_NEAR_TOL(0.037010, inform_relative_entropy((int[]){1,0,0,1,0,0,1,0,0}, - (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, &err), 1e-6); // == 0.037010 + (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, &err), 1e-6); ASSERT_EQUAL(INFORM_SUCCESS, err); ASSERT_DBL_NEAR_TOL(0.000000, inform_relative_entropy((int[]){0,0,0,0,1,1,1,1}, @@ -129,6 +129,174 @@ UNIT(RelativeEntropy) ASSERT_EQUAL(INFORM_SUCCESS, err); } +UNIT(LocalRelativeEntropyNULLSeries) +{ + double re[8]; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(NULL, NULL, 3, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy((int[]){0,0,1}, NULL, 3, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ETIMESERIES, err); +} + +UNIT(LocalRelativeEntropySeriesTooShort) +{ + double re[8]; + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(xs, xs, 0, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ESHORTSERIES, err); +} + +UNIT(LocalRelativeEntropyInvalidBase) +{ + double re[8]; + int const xs[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + for (int i = 0; i < 2; ++i) + { + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(xs, xs, 8, i, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBASE, err); + } +} + +UNIT(LocalRelativeEntropyNegativeState) +{ + double re[8]; + int const xs[] = {1,1,0,0,-1,0,0,1}; + int const ys[] = {1,1,0,0, 1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(xs, ys, 8, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(ys, xs, 8, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_ENEGSTATE, err); +} + +UNIT(LocalRelativeEntropyBadState) +{ + double re[8]; + int const xs[] = {1,2,0,0,1,0,0,1}; + int const ys[] = {1,1,0,0,1,0,0,1}; + inform_error err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(xs, ys, 8, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); + + err = INFORM_SUCCESS; + ASSERT_NULL(inform_local_relative_entropy(xs, ys, 8, 2, 2, re, &err)); + ASSERT_TRUE(inform_failed(&err)); + ASSERT_EQUAL(INFORM_EBADSTATE, err); +} + +UNIT(LocalRelativeEntropyAllocatesOutput) +{ + int const xs[] = {0,0,1,1,1,1,0,0,0}; + int const ys[] = {1,1,0,0,0,0,1,1,1}; + inform_error err = INFORM_SUCCESS; + double *re = inform_local_relative_entropy(xs, ys, 9, 2, 2, NULL, &err); + ASSERT_NOT_NULL(re); + ASSERT_EQUAL(INFORM_SUCCESS, err); + free(re); +} + +bool dbl_near_tol_arrays(double const *xs, double const *ys, size_t n, double tol) +{ + for (size_t i = 0; i < n; ++i) + { + if (isnan(xs[i]) && isnan(ys[i])) + { + continue; + } + else if (isinf(xs[i]) && isinf(ys[i])) + { + continue; + } + else if (isnan(xs[i]) || isnan(ys[i])) + { + return false; + } + else if (isinf(xs[i]) || isinf(ys[i])) + { + return false; + } + else if (fabs(xs[i] - ys[i]) > tol) + { + return false; + } + } + return true; +} + +UNIT(LocalRelativeEntropy) +{ + inform_error err = INFORM_SUCCESS; + double re_2[2]; + double re_3[3]; + + inform_local_relative_entropy((int[]){0,0,1,1,1,1,0,0,0}, (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){-0.263034, 0.415037}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){1,0,0,1,0,0,1,0,0}, (int[]){0,0,1,1,1,1,0,0,0}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.263034, -0.415037}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,0,0,0,1,1,1,1}, (int[]){1,1,1,1,0,0,0,0}, 8, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.000000, 0.000000}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,0,1,1,1,1,0,0,0}, (int[]){1,1,0,0,0,0,1,1,1}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.321928, -0.321928}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){1,1,0,1,0,1,1,1,0}, (int[]){1,1,0,0,0,1,0,1,1}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){-0.415037, 0.263034}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,0,0,0,0,0,0,0,0}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){1.584963, -INFINITY}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){1,1,1,1,0,0,0,0,1}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.415037, -0.263034}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){1,1,0,0,1,1,0,0,1}, (int[]){1,1,1,0,0,0,1,1,1}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.415037, -0.263034}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,1,0,1,0,1,0,1}, (int[]){0,2,0,2,0,2,0,2}, 8, 3, 2, re_3, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.000000, INFINITY, -INFINITY}, re_3, 3, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,0,0,0,0,0,1,1,1,1,1,1}, (int[]){0,0,0,0,1,1,1,1,2,2,2,2}, 12, 3, 2, re_3, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.584963, 0.584963, -INFINITY}, re_3, 3, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,0,1,1,2,1,1,0,0}, (int[]){0,0,0,1,1,1,0,0,0}, 9, 3, 2, re_3, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){-0.584963, 0.415037, INFINITY}, re_3, 3, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){0,1,0,0,1,0,0,1,0}, (int[]){1,0,0,1,0,0,1,0,0}, 9, 2, 2, re_2, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.000000, 0.000000, -INFINITY}, re_2, 2, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); + + inform_local_relative_entropy((int[]){1,0,0,1,0,0,1,0}, (int[]){2,0,1,2,0,1,2,0}, 8, 3, 2, re_3, &err); + ASSERT_TRUE(dbl_near_tol_arrays((double[]){0.736966, 0.584963, -INFINITY}, re_3, 3, 1e-6)); + ASSERT_EQUAL(INFORM_SUCCESS, err); +} + BEGIN_SUITE(RelativeEntropy) ADD_UNIT(RelativeEntropyNULLSeries) ADD_UNIT(RelativeEntropySeriesTooShort) @@ -136,4 +304,11 @@ BEGIN_SUITE(RelativeEntropy) ADD_UNIT(RelativeEntropyNegativeState) ADD_UNIT(RelativeEntropyBadState) ADD_UNIT(RelativeEntropy) + ADD_UNIT(LocalRelativeEntropyNULLSeries) + ADD_UNIT(LocalRelativeEntropySeriesTooShort) + ADD_UNIT(LocalRelativeEntropyInvalidBase) + ADD_UNIT(LocalRelativeEntropyNegativeState) + ADD_UNIT(LocalRelativeEntropyBadState) + ADD_UNIT(LocalRelativeEntropyAllocatesOutput) + ADD_UNIT(LocalRelativeEntropy) END_SUITE From 8189c86f0863f36667defb0612db820ec4751d4b Mon Sep 17 00:00:00 2001 From: Douglas Moore Date: Mon, 1 Aug 2016 14:53:36 -0700 Subject: [PATCH 9/9] Update version to 0.0.5 --- CMakeLists.txt | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d5c1d8..cd2805b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8) project(inform C) set(${PROJECT_NAME}_VERSION_MAJOR 0) -set(${PROJECT_NAME}_VERSION_MINOR 0.4) +set(${PROJECT_NAME}_VERSION_MINOR 0.5) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}) message(STATUS "inform version: ${${PROJECT_NAME}_VERSION}") diff --git a/appveyor.yml b/appveyor.yml index fe794d6..bdefe3b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.0.4.{build} +version: 0.0.5.{build} configuration: - Debug - Release