From d49e1ad5e9ec120643936d6841996efe5b271d84 Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Thu, 8 Oct 2020 10:11:51 +0200
Subject: [PATCH] Redirect stats in VirtualRobot to SimoxUtility

---
 VirtualRobot/CMakeLists.txt                |   2 -
 VirtualRobot/math/statistics/BoxPlot.cpp   |  60 -------
 VirtualRobot/math/statistics/BoxPlot.h     |  31 +---
 VirtualRobot/math/statistics/Histogram.cpp | 177 ---------------------
 VirtualRobot/math/statistics/Histogram.h   |  92 +----------
 VirtualRobot/math/statistics/measures.cpp  |  78 ++-------
 6 files changed, 22 insertions(+), 418 deletions(-)
 delete mode 100644 VirtualRobot/math/statistics/BoxPlot.cpp
 delete mode 100644 VirtualRobot/math/statistics/Histogram.cpp

diff --git a/VirtualRobot/CMakeLists.txt b/VirtualRobot/CMakeLists.txt
index 8e32dec13..738f6bd2a 100644
--- a/VirtualRobot/CMakeLists.txt
+++ b/VirtualRobot/CMakeLists.txt
@@ -271,8 +271,6 @@ SET(SOURCES
     math/Triangle.cpp
     math/WeightedAverage.cpp
     math/statistics/measures.cpp
-    math/statistics/BoxPlot.cpp
-    math/statistics/Histogram.cpp
 
     MJCF/Document.cpp
     MJCF/elements/core/AnyElement.cpp
diff --git a/VirtualRobot/math/statistics/BoxPlot.cpp b/VirtualRobot/math/statistics/BoxPlot.cpp
deleted file mode 100644
index 08b5445a5..000000000
--- a/VirtualRobot/math/statistics/BoxPlot.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "BoxPlot.h"
-
-#include "measures.h"
-
-
-namespace math { namespace stat
-{
-
-
-BoxPlot::BoxPlot() = default;
-
-
-BoxPlot::BoxPlot(const std::vector<float>& values, bool isSorted, float whisk) :
-    whisk(whisk)
-{
-    set(values, isSorted);
-}
-
-void BoxPlot::set(const std::vector<float>& _values, bool isSorted)
-{
-    const std::vector<float>& values = isSorted ? _values : sorted(_values);
-
-    this->minimum = stat::min(values, true);
-    this->maximum = stat::max(values, true);
-
-    this->lowerQuartile = stat::lowerQuartile(values, true);
-    this->median = stat::median(values, true);
-    this->upperQuartile = stat::upperQuartile(values, true);
-
-    const float iqr = interquartileRange(lowerQuartile, upperQuartile);
-
-    this->minWhisker = lowerQuartile - whisk * iqr;
-    this->maxWhisker = upperQuartile + whisk * iqr;
-
-
-    // compute outliers and correct whiskers if necessary
-
-    {
-        auto it = values.begin();
-        for (; it != values.end() && *it < minWhisker; ++it)
-        {
-            outliers.push_back(*it);
-        }
-        minWhisker = (it != values.begin()) ? *it : minimum;
-    }
-
-    {
-        auto rit = values.rbegin();
-        for (; rit != values.rend() && *rit > maxWhisker; ++rit)
-        {
-            outliers.push_back(*rit);
-        }
-        maxWhisker = (rit != values.rbegin()) ? *rit : maximum;
-    }
-
-}
-
-
-
-}}
diff --git a/VirtualRobot/math/statistics/BoxPlot.h b/VirtualRobot/math/statistics/BoxPlot.h
index cd9089d6e..5c76ebe82 100644
--- a/VirtualRobot/math/statistics/BoxPlot.h
+++ b/VirtualRobot/math/statistics/BoxPlot.h
@@ -1,37 +1,10 @@
 #pragma once
 
-#include <vector>
+#include <SimoxUtility/math/statistics/BoxPlotStats.h>
 
 
 namespace math { namespace stat
 {
-
-    /**
-     * @brief Computes and stores statistical measures found in a box plot.
-     */
-    class BoxPlot
-    {
-    public:
-
-
-        BoxPlot();
-        BoxPlot(const std::vector<float>& values, bool isSorted = false, float whisk = 1.5);
-
-        void set(const std::vector<float>& values, bool isSorted = false);
-
-        float whisk = 1.5;
-
-        float minimum;
-        float minWhisker;
-        float lowerQuartile;
-        float median;
-        float upperQuartile;
-        float maxWhisker;
-        float maximum;
-
-        std::vector<float> outliers;
-
-    };
-
+    using BoxPlot = simox::math::BoxPlotStats;
 }}
 
diff --git a/VirtualRobot/math/statistics/Histogram.cpp b/VirtualRobot/math/statistics/Histogram.cpp
deleted file mode 100644
index 3ec3cd128..000000000
--- a/VirtualRobot/math/statistics/Histogram.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-#include "Histogram.h"
-
-#include <algorithm>
-
-
-namespace VirtualRobot
-{
-
-Histogram::Histogram()
-{}
-
-Histogram::Histogram(const std::vector<float>& data, std::size_t numBins)
-{
-    setMinMax(data);
-    resetBins(numBins);
-    insert(data);
-}
-
-Histogram::Histogram(const std::vector<float>& data, float min, float max, std::size_t numBins)
-{
-    setMinMax(min, max);
-    resetBins(numBins);
-    insert(data);
-}
-
-void Histogram::resetBins(std::size_t numBins)
-{
-    bins.assign(numBins, 0);
-}
-
-std::size_t Histogram::valueToIndex(float value) const
-{
-    // normalized = 0..1
-    float normalized = (value - min) / (max - min);
-    std::size_t index = static_cast<std::size_t>(normalized * getNumberOfBins());
-
-    // avoid out-of-bounce errors
-    // (if histogram is falsely used, this could lead to peaks at the edges)
-    return std::max(std::size_t(0), std::min(getNumberOfBins() - 1, index));
-}
-
-float Histogram::indexToValue(std::size_t index) const
-{
-    float normalized = static_cast<float>(index) / getNumberOfBins();
-    float value = normalized * (max - min) + min;
-    return value;
-}
-
-void Histogram::insert(float value)
-{
-    bins[valueToIndex(value)]++;
-}
-
-void Histogram::insert(const std::vector<float>& values)
-{
-    for (float v : values)
-    {
-        insert(v);
-    }
-}
-
-void Histogram::setMinMax(float min, float max)
-{
-    this->min = min;
-    this->max = max;
-}
-
-void Histogram::setMinMax(const std::vector<float>& data)
-{
-    float min = data.front();
-    float max = data.front();
-
-    for (float d : data)
-    {
-        min = std::min(min, d);
-        max = std::max(max, d);
-    }
-    setMinMax(min, max);
-}
-
-const std::vector<std::size_t>& Histogram::getBins() const
-{
-    return bins;
-}
-
-std::size_t Histogram::getNumberOfBins() const
-{
-    return bins.size();
-}
-
-float Histogram::getMin() const
-{
-    return min;
-}
-
-float Histogram::getMax() const
-{
-    return max;
-}
-
-std::size_t Histogram::getMinBinIndex() const
-{
-    return static_cast<std::size_t>(
-                std::distance(bins.begin(), std::min_element(bins.begin(), bins.end())));
-}
-
-float Histogram::getMinBinValue() const
-{
-    return indexToValue(getMaxBinIndex());
-}
-
-std::size_t Histogram::getMaxBinIndex() const
-{
-    return static_cast<std::size_t>(
-                std::distance(bins.begin(), std::max_element(bins.begin(), bins.end())));
-}
-
-float Histogram::getMaxBinValue() const
-{
-    return indexToValue(getMaxBinIndex());
-}
-
-void Histogram::applyMedianFilter(std::size_t size)
-{
-    std::vector<std::size_t> newBins(bins.size());
-    std::vector<std::size_t> neighborhood(2 * size + 1);
-
-    for (std::size_t index = 0; index < bins.size(); index++)
-    {
-        // handle cases at borders
-        std::size_t beginIndex = std::max(index - size, std::size_t(0));
-        std::size_t endIndex   = std::min(index + size + 1, bins.size());
-        std::size_t num = endIndex - beginIndex; // common case: num == 2*size+1
-
-        // example: index = 3, size = 2
-        // => beginIndex = 3-2 = 1, endIndex = 3+2+1 = 6, num = 6-1 = 5
-        // => neighborhood = [1, 6) == [1,5]
-
-        neighborhood.assign(bins.begin() + beginIndex, bins.begin() + endIndex);
-
-        std::sort(neighborhood.begin(), neighborhood.begin() + num);
-
-        newBins[index] = neighborhood[num / 2]; // == median
-        // (ignore cases where num is even, this only happens at the borders)
-    }
-
-    bins = newBins;
-}
-
-std::ostream& operator<<(std::ostream& os, const Histogram& histo)
-{
-    os << "Histogram:\n";
-    os << "min:;" << histo.min << ";max:;" << histo.max << ";\n";
-
-    os << "Index:;";
-    for (std::size_t index = 0; index < histo.bins.size(); index++)
-    {
-        os << index << ";";
-    }
-    os << "\n";
-    os << "Values:;";
-    for (std::size_t index = 0; index < histo.bins.size(); index++)
-    {
-        os << histo.indexToValue(index) << ";";
-    }
-    os << "\n";
-    os << "Counts:;";
-    for (std::size_t index = 0; index < histo.bins.size(); index++)
-    {
-        os << histo.bins[index] << ";";
-    }
-    os << "\n";
-
-    return os;
-}
-
-}
diff --git a/VirtualRobot/math/statistics/Histogram.h b/VirtualRobot/math/statistics/Histogram.h
index 9ecdc0162..8a369ffd8 100644
--- a/VirtualRobot/math/statistics/Histogram.h
+++ b/VirtualRobot/math/statistics/Histogram.h
@@ -1,98 +1,14 @@
 #pragma once
 
-#include <vector>
-#include <ostream>
+#include <SimoxUtility/math/statistics/Histogram.h>
 
 
 namespace VirtualRobot
 {
 
-    /**
-     * @brief Histogram for one-dimensional float data.
-     */
-    class Histogram
+    namespace math { namespace stat
     {
-    public:
-
-        /// No initialization constructor.
-        Histogram();
-
-        /// Construct with the given data.
-        /// Minimum and maximum are derived automatically.
-        Histogram(const std::vector<float>& data, std::size_t numBins = 128);
-
-        /// Construct with the given data and given limits.
-        Histogram(const std::vector<float>& data, float min, float max, std::size_t numBins = 128);
-
-
-        /// Set the number of bins and set them to 0.
-        void resetBins(std::size_t numBins);
-
-        /// Insert the given value into the histogram.
-        void insert(float value);
-        /// Inserts the given values into the histogram.
-        void insert(const std::vector<float>& value);
-
-        /// Set the limits.
-        void setMinMax(float min, float max);
-        /// Set the limits from the given data.
-        void setMinMax(const std::vector<float>& data);
-
-
-        /// Get the bins.
-        const std::vector<std::size_t>& getBins() const;
-
-        /// Get the number of bins.
-        std::size_t getNumberOfBins() const;
-
-        ///  Transfer the given value to its corresponding bin index.
-        std::size_t valueToIndex(float value) const;
-        /// Get the value at the center of the bin with the given index.
-        float indexToValue(std::size_t index) const;
-
-        /// Get the minimum, i.e. the lower limit.
-        float getMin() const;
-        /// Get the maximum, i.e. the upper limit.
-        float getMax() const;
-
-        /// Return the index of the bin containing the fewest data points.
-        std::size_t getMinBinIndex() const;
-        /// Returns the corresponding value of the bin containing the fewest data points.
-        float getMinBinValue() const;
-
-        /// Return the index of the bin containing the most data points.
-        std::size_t getMaxBinIndex() const;
-        /// Returns the corresponding value of the bin containing the most data points.
-        float getMaxBinValue() const;
-
-
-        /**
-         * @brief Applies a median filter to the histogram bins.
-         *
-         * The size specifies the number of neighours (in each direction)
-         * considered.
-         * That is, if k = size, 2k+1 values are considered for each point
-         * (k neighbours in each direction).
-         *
-         * @param size the size of the neighbourhood (in each direction)
-         */
-        void applyMedianFilter(std::size_t size = 2);
-
-
-        /// Streams a CVS-like description of the histogram containing the bin data.
-        friend std::ostream& operator<<(std::ostream& os, const Histogram& histo);
-
-
-    private:
-
-        /// The minimum mapped value.
-        float min;
-        /// The maximum mapped value.
-        float max;
-
-        /// The bins.
-        std::vector<std::size_t> bins;
-
-    };
+        using Histogram = simox::math::Histogram;
+    }}
 
 }
