From ebcb55409b6984272c2c9874595ea00fc792df9d Mon Sep 17 00:00:00 2001
From: phesch <ulila@student.kit.edu>
Date: Mon, 23 May 2022 23:07:42 +0200
Subject: [PATCH] Add memory implementation for pred. engine support

---
 .../RobotAPI/libraries/armem/CMakeLists.txt   |  1 +
 .../armem/core/base/CoreSegmentBase.h         | 22 ++++--
 .../libraries/armem/core/base/MemoryBase.h    | 12 ++-
 .../armem/core/base/ProviderSegmentBase.h     | 48 ++++++++++--
 .../armem/core/base/detail/Predictive.h       | 73 +++++++++++++++++++
 .../armem/server/MemoryToIceAdapter.cpp       | 32 ++++++++
 .../armem/server/MemoryToIceAdapter.h         |  3 +
 .../server/plugins/ReadWritePluginUser.cpp    |  2 +-
 .../server/segment/SpecializedCoreSegment.cpp | 12 ++-
 .../server/segment/SpecializedCoreSegment.h   |  6 +-
 .../segment/SpecializedProviderSegment.cpp    | 29 ++++++--
 .../segment/SpecializedProviderSegment.h      |  7 +-
 12 files changed, 218 insertions(+), 29 deletions(-)
 create mode 100644 source/RobotAPI/libraries/armem/core/base/detail/Predictive.h

diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index cff3ea8a1..8dba8b8e7 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -106,6 +106,7 @@ set(LIB_HEADERS
     core/base/detail/iteration_mixins.h
     core/base/detail/lookup_mixins.h
     core/base/detail/negative_index_semantics.h
+    core/base/detail/Predictive.h
 
     core/base/CoreSegmentBase.h
     core/base/EntityBase.h
diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
index 8f158a3fe..56526eb1c 100644
--- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
@@ -8,6 +8,7 @@
 #include "detail/MemoryContainerBase.h"
 #include "detail/iteration_mixins.h"
 #include "detail/lookup_mixins.h"
+#include "detail/Predictive.h"
 
 #include <ArmarXCore/core/logging/Logging.h>
 
@@ -21,6 +22,7 @@ namespace armarx::armem::base
     class CoreSegmentBase :
         public detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived>
         , public detail::AronTyped
+        , public detail::Predictive<_Derived>
         , public detail::ForEachEntityInstanceMixin<_Derived>
         , public detail::ForEachEntitySnapshotMixin<_Derived>
         , public detail::ForEachEntityMixin<_Derived>
@@ -66,17 +68,23 @@ namespace armarx::armem::base
         CoreSegmentBase()
         {
         }
-        explicit CoreSegmentBase(const std::string& name, aron::type::ObjectPtr aronType = nullptr) :
-            CoreSegmentBase(name, MemoryID(), aronType)
+        explicit CoreSegmentBase(const std::string& name,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            CoreSegmentBase(name, MemoryID(), aronType, predictionEngines)
         {
         }
-        explicit CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::type::ObjectPtr aronType = nullptr) :
-            CoreSegmentBase(parentID.withCoreSegmentName(name), aronType)
+        explicit CoreSegmentBase(const std::string& name,
+                                 const MemoryID& parentID,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            CoreSegmentBase(parentID.withCoreSegmentName(name), aronType, predictionEngines)
         {
         }
-        explicit CoreSegmentBase(const MemoryID& id, aron::type::ObjectPtr aronType = nullptr) :
-            Base(id),
-            AronTyped(aronType)
+        explicit CoreSegmentBase(const MemoryID& id,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            Base(id), AronTyped(aronType), detail::Predictive<_Derived>(predictionEngines)
         {
         }
 
diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
index 0bb30f689..991cc609e 100644
--- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
@@ -7,6 +7,7 @@
 #include "detail/MemoryContainerBase.h"
 #include "detail/iteration_mixins.h"
 #include "detail/lookup_mixins.h"
+#include "detail/Predictive.h"
 
 
 namespace armarx::armem::base
@@ -18,6 +19,7 @@ namespace armarx::armem::base
     template <class _CoreSegmentT, class _Derived>
     class MemoryBase :
         public detail::MemoryContainerBase<std::map<std::string, _CoreSegmentT>, _Derived>
+        , public detail::Predictive<_Derived>
         , public detail::ForEachEntityInstanceMixin<_Derived>
         , public detail::ForEachEntitySnapshotMixin<_Derived>
         , public detail::ForEachEntityMixin<_Derived>
@@ -67,12 +69,14 @@ namespace armarx::armem::base
         MemoryBase()
         {
         }
-        explicit MemoryBase(const std::string& name) :
-            MemoryBase(MemoryID().withMemoryName(name))
+        explicit MemoryBase(const std::string& name,
+                            const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            MemoryBase(MemoryID().withMemoryName(name), predictionEngines)
         {
         }
-        explicit MemoryBase(const MemoryID& id) :
-            Base(id)
+        explicit MemoryBase(const MemoryID& id,
+                            const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            Base(id), detail::Predictive<_Derived>(predictionEngines)
         {
         }
 
diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
index 7deccd836..ffa8bbda1 100644
--- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
@@ -3,6 +3,8 @@
 #include <map>
 #include <string>
 
+#include <RobotAPI/interface/armem/prediction.h>
+
 #include "EntityBase.h"
 #include "detail/AronTyped.h"
 #include "detail/MemoryContainerBase.h"
@@ -53,6 +55,9 @@ namespace armarx::armem::base
             {}
         };
 
+    private:
+        
+        prediction::data::PredictionEngineSeq supportedEngines;
 
     public:
 
@@ -60,17 +65,26 @@ namespace armarx::armem::base
         {
         }
 
-        explicit ProviderSegmentBase(const std::string& name, aron::type::ObjectPtr aronType = nullptr) :
-            ProviderSegmentBase(name, MemoryID(), aronType)
+        explicit ProviderSegmentBase(
+            const std::string& name,
+            aron::type::ObjectPtr aronType = nullptr,
+            const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            ProviderSegmentBase(name, MemoryID(), aronType, predictionEngines)
         {
         }
-        explicit ProviderSegmentBase(const std::string& name, const MemoryID parentID, aron::type::ObjectPtr aronType = nullptr) :
-            ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType)
+        explicit ProviderSegmentBase(
+            const std::string& name,
+            const MemoryID parentID,
+            aron::type::ObjectPtr aronType = nullptr,
+            const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType, predictionEngines)
         {
         }
-        explicit ProviderSegmentBase(const MemoryID id, aron::type::ObjectPtr aronType = nullptr) :
-            Base(id),
-            AronTyped(aronType)
+        explicit ProviderSegmentBase(
+            const MemoryID id,
+            aron::type::ObjectPtr aronType = nullptr,
+            const prediction::data::PredictionEngineSeq& predictionEngines = {}) :
+            Base(id), AronTyped(aronType), supportedEngines(predictionEngines)
         {
         }
 
@@ -274,6 +288,26 @@ namespace armarx::armem::base
             return child;
         }
 
+        // PREDICTION ENGINES
+        prediction::data::PredictionEngineSeq&
+        predictionEngines()
+        {
+            return supportedEngines;
+        }
+
+        std::map<MemoryID, prediction::data::PredictionEngineSeq>
+        getAllPredictionEngines()
+        {
+            auto engines = predictionEngines();
+            if (engines.empty())
+            {
+                return {};
+            }
+            // Type inference fails when using initializer lists here, not sure why.
+            std::map<MemoryID, prediction::data::PredictionEngineSeq> engineMap;
+            engineMap.emplace(this->id(), engines);
+            return engineMap;
+        }
 
         // MISC
 
diff --git a/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h b/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h
new file mode 100644
index 000000000..096ba6429
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::armem::core::base::detail
+ * @author     phesch ( phesch at student dot kit dot edu )
+ * @date       2022
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <RobotAPI/interface/armem/prediction.h>
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
+
+#include "derived.h"
+
+namespace armarx::armem::base::detail
+{
+    /**
+     * @brief Something that supports a set of prediction engines.
+     */
+    template <class DerivedT>
+    class Predictive
+    {
+    public:
+        explicit Predictive(const prediction::data::PredictionEngineSeq& engines = {}) :
+            supportedEngines(engines)
+        {
+        }
+
+        prediction::data::PredictionEngineSeq&
+        predictionEngines()
+        {
+            return supportedEngines;
+        }
+
+        std::map<MemoryID, prediction::data::PredictionEngineSeq>
+        getAllPredictionEngines()
+        {
+            std::map<MemoryID, prediction::data::PredictionEngineSeq> engines;
+            auto& derivedContainer = derived<DerivedT>(this);
+            derivedContainer.forEachChild(
+                [&engines](auto& child)
+                {
+                    auto childMap = child.getAllPredictionEngines();
+                    engines.insert(childMap.begin(), childMap.end());
+                });
+            auto ownEngines = derivedContainer.predictionEngines();
+            if (!ownEngines.empty())
+            {
+                engines.emplace(derivedContainer.id(), derivedContainer.predictionEngines());
+            }
+
+            return engines;
+        }
+
+    protected:
+        prediction::data::PredictionEngineSeq supportedEngines;
+    };
+} // namespace armarx::armem::base::detail
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
index a838e9e0f..930c1c15d 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
@@ -360,4 +360,36 @@ namespace armarx::armem::server
         return output;
     }
 
+    // PREDICTION
+    prediction::data::EngineSupportMap MemoryToIceAdapter::getAvailableEngines()
+    {
+        prediction::data::EngineSupportMap result;
+        auto wmMap = workingMemory->getAllPredictionEngines();
+        for (const auto& [memoryID, engines] : wmMap)
+        {
+            result.emplace(armarx::toIce<data::MemoryID>(memoryID), engines);
+        }
+
+        auto ltmMap = workingMemory->getAllPredictionEngines();
+        for (const auto& [memoryID, engines] : ltmMap)
+        {
+            auto dtoID = armarx::toIce<data::MemoryID>(memoryID);
+            auto entryIter = result.find(dtoID);
+            if (entryIter == result.end())
+            {
+                result.emplace(armarx::toIce<data::MemoryID>(memoryID), engines);
+            }
+            else
+            {
+                // Merge LTM-supported engines with WM-supported engines, removing duplicates
+                std::set<prediction::data::PredictionEngine> engineSet;
+                engineSet.insert(entryIter->second.begin(), entryIter->second.end());
+                engineSet.insert(engines.begin(), engines.end());
+                entryIter->second.assign(engineSet.begin(), engineSet.end());
+            }
+        }
+
+        return result;
+    }
+
 }
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
index 33e788ff5..96c1e822d 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
@@ -52,6 +52,9 @@ namespace armarx::armem::server
         // LTM STORING
         data::StoreResult store(const armem::data::StoreInput& input);
 
+        // PREDICTION
+        prediction::data::EngineSupportMap getAvailableEngines();
+
     public:
 
         server::wm::Memory* workingMemory;
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
index f690cbaee..53027b903 100644
--- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
@@ -137,7 +137,7 @@ namespace armarx::armem::server::plugins
     armem::prediction::data::EngineSupportMap
     ReadWritePluginUser::getAvailableEngines()
     {
-        return {};
+        return iceAdapter().getAvailableEngines();
     }
 
     armem::prediction::data::PredictionResultSeq
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
index b0afa2826..e33009bbb 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
@@ -14,9 +14,11 @@ namespace armarx::armem::server::segment
             armem::server::MemoryToIceAdapter& iceMemory,
             const std::string& defaultCoreSegmentName,
             aron::type::ObjectPtr coreSegmentAronType,
-            int defaultMaxHistorySize) :
+            int defaultMaxHistorySize,
+            const prediction::data::PredictionEngineSeq& predictionEngines) :
         Base(iceMemory),
         aronType(coreSegmentAronType),
