From 3979788911bb937f9ed5da53a630e8956dc217f4 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (h)" <j.wuttke@fz-juelich.de>
Date: Sun, 28 Jun 2020 14:30:20 +0200
Subject: [PATCH] provide generic functions min_value, max_value

---
 Core/Basics/Algorithms.h                      | 65 +++++++++++++++++++
 .../UnitTests/Core/Basics/MinMaxValueTest.cpp | 32 +++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 Core/Basics/Algorithms.h
 create mode 100644 Tests/UnitTests/Core/Basics/MinMaxValueTest.cpp

diff --git a/Core/Basics/Algorithms.h b/Core/Basics/Algorithms.h
new file mode 100644
index 00000000000..39c2f1480b3
--- /dev/null
+++ b/Core/Basics/Algorithms.h
@@ -0,0 +1,65 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Core/Basics/Algorithms
+//! @brief     Defines and implements namespace algo with some algorithms
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+// ************************************************************************** //
+
+#ifndef ALGORITHMS_H
+#define ALGORITHMS_H
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <cassert>
+
+//! Some additions to standard library algorithms.
+
+namespace algo {
+
+//! Returns the minimum value of function evaluate as applied to the elements of an iterator range.
+template<typename Evaluator, typename Iterator>
+double min_value(const Iterator& begin, const Iterator& end, const Evaluator& evaluate);
+
+//! Returns the maximum value of function evaluate as applied to the elements of an iterator range.
+template<typename Evaluator, typename Iterator>
+double max_value(const Iterator& begin, const Iterator& end, const Evaluator& evaluate);
+
+} // namespace algo
+
+
+// ************************************************************************** //
+// Implementation
+// ************************************************************************** //
+
+template<typename Evaluator, typename Iterator>
+double algo::min_value(const Iterator& begin, const Iterator& end, const Evaluator& evaluate)
+{
+    assert(begin != end);
+    double ret = evaluate(*begin);
+    Iterator it = begin;
+    while (++it != end)
+        ret = std::min(ret, evaluate(*it));
+    return ret;
+}
+
+template<typename Evaluator, typename Iterator>
+double algo::max_value(const Iterator& begin, const Iterator& end, const Evaluator& evaluate)
+{
+    assert(begin != end);
+    double ret = evaluate(*begin);
+    Iterator it = begin;
+    while (++it != end)
+        ret = std::max(ret, evaluate(*it));
+    return ret;
+}
+
+
+#endif // ALGORITHMS_H
diff --git a/Tests/UnitTests/Core/Basics/MinMaxValueTest.cpp b/Tests/UnitTests/Core/Basics/MinMaxValueTest.cpp
new file mode 100644
index 00000000000..4cc4591e8d7
--- /dev/null
+++ b/Tests/UnitTests/Core/Basics/MinMaxValueTest.cpp
@@ -0,0 +1,32 @@
+#include "Algorithms.h"
+#include "google_test.h"
+#include <cmath>
+
+class MinMaxValueTest : public ::testing::Test
+{
+};
+
+TEST_F(MinMaxValueTest, MinMaxValueAlmostEq)
+{
+    double val;
+    std::vector<double> A{0.};
+    std::vector<int> C {1, 2, 3};
+
+    val = algo::min_value(A.begin(), A.end(), [](const double& x)->double { return x; });
+    EXPECT_EQ(val, 0.);
+    val = algo::max_value(A.begin(), A.end(), [](const double& x)->double { return 2+x; });
+    EXPECT_NEAR(val, 2., 1e-15);
+
+    val = algo::min_value(C.begin(), C.end(), [](const int& i)->double { return i; });
+    EXPECT_EQ(val, 1);
+    val = algo::min_value(C.begin(), C.end(), [](const int& i)->double { return -i; });
+    EXPECT_EQ(val, -3);
+    val = algo::min_value(C.begin(), C.end(), [](const int& i)->double { return pow(i-2.1,2); });
+    EXPECT_NEAR(val, 0.01, 1e-13);
+    val = algo::max_value(C.begin(), C.end(), [](const int& i)->double { return i; });
+    EXPECT_EQ(val, 3);
+    val = algo::max_value(C.begin(), C.end(), [](const int& i)->double { return -i; });
+    EXPECT_EQ(val, -1);
+    val = algo::max_value(C.begin(), C.end(), [](const int& i)->double { return -pow(i-2.1,2); });
+    EXPECT_NEAR(val, -0.01, 1e-13);
+}
-- 
GitLab