diff --git a/VirtualRobot/math/statistics/measures.cpp b/VirtualRobot/math/statistics/measures.cpp
index 1430b7b22..73aa17070 100644
--- a/VirtualRobot/math/statistics/measures.cpp
+++ b/VirtualRobot/math/statistics/measures.cpp
@@ -1,120 +1,74 @@
 #include "measures.h"
 
-#include <algorithm>
-#include <cmath>
-#include <stdexcept>
+#include <SimoxUtility/math/statistics/measures.h>
 
 
 namespace math { namespace stat
 {
 
-static void checkNotEmpty(const std::vector<float>& values)
-{
-    if (values.empty())
-        throw std::range_error("Given values are empty.");
-}
-
 void sort(std::vector<float>& values)
 {
-    std::sort(values.begin(), values.end());
+    simox::math::sort(values);
 }
 
 std::vector<float> sorted(const std::vector<float>& values)
 {
-    std::vector<float> s = values;
-    std::sort(s.begin(), s.end());
-    return s;
+    return simox::math::sorted(values);
 }
 
 float min(const std::vector<float>& values, bool isSorted)
 {
-    checkNotEmpty(values);
-    return isSorted ? values.front() : *std::min_element(values.begin(), values.end());
+    return simox::math::min(values, isSorted);
 }
 
 float max(const std::vector<float>& values, bool isSorted)
 {
-    checkNotEmpty(values);
-    return isSorted ? values.back() : *std::max_element(values.begin(), values.end());
+    return simox::math::max(values, isSorted);
 }
 
 float mean(const std::vector<float>& values)
 {
-    checkNotEmpty(values);
-
-    float sum = 0;
-    for (float v : values)
-    {
-        sum += v;
-    }
-    return sum / values.size();
+    return simox::math::mean(values);
 }
 
 float stddev(const std::vector<float>& values)
 {
-    return stddev(values, mean(values));
+    return simox::math::stddev(values);
 }
 
 float stddev(const std::vector<float>& values, float mean)
 {
-    checkNotEmpty(values);
-    float sum = 0;
-    for (float v : values)
-    {
-        float diff = v - mean;
-        sum += diff * diff;
-    }
-    float variance = sum / (values.size() - 1);
-    return std::sqrt(variance);
+    return simox::math::stddev(values, mean);
 }
 
-float quantile(const std::vector<float>& _values, float p, bool isSorted)
+float quantile(const std::vector<float>& values, float p, bool isSorted)
 {
-    checkNotEmpty(_values);
-    const std::vector<float>& values = isSorted ? _values : sorted(_values);
-
-    float location = p < 1 ? p * values.size() : values.size() - 1;
-
-    std::size_t floor = static_cast<std::size_t>(std::floor(location));
-    std::size_t ceil = static_cast<std::size_t>(std::ceil(location));
-
-    if (floor == ceil)
-    {
-        return values.at(floor);
-    }
-    else
-    {
-        float t = location - floor;
-        return (1 - t) * values.at(floor) + t * values.at(ceil);
-    }
+    return simox::math::quantile(values, p, isSorted);
 }
 
 float lowerQuartile(const std::vector<float>& values, bool isSorted)
 {
-    return quantile(values, .25, isSorted);
+    return simox::math::lower_quartile(values, isSorted);
 }
 
 float median(const std::vector<float>& values, bool isSorted)
 {
-    return quantile(values, .5, isSorted);
+    return simox::math::median(values, isSorted);
 }
 
 float upperQuartile(const std::vector<float>& values, bool isSorted)
 {
-    return quantile(values, .75, isSorted);
+    return simox::math::upper_quartile(values, isSorted);
 }
 
-float interquartileRange(const std::vector<float>& _values, bool isSorted)
+float interquartileRange(const std::vector<float>& values, bool isSorted)
 {
-    checkNotEmpty(_values);
-
-    const std::vector<float>& values = isSorted ? _values : sorted(_values);
-    return interquartileRange(lowerQuartile(values, true), upperQuartile(values, true));
+    return simox::math::interquartile_range(values, isSorted);
 }
 
 float interquartileRange(float lowerQuartile, float upperQuartile)
 {
-    return upperQuartile - lowerQuartile;
+    return simox::math::interquartile_range(lowerQuartile, upperQuartile);
 }
 
 
-- 
GitLab