+        predictionEngines(predictionEngines),
         properties({defaultCoreSegmentName, defaultMaxHistorySize})
     {
         Logging::setTag("armarx::armem::SpecializedCoreSegment");
@@ -60,6 +62,7 @@ namespace armarx::armem::server::segment
 
             segmentPtr->aronType() = aronType;
             segmentPtr->setMaxHistorySize(properties.maxHistorySize);
+            segmentPtr->predictionEngines() = predictionEngines;
         }
     }
 
@@ -80,6 +83,13 @@ namespace armarx::armem::server::segment
         this->aronType = aronType;
     }
 
+    void
+    SpecializedCoreSegment::setPredictionEngines(
+        const prediction::data::PredictionEngineSeq& predictionEngines)
+    {
+        this->predictionEngines = predictionEngines;
+    }
+
     wm::CoreSegment& SpecializedCoreSegment::getCoreSegment()
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
index d94fa1aed..059d9c7bc 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
@@ -27,7 +27,8 @@ namespace armarx::armem::server::segment
                 MemoryToIceAdapter& iceMemory,
                 const std::string& defaultCoreSegmentName = "",
                 aron::type::ObjectPtr coreSegmentAronType = nullptr,
-                int defaultMaxHistorySize = -1);
+                int defaultMaxHistorySize = -1,
+                const prediction::data::PredictionEngineSeq& predictionEngines = {});
 
             virtual ~SpecializedCoreSegment() override;
 
