diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp index cd7e8b18230e38d21cf700f04c116cca830eaa14..d55a0407db9488bae4ca80cc401dcf8cc540f0b7 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp +++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp @@ -27,9 +27,9 @@ #include <SimoxUtility/algorithm/string.h> -#include <RobotAPI/libraries/armem/client/Prediction.h> #include <RobotAPI/libraries/armem/client/query/Builder.h> #include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> #include <RobotAPI/libraries/armem/core/ice_conversions.h> #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h> @@ -72,6 +72,9 @@ namespace armarx workingMemory().addCoreSegment("ExampleData", armem::example::ExampleData::ToAronType()); workingMemory().addCoreSegment("LinkedData", armem::example::LinkedData::ToAronType()); + // We support the "Latest" prediction engine for the entire memory. + workingMemory().addPredictionEngine({"Latest"}); + // For illustration purposes, we add more segments (without types). bool trim = true; p.core.defaultCoreSegments = simox::alg::split(p.core._defaultSegmentsStr, ",", trim); @@ -228,7 +231,7 @@ namespace armarx armem::prediction::data::PredictionResult ExampleMemory::predictSingle(const armem::prediction::data::PredictionRequest& request) { - armem::client::PredictionResult result; + armem::PredictionResult result; std::string engine = request.settings.predictionEngineID; if (engine.empty() || engine == "Latest") @@ -275,12 +278,6 @@ namespace armarx return result.toIce(); } - armem::prediction::data::EngineSupportMap - ExampleMemory::getAvailableEngines() - { - return {{armarx::toIce<armem::data::MemoryID>(workingMemory().id()), {{"Latest"}}}}; - } - // REMOTE GUI void ExampleMemory::createRemoteGuiTab() diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h index fa9c2b1eacc314bcb37de05f4f19039d9bcbd582..76e437bcb6f6db0e31c023eed4386831267c5fc2 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h +++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h @@ -76,8 +76,6 @@ namespace armarx armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests) override; - armem::prediction::data::EngineSupportMap getAvailableEngines() override; - protected: diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp index 02ac6e6aec08d86253f0512584a9921f8063bf9e..fe2a7471594c303e21ed0638bb1fa6f5e1635fa5 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp @@ -27,8 +27,8 @@ #include <RobotAPI/libraries/ArmarXObjects/aron_conversions.h> #include <RobotAPI/libraries/ArmarXObjects/ice_conversions.h> -#include <RobotAPI/libraries/armem/client/Prediction.h> #include <RobotAPI/libraries/armem/client/query.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> #include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h> @@ -231,8 +231,8 @@ namespace armarx::armem::server::obj std::vector<armem::prediction::data::PredictionResult> results; for (const auto& request : requests) { - auto boRequest = armarx::fromIce<armem::client::PredictionRequest>(request); - armem::client::PredictionResult result; + auto boRequest = armarx::fromIce<armem::PredictionRequest>(request); + armem::PredictionResult result; result.snapshotID = boRequest.snapshotID; if (armem::contains(workingMemory().id().withCoreSegmentName("Instance"), boRequest.snapshotID) && @@ -295,14 +295,6 @@ namespace armarx::armem::server::obj return results; } - armem::prediction::data::EngineSupportMap ObjectMemory::getAvailableEngines() - { - // TODO(phesch): Replace with generic code in Memory implementation - return {{armarx::toIce<armem::data::MemoryID>( - workingMemory().id().withCoreSegmentName("Instance")), - {{"Linear Position Regression"}}}}; - } - void ObjectMemory::createRemoteGuiTab() { using namespace armarx::RemoteGui::Client; diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h index 7067f42da1344fb4aa1936dfcafaa2b77f3df599..1a939eebff7c94f887b4d68f5d363c5f986e5194 100644 --- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h +++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h @@ -110,7 +110,6 @@ namespace armarx::armem::server::obj // Predictions armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests) override; - armem::prediction::data::EngineSupportMap getAvailableEngines() override; // Remote GUI void createRemoteGuiTab(); diff --git a/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice b/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice index ead5ad03b5edd7f1bbb39dd1c528376005c8b041..aeae3745854d595ba7799a399df43cf2e33922b7 100644 --- a/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice +++ b/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice @@ -18,7 +18,7 @@ module armarx predict(prediction::data::PredictionRequestSeq requests); /* Get a map from memory segments to the prediction engines they support. - * Best used with the armem::core::PrefixMap to easily retrieve + * Best used with the container_map operations to easily retrieve * the available engine selection for fully evaluated MemoryIDs. */ prediction::data::EngineSupportMap getAvailableEngines(); diff --git a/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp b/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp index 427868519c15f4f3c31342f980d3ee245f528a88..fc9dfe5081f69215398cd5c6eefaf7c8c1fbd705 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp +++ b/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp @@ -25,6 +25,7 @@ #include <SimoxUtility/math/pose/pose.h> #include <SimoxUtility/math/regression/linear.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include <ArmarXCore/core/ice_conversions/ice_conversions_templates.h> namespace armarx::objpose diff --git a/source/RobotAPI/libraries/ArmarXObjects/predictions.h b/source/RobotAPI/libraries/ArmarXObjects/predictions.h index d9b647f9dd81a1e04ff435a0e20c94368cdb89f4..03b3f7de2eb2267ba43c356c44988e374792c591 100644 --- a/source/RobotAPI/libraries/ArmarXObjects/predictions.h +++ b/source/RobotAPI/libraries/ArmarXObjects/predictions.h @@ -25,7 +25,6 @@ #include <RobotAPI/interface/objectpose/ObjectPoseStorageInterface.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectPose.h> -#include <RobotAPI/libraries/armem/client/Prediction.h> namespace armarx::objpose { diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index 237d90fa5c71d2ad987102a443c6438691079e9f..62da8840409c17d8968c34171120a230a379ef33 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -18,6 +18,7 @@ set(LIB_FILES core/MemoryID.cpp core/MemoryID_operators.cpp core/operations.cpp + core/Prediction.cpp core/SuccessHeader.cpp core/Time.cpp core/aron_conversions.cpp @@ -51,7 +52,6 @@ set(LIB_FILES client/MemoryNameSystem.cpp - client/Prediction.cpp client/Reader.cpp client/Writer.cpp @@ -82,10 +82,12 @@ set(LIB_HEADERS core/actions.h core/Commit.h + core/container_maps.h core/DataMode.h core/MemoryID.h core/MemoryID_operators.h core/operations.h + core/Prediction.h core/SuccessHeader.h core/Time.h core/aron_conversions.h @@ -105,6 +107,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 @@ -126,7 +129,6 @@ set(LIB_HEADERS client.h client/forward_declarations.h client/MemoryNameSystem.h - client/Prediction.h client/Reader.h client/Writer.h diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp index ce2d0cfcfa41bedc7f6cab56f45e79d959bc68da..9fb03536bbef6047d96baf6203893ad9cc9f78ed 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.cpp +++ b/source/RobotAPI/libraries/armem/client/Reader.cpp @@ -479,7 +479,7 @@ namespace armarx::armem::client return boResults; } - armem::prediction::data::EngineSupportMap + std::map<MemoryID, std::vector<PredictionEngine>> Reader::getAvailablePredictionEngines() const { if (!predictionPrx) @@ -499,13 +499,9 @@ namespace armarx::armem::client // Just leave engines empty in this case. } - //std::vector<PredictionEngine> boEngines; - //boEngines.reserve(engines.size()); - //for (const auto& engine : engines) - //{ - // boEngines.push_back(armarx::fromIce<PredictionEngine>(engine)); - //} + std::map<MemoryID, std::vector<PredictionEngine>> boMap; + armarx::fromIce(engines, boMap); - return engines; + return boMap; } } // namespace armarx::armem::client diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h index 34b3ce320182c7995412dc7e02b04c58fe1a0dfa..7ecb453c845524edce1a217c49db671efbf3c9e7 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.h +++ b/source/RobotAPI/libraries/armem/client/Reader.h @@ -9,10 +9,10 @@ #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h> #include <RobotAPI/interface/armem/server/StoringMemoryInterface.h> #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> #include "Query.h" -#include "Prediction.h" namespace armarx::armem::client @@ -178,15 +178,14 @@ namespace armarx::armem::client */ std::vector<PredictionResult> predict(const std::vector<PredictionRequest>& requests) const; - //TODO(phesch): Fix this interface with the proper type /** * @brief Get the list of prediction engines supported by the memory. * * The `predictionPrx` must not be null when calling this function. * - * @return the vector of supported prediction engines + * @return a map from memory containers to their supported engines */ - armem::prediction::data::EngineSupportMap getAvailablePredictionEngines() const; + std::map<MemoryID, std::vector<PredictionEngine>> getAvailablePredictionEngines() const; inline operator bool() const { diff --git a/source/RobotAPI/libraries/armem/client/Prediction.cpp b/source/RobotAPI/libraries/armem/core/Prediction.cpp similarity index 98% rename from source/RobotAPI/libraries/armem/client/Prediction.cpp rename to source/RobotAPI/libraries/armem/core/Prediction.cpp index dce9473bd58d557d3a37a511c7c257c65305bee8..9880d03a2f4e4c28e649e50f08a1f0b93ce52cb2 100644 --- a/source/RobotAPI/libraries/armem/client/Prediction.cpp +++ b/source/RobotAPI/libraries/armem/core/Prediction.cpp @@ -26,7 +26,7 @@ #include <RobotAPI/libraries/armem/core/ice_conversions.h> -namespace armarx::armem::client +namespace armarx::armem { PredictionEngine PredictionEngine::fromIce(const armem::prediction::data::PredictionEngine& ice) @@ -132,4 +132,4 @@ namespace armarx::armem::client result.prediction = aron::data::Dict::FromAronDictDTO(ice.prediction); } -} // namespace armarx::armem::client +} // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/client/Prediction.h b/source/RobotAPI/libraries/armem/core/Prediction.h similarity index 97% rename from source/RobotAPI/libraries/armem/client/Prediction.h rename to source/RobotAPI/libraries/armem/core/Prediction.h index 0e9ac30d5e6e797dd228ca6f313c6cdbed19bf5b..a8ec9ee52436b5b5d96c5c8013d058f8d6abc6e5 100644 --- a/source/RobotAPI/libraries/armem/client/Prediction.h +++ b/source/RobotAPI/libraries/armem/core/Prediction.h @@ -26,7 +26,7 @@ #include <RobotAPI/libraries/armem/core/MemoryID.h> #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -namespace armarx::armem::client +namespace armarx::armem { struct PredictionEngine @@ -83,4 +83,4 @@ namespace armarx::armem::client void toIce(armem::prediction::data::PredictionResult& ice, const PredictionResult& result); void fromIce(const armem::prediction::data::PredictionResult& ice, PredictionResult& result); -} // namespace armarx::armem::client +} // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 7fe2f81f4eed5ac478ecb974cf0c09e73de874b3..8c1ed546b3d8699ea4eed9225f055323510745d6 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::PredictiveContainer<_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 std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& predictionEngines = {}) : + Base(id), AronTyped(aronType), detail::PredictiveContainer<_Derived>(predictionEngines) { } @@ -276,15 +284,20 @@ namespace armarx::armem::base } /** - * @brief Add an empty provider segment with the given name and optional provider segment type. + * @brief Add an empty provider segment with the given name, + * optional provider segment type and prediction engines. * @param name The segment name. * @param providerSegmentType The provider type. If nullptr, the core segment type is used. + * @param predictionEngines The prediction engines supported by the provider segment (optional). * @return The added provider segment. */ - ProviderSegmentT& addProviderSegment(const std::string& name, aron::type::ObjectPtr providerSegmentType = nullptr) + ProviderSegmentT& + addProviderSegment(const std::string& name, + aron::type::ObjectPtr providerSegmentType = nullptr, + const std::vector<PredictionEngine>& predictionEngines = {}) { aron::type::ObjectPtr type = providerSegmentType ? providerSegmentType : this->aronType(); - return this->_derived().addProviderSegment(name, name, type); + return this->_derived().addProviderSegment(name, name, type, predictionEngines); } /// Copy and insert a provider segment. diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index 6a9ce75b7d9e62ae182b7da16eba733a210b279a..b6497f8ff421feb16b7f7b07ede1f2d3e57c2266 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::PredictiveContainer<_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 std::vector<PredictionEngine>& predictionEngines = {}) : + MemoryBase(MemoryID().withMemoryName(name), predictionEngines) { } - explicit MemoryBase(const MemoryID& id) : - Base(id) + explicit MemoryBase(const MemoryID& id, + const std::vector<PredictionEngine>& predictionEngines = {}) : + Base(id), detail::PredictiveContainer<_Derived>(predictionEngines) { } @@ -215,15 +219,18 @@ namespace armarx::armem::base // MODIFICATION /** - * @brief Add an empty core segment with the given name. + * @brief Add an empty core segment with the given name, type and prediction engines. * @param name The core segment name. * @param coreSegmentType The core segment type (optional). + * @param predictionEngines The prediction engines supported by the core segment (optional). * @return The added core segment. */ - CoreSegmentT& addCoreSegment( - const std::string& name, aron::type::ObjectPtr coreSegmentType = nullptr) + CoreSegmentT& + addCoreSegment(const std::string& name, + aron::type::ObjectPtr coreSegmentType = nullptr, + const std::vector<PredictionEngine>& predictionEngines = {}) { - return this->_derived().addCoreSegment(name, name, coreSegmentType); + return this->_derived().addCoreSegment(name, name, coreSegmentType, predictionEngines); } /// Copy and insert a core segment. diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h index 02f47105d2a8591e8953179edb00fbe81fffbc3e..6cd70391660d6f61fe073837052a9b06fb57da1c 100644 --- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h @@ -3,8 +3,11 @@ #include <map> #include <string> +#include <RobotAPI/libraries/armem/core/Prediction.h> + #include "EntityBase.h" #include "detail/AronTyped.h" +#include "detail/Predictive.h" #include "detail/MemoryContainerBase.h" #include "detail/iteration_mixins.h" #include "detail/lookup_mixins.h" @@ -20,6 +23,7 @@ namespace armarx::armem::base class ProviderSegmentBase : public detail::MemoryContainerBase<std::map<std::string, _EntityT>, _Derived> , public detail::AronTyped + , public detail::Predictive<_Derived> , public detail::ForEachEntityInstanceMixin<_Derived> , public detail::ForEachEntitySnapshotMixin<_Derived> , public detail::GetFindInstanceMixin<_Derived> @@ -60,17 +64,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 std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& predictionEngines = {}) : + Base(id), AronTyped(aronType), detail::Predictive<_Derived>(predictionEngines) { } 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 0000000000000000000000000000000000000000..ea9ec0dde71cbdb19c6bebe0e160bfbcea8c8155 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h @@ -0,0 +1,125 @@ +/* + * 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/libraries/armem/core/MemoryID.h> +#include <RobotAPI/libraries/armem/core/Prediction.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 std::vector<PredictionEngine>& engines = {}) : + _predictionEngines(engines) + { + } + + const std::vector<PredictionEngine>& + predictionEngines() const + { + return _predictionEngines; + } + + void addPredictionEngine(const PredictionEngine& engine) + { + _predictionEngines.push_back(engine); + } + + void setPredictionEngines(const std::vector<PredictionEngine>& engines) + { + this->_predictionEngines = engines; + } + + std::map<MemoryID, std::vector<PredictionEngine>> + getAllPredictionEngines() const + { + std::map<MemoryID, std::vector<PredictionEngine>> engines; + + // Add own engines. + const auto& derivedThis = derived<DerivedT>(this); + const auto& ownEngines = derivedThis.predictionEngines(); + if (not ownEngines.empty()) + { + engines.emplace(derivedThis.id(), derivedThis.predictionEngines()); + } + + return engines; + } + + + private: + + std::vector<PredictionEngine> _predictionEngines; + + }; + + + /** + * @brief Something that supports a set of prediction engines. + */ + template <class DerivedT> + class PredictiveContainer : public Predictive<DerivedT> + { + public: + + using Predictive<DerivedT>::Predictive; + + + std::map<MemoryID, std::vector<PredictionEngine>> + getAllPredictionEngines() const + { + std::map<MemoryID, std::vector<PredictionEngine>> engines; + + // Collect engines of children. + const auto& derivedThis = derived<DerivedT>(this); + derivedThis.forEachChild( + [&engines](const auto& child) + { + const auto& childMap = child.getAllPredictionEngines(); + engines.insert(childMap.begin(), childMap.end()); + }); + + // Add own engines. + const auto& ownEngines = derivedThis.predictionEngines(); + if (not ownEngines.empty()) + { + engines.emplace(derivedThis.id(), derivedThis.predictionEngines()); + } + + return engines; + } + + }; + + +} // namespace armarx::armem::base::detail diff --git a/source/RobotAPI/libraries/armem/core/container_maps.h b/source/RobotAPI/libraries/armem/core/container_maps.h new file mode 100644 index 0000000000000000000000000000000000000000..625c92bb02548c66b96c18e349bbe23acc0385ef --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/container_maps.h @@ -0,0 +1,232 @@ +/* + * 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/>. + * + * @author phesch ( ulila 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 <map> +#include <optional> +#include <tuple> + +#include <RobotAPI/libraries/armem/core/MemoryID.h> + +namespace armarx::armem +{ + + namespace detail + { + template <class KeyT, class ValueT> + struct MapRef + { + KeyT* key; + ValueT* value; + }; + + + + /** + * @brief Get the entry in the map for which the returned key is the longest prefix + * of the given key among the keys in the map. + * + * `prefixFunc` is used to successively calculate the prefixes of the given key. + * It must be pure and return an empty optional when there is no shorter + * prefix of the given key (for strings, this would be the case when passed the empty string). + * + * @param keyValMap the map that contains the key-value-pairs to search + * @param prefixFunc the function that returns the longest non-identical prefix of the key + * @param key the key to calculate the prefixes of + * + * @return The iterator pointing to the found entry, or `keyValMap.end()`. + */ + template <typename KeyT, typename ValueT> + typename std::map<KeyT, ValueT>::const_iterator + findEntryWithLongestPrefix(const std::map<KeyT, ValueT>& keyValMap, + const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, + const KeyT& key) + { + std::optional<KeyT> curKey = key; + + typename std::map<KeyT, ValueT>::const_iterator result = keyValMap.end(); + do + { + auto iterator = keyValMap.find(curKey.value()); + if (iterator != keyValMap.end()) + { + result = iterator; + } + else + { + curKey = prefixFunc(curKey.value()); + } + } + while (result == keyValMap.end() and curKey.has_value()); + + return result; + } + + + /** + * @brief Accumulate all the values in a map for which the keys are prefixes of the given key. + * + * `AccumulateT` is a type that the values will be accumulated into using `accumulateFunc`. + * `accumulateFunc` is a function that modifies the given accumulator + * (by, e.g., adding the given value to it). + * + * The values are accumulated in order from the longest key to the shortest. + * + * @see `getWithLongestPrefix` for a description of `prefixFunc` + * @param keyValMap the map that contains the key-value-pairs to search + * @param prefixFunc the function that returns the longest non-identical prefix of the key + * @param accumulateFunc the function that accumulates the values in the accumulator + * @param key the key to calculate the prefixes of + */ + template <typename KeyT, typename ValueT, typename AccumulateT> + AccumulateT + accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, + const std::function<void(AccumulateT&, const ValueT&)> accumulateFunc, + const KeyT& key) + { + std::optional<KeyT> curKey = key; + AccumulateT values; + do + { + const auto nextEntry = + findEntryWithLongestPrefix<KeyT, ValueT>(keyValMap, prefixFunc, curKey.value()); + if (nextEntry != keyValMap.end()) + { + curKey = prefixFunc(nextEntry->first); + accumulateFunc(values, nextEntry->second); + } + else + { + curKey.reset(); + } + } + while (curKey.has_value()); + + return values; + } + + /** + * @brief Collect all the values in a map for which the keys are prefixes of the given key. + * + * This is a specialization of the general `accumulateFromPrefixes` + * for collecting single values into a vector. + * + * @see `accumulateFromPrefixes` for a detailed description + * @param keyValMap the map that contains the key-value-pairs to search + * @param prefixFunc the function that returns the longest non-identical prefix of the key + * @param key the key to calculate the prefixes of + */ + template <typename KeyT, typename ValueT> + std::vector<ValueT> + accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, + const KeyT& key) + { + return accumulateFromPrefixes<KeyT, ValueT, std::vector<ValueT>>( + keyValMap, + prefixFunc, + [](std::vector<ValueT>& values, const ValueT& val) { values.push_back(val); }, + key); + } + + /** + * @brief Collect all the values in a map for which the keys are prefixes of the given key. + * + * This is a specialization of the general `accumulateFromPrefixes` + * for appending vector values into a single vector. + * + * @see `accumulateFromPrefixes` for a detailed description + * @param keyValMap the map that contains the key-value-pairs to search + * @param prefixFunc the function that returns the longest non-identical prefix of the key + * @param key the key to calculate the prefixes of + */ + template <typename KeyT, typename ValueT> + std::vector<ValueT> + accumulateFromPrefixes(const std::map<KeyT, std::vector<ValueT>>& keyValMap, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, + const KeyT& key) + { + return accumulateFromPrefixes<KeyT, std::vector<ValueT>, std::vector<ValueT>>( + keyValMap, + prefixFunc, + [](std::vector<ValueT>& values, const std::vector<ValueT>& val) + { values.insert(values.end(), val.begin(), val.end()); }, + key); + } + + } // namespace detail + + + std::optional<MemoryID> inline getMemoryIDParent(const MemoryID& memID) + { + if (!memID.hasMemoryName()) + { + return std::nullopt; + } + MemoryID parent = memID.removeLeafItem(); + return {parent}; + } + + + /** + * @brief Find the entry with the most specific key that contains the given ID, + * or `idMap.end()` if no key contains the ID. + * + * @see `detail::findEntryWithLongestPrefix()` + */ + template <typename ValueT> + typename std::map<MemoryID, ValueT>::const_iterator + findMostSpecificEntryContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id) + { + return detail::findEntryWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, id); + } + + + /** + * @brief Return all values of keys containing the given ID. + * + * @see `detail::accumulateFromPrefixes()` + */ + template <typename ValueT> + std::vector<ValueT> + accumulateEntriesContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id) + { + return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, id); + } + + + /** + * @brief Return all values of keys containing the given ID in a flattened vector. + * + * @see `detail::accumulateFromPrefixes()` + */ + template <typename ValueT> + std::vector<ValueT> + accumulateEntriesContainingID(const std::map<MemoryID, std::vector<ValueT>>& idMap, + const MemoryID& key) + { + return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key); + } + + +} // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp index 1400107eaa926207ce2cc7b1a07f508897038c88..a10a398186c73734a841dbf3e40cf8db11987769 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp @@ -359,4 +359,32 @@ namespace armarx::armem::server return output; } + // PREDICTION + prediction::data::EngineSupportMap MemoryToIceAdapter::getAvailableEngines() + { + prediction::data::EngineSupportMap result; + armarx::toIce(result, workingMemory->getAllPredictionEngines()); + + prediction::data::EngineSupportMap ltmMap; + armarx::toIce(ltmMap, workingMemory->getAllPredictionEngines()); + for (const auto& [memoryID, engines] : ltmMap) + { + auto entryIter = result.find(memoryID); + if (entryIter == result.end()) + { + result.emplace(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 33e788ff566ca4f06b369160112f54160b425b46..96c1e822d6f4150c6e341bd5c0d234f57efec2b5 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 f690cbaeef48944c8568ef58b0aae08b82735513..44454b87d83b905edff8b925b0aa5831ffd8715e 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp @@ -1,8 +1,8 @@ #include "ReadWritePluginUser.h" #include "Plugin.h" -#include <RobotAPI/libraries/armem/client/Prediction.h> #include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> #include <ArmarXCore/core/Component.h> @@ -125,7 +125,7 @@ namespace armarx::armem::server::plugins armem::prediction::data::PredictionResultSeq result; for (auto request : requests) { - armem::client::PredictionResult singleResult; + armem::PredictionResult singleResult; singleResult.success = false; singleResult.errorMessage = "This memory does not implement predictions."; singleResult.prediction = nullptr; @@ -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/plugins/ReadWritePluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h index 37f25fd8f3199179402755dc76d98367964aa2af..8ddf174b172d4eb2fc4fba7f3e89d79553d72b42 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h @@ -57,6 +57,10 @@ namespace armarx::armem::server::plugins // PredictingInterface interface virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests); + + // Unless you need very unusual behavior from this method for your memory server, + // it is better to set the available prediction engines in the memory itself + // and let it handle the requests than to override this. virtual armem::prediction::data::EngineSupportMap getAvailableEngines(); virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests, const ::Ice::Current&) override; diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp index b0afa282677c45325993feee0fcba60245236611..818c2d38520fa55b31390cff00123720f0fdbefd 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 std::vector<PredictionEngine>& 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->setPredictionEngines(predictionEngines); } } @@ -80,6 +83,13 @@ namespace armarx::armem::server::segment this->aronType = aronType; } + void + SpecializedCoreSegment::setPredictionEngines( + const std::vector<PredictionEngine>& 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 d94fa1aed5632e752fec44bbfeadc91b1c7e34bd..5ddca3e7d1dc0820a29039dba17af1e956d9897c 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 std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& predictionEngines); wm::CoreSegment& getCoreSegment(); const wm::CoreSegment& getCoreSegment() const; @@ -51,6 +54,7 @@ namespace armarx::armem::server::segment public: aron::type::ObjectPtr aronType; + std::vector<PredictionEngine> predictionEngines; struct Properties { diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp index 747b2bec833e5f1b13366e2954b5af4f12f64b4b..f5ab3b86543d601310a02a0de59820a2d459a32e 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 std::vector<PredictionEngine>& providerSegmentPredictionEngines, + const std::vector<PredictionEngine>& 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->setPredictionEngines(predictionEngines); } } @@ -85,6 +93,13 @@ namespace armarx::armem::server::segment this->aronType = aronType; } + void + SpecializedProviderSegment::setPredictionEngines( + const std::vector<PredictionEngine>& 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 44db000d18e7804c99e1cc1d412cd3efe5b9b652..3cb50c52f42ba2e2ca35a5024755729b9226336f 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 std::vector<PredictionEngine>& providerSegmentPredictionEngines = {}, + const std::vector<PredictionEngine>& 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 std::vector<PredictionEngine>& predictionEngines); wm::ProviderSegment& getProviderSegment(); const wm::ProviderSegment& getProviderSegment() const; @@ -47,6 +51,7 @@ namespace armarx::armem::server::segment public: aron::type::ObjectPtr aronType; + std::vector<PredictionEngine> predictionEngines; SpecializedCoreSegment coreSegment; struct Properties diff --git a/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4efc404325b61dbea0f68c7ec1bda5ecb051b8c6 --- /dev/null +++ b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp @@ -0,0 +1,94 @@ +/* + * 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 + * @author phesch ( ulila at student dot kit dot edu ) + * @date 2022 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE RobotAPI::armem + +#define ARMARX_BOOST_TEST + +#include <iostream> + +#include <RobotAPI/Test.h> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/container_maps.h> + + +namespace armem = armarx::armem; + +BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes) +{ + std::map<armem::MemoryID, int> idMap; + std::map<armem::MemoryID, std::vector<int>> idListMap; + armem::MemoryID empty; + armem::MemoryID complete("mem", "coreSeg", "provSeg", "entity", armarx::DateTime::Now(), 0); + + BOOST_TEST_CONTEXT(VAROUT(idMap)) + { + BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, empty) == idMap.end()); + BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, complete) == idMap.end()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, empty).empty()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, complete).empty()); + + BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, empty).empty()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, complete).empty()); + } + + idMap[armem::MemoryID()] = 0; + idMap.emplace("mem", 1); + idMap.emplace("mem/coreSeg", 2); + idMap.emplace("mem/coreSeg/provSeg", 3); + idMap.emplace("mem/otherSeg/provSeg", 10); + + BOOST_TEST_CONTEXT(VAROUT(idMap)) + { + auto it = armem::findMostSpecificEntryContainingID(idMap, empty); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 0); + + it = armem::findMostSpecificEntryContainingID(idMap, complete.getCoreSegmentID()); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 2); + + it = armem::findMostSpecificEntryContainingID(idMap, complete); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 3); + + BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, empty) == std::vector<int>{0})); + BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, complete.getCoreSegmentID()) == + std::vector<int>{2, 1, 0})); + BOOST_CHECK( + (armem::accumulateEntriesContainingID(idMap, complete) == std::vector<int>{3, 2, 1, 0})); + } + + idListMap.emplace("mem", std::vector<int>{1, 2}); + idListMap.emplace("mem/coreSeg", std::vector<int>{3, 4, 5}); + idListMap.emplace("mem/coreSeg/provSeg", std::vector<int>{6, 7, 8}); + idListMap.emplace("mem/otherSeg/provSeg", std::vector<int>{9, 10, 11}); + + BOOST_TEST_CONTEXT(VAROUT(idListMap)) + { + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, empty).empty())); + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete.getCoreSegmentID()) == + std::vector<int>{3, 4, 5, 1, 2})); + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete) == + std::vector<int>{6, 7, 8, 3, 4, 5, 1, 2})); + } +} diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt index 592b9aef3105bd7fc780c92348cae11e60f65a6d..da77a43b82a6174b756ddf1705e8c29ea3acabb2 100644 --- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt @@ -7,3 +7,4 @@ armarx_add_test(ArMemGetFindTest ArMemGetFindTest.cpp "${LIBS}") armarx_add_test(ArMemIceConversionsTest ArMemIceConversionsTest.cpp "${LIBS}") armarx_add_test(ArMemMemoryIDTest ArMemMemoryIDTest.cpp "${LIBS}") armarx_add_test(ArMemQueryBuilderTest ArMemQueryBuilderTest.cpp "${LIBS}") +armarx_add_test(ArMemPrefixesTest ArMemPrefixesTest.cpp "${LIBS}") diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp index 6bad86c0f05ccdaa33855d9411c27d9cc04d50f6..aaf23c20e21eff50cf135664b6c8c951d9980abd 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp @@ -49,8 +49,11 @@ namespace armarx::armem::server::obj::instance { Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) : - SpecializedCoreSegment(memoryToIceAdapter, "Instance", - arondto::ObjectInstance::ToAronType(), 64) + SpecializedCoreSegment(memoryToIceAdapter, + "Instance", + arondto::ObjectInstance::ToAronType(), + 64, + predictionEngines) { oobbCache.setFetchFn([this](const ObjectID & id) -> std::optional<simox::OrientedBoxf> { diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h index 0aa9b930411f0a6f6336ea439fbb98ff6dc74a50..ba7c5539df7299be11ceead0c4253938bfe9ed73 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h @@ -18,7 +18,7 @@ #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> #include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h> -#include <RobotAPI/libraries/armem/client/Prediction.h> +#include <RobotAPI/libraries/armem/core/Prediction.h> #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h> #include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h> @@ -194,7 +194,6 @@ namespace armarx::armem::server::obj::instance static const std::string timestampPlaceholder; - public: struct RemoteGui diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp index 7c7dac41c1a74bca1606721b86de565f821a7608..7a36b0cbce48d258eded0545492bd4974019069f 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp @@ -68,6 +68,7 @@ namespace armarx::armem::server::obj::instance { segment.setTag(getName()); segment.decay.setTag(getName()); + segment.setPredictionEngines(predictionEngines); robotHead.setTag(getName()); visu.setTag(getName()); @@ -494,11 +495,11 @@ namespace armarx::armem::server::obj::instance if (result.success) { - armem::client::PredictionSettings settings = - armem::client::PredictionSettings::fromIce(request.settings); + armem::PredictionSettings settings = + armem::PredictionSettings::fromIce(request.settings); if (settings.predictionEngineID.empty() - or settings.predictionEngineID == "Linear Position Regression") + or settings.predictionEngineID == linearPredictionEngineID) { result = objpose::predictObjectPoseLinear( poses.at(i), @@ -519,10 +520,7 @@ namespace armarx::armem::server::obj::instance armem::prediction::data::PredictionEngineSeq SegmentAdapter::getAvailableObjectPoseEngines(const Ice::Current&) { - armem::prediction::data::PredictionEngine engine; - // TODO(phesch): Make this a constant somewhere - engine.engineID = "Linear Position Regression"; - return { engine }; + return armarx::toIce<armem::prediction::data::PredictionEngineSeq>(predictionEngines); } void @@ -600,6 +598,10 @@ namespace armarx::armem::server::obj::instance cycle.waitForCycleDuration(); } } + + + const std::string SegmentAdapter::linearPredictionEngineID = "Linear Position Regression"; + const std::vector<PredictionEngine> SegmentAdapter::predictionEngines{{linearPredictionEngineID}}; void SegmentAdapter::Calibration::defineProperties(PropertyDefinitionsPtr defs, const std::string& prefix) @@ -609,7 +611,6 @@ namespace armarx::armem::server::obj::instance } - void SegmentAdapter::RemoteGui::setup(const SegmentAdapter& adapter) { using namespace armarx::RemoteGui::Client; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h index 69595f7b640ec57cb1dcd7222233e7681f6f20e1..aafe61f5c87e5a1363ef837d56cd7cbeec08407c 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h +++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h @@ -116,7 +116,9 @@ namespace armarx::armem::server::obj::instance virtual armem::prediction::data::PredictionEngineSeq getAvailableObjectPoseEngines(ICE_CURRENT_ARG) override; + private: + void updateProviderInfo(const std::string& providerName, const objpose::ProviderInfo& info); void updateObjectPoses(const std::string& providerName, const objpose::data::ProvidedObjectPoseSeq& providedPoses); @@ -128,6 +130,12 @@ namespace armarx::armem::server::obj::instance void visualizeRun(); + public: + + static const std::string linearPredictionEngineID; + static const std::vector<PredictionEngine> predictionEngines; + + private: viz::Client arviz; diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp index 47206a42fa74036015b875f104c0503172d9ac2e..eb7d90cd267566d10487ce4d2b390ccc63eee586 100644 --- a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp @@ -10,7 +10,6 @@ #include <RobotAPI/libraries/ArmarXObjects/ice_conversions.h> #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h> #include <RobotAPI/libraries/ArmarXObjects/predictions.h> -#include <RobotAPI/libraries/armem/client/Prediction.h> namespace armarx::armem::server::obj::instance