@@ -43,6 +44,8 @@ namespace armarx::armem::server::segment
             void setDefaultCoreSegmentName(const std::string& coreSegmentName);
             void setDefaultMaxHistorySize(int64_t maxHistorySize);
             void setAronType(aron::type::ObjectPtr aronType);
+            void
+            setPredictionEngines(const prediction::data::PredictionEngineSeq& predictionEngines);
 
             wm::CoreSegment& getCoreSegment();
             const wm::CoreSegment& getCoreSegment() const;
@@ -51,6 +54,7 @@ namespace armarx::armem::server::segment
         public:
 
             aron::type::ObjectPtr aronType;
+            prediction::data::PredictionEngineSeq predictionEngines;
 
             struct Properties
             {
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
index 747b2bec8..541f5ce07 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
@@ -10,15 +10,22 @@
 namespace armarx::armem::server::segment
 {
     SpecializedProviderSegment::SpecializedProviderSegment(
-            armem::server::MemoryToIceAdapter& iceMemory,
-            const std::string& defaultProviderSegmentName,
-            const std::string& defaultCoreSegmentName,
-            aron::type::ObjectPtr providerSegmentAronType,
-            aron::type::ObjectPtr coreSegmentAronType,
-            int defaultMaxHistorySize) :
+        armem::server::MemoryToIceAdapter& iceMemory,
+        const std::string& defaultProviderSegmentName,
+        const std::string& defaultCoreSegmentName,
+        aron::type::ObjectPtr providerSegmentAronType,
+        aron::type::ObjectPtr coreSegmentAronType,
+        int defaultMaxHistorySize,
+        const prediction::data::PredictionEngineSeq& providerSegmentPredictionEngines,
+        const prediction::data::PredictionEngineSeq& coreSegmentPredictionEngines) :
         Base(iceMemory),
         aronType(providerSegmentAronType),
-        coreSegment(iceMemory, defaultCoreSegmentName, coreSegmentAronType),
+        predictionEngines(providerSegmentPredictionEngines),
+        coreSegment(iceMemory,
+                    defaultCoreSegmentName,
+                    coreSegmentAronType,
+                    -1,
+                    providerSegmentPredictionEngines),
         properties({defaultProviderSegmentName, defaultMaxHistorySize})
     {
         Logging::setTag("armarx::armem::SpecializedProviderSegment");
@@ -65,6 +72,7 @@ namespace armarx::armem::server::segment
 
             segmentPtr->aronType() = aronType;
             segmentPtr->setMaxHistorySize(properties.maxHistorySize);
+            segmentPtr->predictionEngines() = predictionEngines;
         }
     }
 
@@ -85,6 +93,13 @@ namespace armarx::armem::server::segment
         this->aronType = aronType;
     }
 
+    void
+    SpecializedProviderSegment::setPredictionEngines(
+        const prediction::data::PredictionEngineSeq& predictionEngines)
+    {
+        this->predictionEngines = predictionEngines;
+    }
+
     wm::ProviderSegment& SpecializedProviderSegment::getProviderSegment()
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
index 44db000d1..f8ffa13c0 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
@@ -29,7 +29,9 @@ namespace armarx::armem::server::segment
                 const std::string& defaultCoreSegmentName = "",
                 aron::type::ObjectPtr providerSegmentAronType = nullptr,
                 aron::type::ObjectPtr coreSegmentAronType = nullptr,
-                int defaultMaxHistorySize = -1);
+                int defaultMaxHistorySize = -1,
+                const prediction::data::PredictionEngineSeq& providerSegmentPredictionEngines = {},
+                const prediction::data::PredictionEngineSeq& coreSegmentPredictionEngines = {});
 
             virtual ~SpecializedProviderSegment() override;
 
@@ -39,6 +41,8 @@ namespace armarx::armem::server::segment
             void setDefaultProviderSegmentName(const std::string& providerSegmentName);
             void setDefaultMaxHistorySize(int64_t maxHistorySize);
             void setAronType(aron::type::ObjectPtr aronType);
+            void
+            setPredictionEngines(const prediction::data::PredictionEngineSeq& predictionEngines);
 
             wm::ProviderSegment& getProviderSegment();
             const wm::ProviderSegment& getProviderSegment() const;
@@ -47,6 +51,7 @@ namespace armarx::armem::server::segment
         public:
 
             aron::type::ObjectPtr aronType;
+            prediction::data::PredictionEngineSeq predictionEngines;
             SpecializedCoreSegment coreSegment;
 
             struct Properties
-- 
GitLab