From 86c9e39829042a497c7b9d364cfc651198cd4924 Mon Sep 17 00:00:00 2001
From: Olivier BICHLER <olivier.bichler@cea.fr>
Date: Tue, 10 Sep 2024 10:54:01 +0200
Subject: [PATCH] Added Operator::getAvailableBackends()

---
 include/aidge/backend/OperatorImpl.hpp          |  2 +-
 include/aidge/operator/Abs.hpp                  |  1 +
 include/aidge/operator/Add.hpp                  |  1 +
 include/aidge/operator/And.hpp                  |  1 +
 include/aidge/operator/ArgMax.hpp               |  1 +
 include/aidge/operator/AvgPooling.hpp           |  1 +
 include/aidge/operator/BatchNorm.hpp            |  1 +
 include/aidge/operator/Cast.hpp                 |  1 +
 include/aidge/operator/Concat.hpp               |  1 +
 include/aidge/operator/Conv.hpp                 |  1 +
 include/aidge/operator/ConvDepthWise.hpp        |  1 +
 include/aidge/operator/DepthToSpace.hpp         |  1 +
 include/aidge/operator/Div.hpp                  |  1 +
 include/aidge/operator/Erf.hpp                  |  1 +
 include/aidge/operator/FC.hpp                   |  1 +
 include/aidge/operator/Fold.hpp                 |  1 +
 include/aidge/operator/Gather.hpp               |  1 +
 include/aidge/operator/GenericOperator.hpp      |  1 +
 include/aidge/operator/GlobalAveragePooling.hpp |  1 +
 include/aidge/operator/GridSample.hpp           |  1 +
 include/aidge/operator/Identity.hpp             |  1 +
 include/aidge/operator/LeakyReLU.hpp            |  1 +
 include/aidge/operator/Ln.hpp                   |  1 +
 include/aidge/operator/MatMul.hpp               |  1 +
 include/aidge/operator/MaxPooling.hpp           |  1 +
 include/aidge/operator/Memorize.hpp             |  1 +
 include/aidge/operator/MetaOperator.hpp         |  1 +
 include/aidge/operator/Move.hpp                 |  1 +
 include/aidge/operator/Mul.hpp                  |  1 +
 include/aidge/operator/Operator.hpp             |  2 ++
 include/aidge/operator/Pad.hpp                  |  1 +
 include/aidge/operator/Pop.hpp                  |  1 +
 include/aidge/operator/Pow.hpp                  |  1 +
 include/aidge/operator/Producer.hpp             |  1 +
 include/aidge/operator/ReLU.hpp                 |  1 +
 include/aidge/operator/ReduceMean.hpp           |  1 +
 include/aidge/operator/ReduceSum.hpp            |  1 +
 include/aidge/operator/Reshape.hpp              |  3 ++-
 include/aidge/operator/Resize.hpp               |  1 +
 include/aidge/operator/Scaling.hpp              |  1 +
 include/aidge/operator/Shape.hpp                |  1 +
 include/aidge/operator/ShiftGELU.hpp            |  1 +
 include/aidge/operator/ShiftMax.hpp             |  1 +
 include/aidge/operator/Sigmoid.hpp              |  1 +
 include/aidge/operator/Slice.hpp                |  1 +
 include/aidge/operator/Softmax.hpp              |  1 +
 include/aidge/operator/Split.hpp                |  1 +
 include/aidge/operator/Sqrt.hpp                 |  1 +
 include/aidge/operator/Sub.hpp                  |  1 +
 include/aidge/operator/Tanh.hpp                 |  1 +
 include/aidge/operator/Transpose.hpp            |  1 +
 include/aidge/operator/Unfold.hpp               |  1 +
 include/aidge/utils/Registrar.hpp               |  8 ++++----
 python_binding/backend/pybind_OperatorImpl.cpp  |  4 ++--
 src/backend/OperatorImpl.cpp                    | 11 ++++++-----
 src/operator/Abs.cpp                            |  4 ++++
 src/operator/Add.cpp                            |  4 ++++
 src/operator/And.cpp                            |  4 ++++
 src/operator/ArgMax.cpp                         |  6 +++++-
 src/operator/AvgPooling.cpp                     |  5 +++++
 src/operator/BatchNorm.cpp                      |  5 +++++
 src/operator/Cast.cpp                           |  4 ++++
 src/operator/Concat.cpp                         |  4 ++++
 src/operator/Conv.cpp                           |  5 +++++
 src/operator/ConvDepthWise.cpp                  |  5 +++++
 src/operator/DepthToSpace.cpp                   |  4 ++++
 src/operator/Div.cpp                            |  4 ++++
 src/operator/Erf.cpp                            |  4 ++++
 src/operator/FC.cpp                             |  4 ++++
 src/operator/Fold.cpp                           |  5 +++++
 src/operator/Gather.cpp                         |  4 ++++
 src/operator/GlobalAveragePooling.cpp           |  4 ++++
 src/operator/GridSample.cpp                     |  4 ++++
 src/operator/LeakyReLU.cpp                      |  4 ++++
 src/operator/Ln.cpp                             |  4 ++++
 src/operator/MatMul.cpp                         |  4 ++++
 src/operator/MaxPooling.cpp                     |  5 +++++
 src/operator/Memorize.cpp                       |  4 ++++
 src/operator/MetaOperator.cpp                   | 10 ++++++++++
 src/operator/Move.cpp                           |  9 +++++++++
 src/operator/Mul.cpp                            |  4 ++++
 src/operator/Pad.cpp                            |  5 +++++
 src/operator/Pop.cpp                            |  4 ++++
 src/operator/Pow.cpp                            |  4 ++++
 src/operator/Producer.cpp                       |  4 ++++
 src/operator/ReLU.cpp                           |  4 ++++
 src/operator/ReduceMean.cpp                     |  4 ++++
 src/operator/ReduceSum.cpp                      |  6 +++++-
 src/operator/Reshape.cpp                        |  4 ++++
 src/operator/Resize.cpp                         |  4 ++++
 src/operator/Scaling.cpp                        |  4 ++++
 src/operator/Shape.cpp                          |  4 ++++
 src/operator/ShiftGELU.cpp                      |  4 ++++
 src/operator/ShiftMax.cpp                       |  4 ++++
 src/operator/Sigmoid.cpp                        |  4 ++++
 src/operator/Slice.cpp                          |  4 ++++
 src/operator/Softmax.cpp                        |  4 ++++
 src/operator/Split.cpp                          |  4 ++++
 src/operator/Sqrt.cpp                           |  4 ++++
 src/operator/Sub.cpp                            |  4 ++++
 src/operator/Tanh.cpp                           |  4 ++++
 src/operator/Transpose.cpp                      |  4 ++++
 src/operator/Unfold.cpp                         |  5 +++++
 103 files changed, 279 insertions(+), 15 deletions(-)

diff --git a/include/aidge/backend/OperatorImpl.hpp b/include/aidge/backend/OperatorImpl.hpp
index e145475c6..af87efedf 100644
--- a/include/aidge/backend/OperatorImpl.hpp
+++ b/include/aidge/backend/OperatorImpl.hpp
@@ -146,7 +146,7 @@ public:
 
 protected:
     virtual std::shared_ptr<ProdConso> getProdConso() const;
-    virtual std::vector<ImplSpec> getAvailableImplSpecs() const;
+    virtual std::set<ImplSpec> getAvailableImplSpecs() const;
     bool checkIOSpec(const ImplSpec::IOSpec& required, const ImplSpec::IOSpec& spec) const;
 
     const Operator &mOp;
diff --git a/include/aidge/operator/Abs.hpp b/include/aidge/operator/Abs.hpp
index a975faa24..f1dc37003 100644
--- a/include/aidge/operator/Abs.hpp
+++ b/include/aidge/operator/Abs.hpp
@@ -54,6 +54,7 @@ public:
     }
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Add.hpp b/include/aidge/operator/Add.hpp
index b35a01923..daf507717 100644
--- a/include/aidge/operator/Add.hpp
+++ b/include/aidge/operator/Add.hpp
@@ -55,6 +55,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName() {
         return {"data_input_0", "data_input_n"};
diff --git a/include/aidge/operator/And.hpp b/include/aidge/operator/And.hpp
index 65b2bc588..e4f04e2fa 100644
--- a/include/aidge/operator/And.hpp
+++ b/include/aidge/operator/And.hpp
@@ -64,6 +64,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input_1", "data_input_2"};
diff --git a/include/aidge/operator/ArgMax.hpp b/include/aidge/operator/ArgMax.hpp
index 1582446bb..13f63ce98 100644
--- a/include/aidge/operator/ArgMax.hpp
+++ b/include/aidge/operator/ArgMax.hpp
@@ -91,6 +91,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::int32_t& axis() const noexcept { return mAttributes -> getAttr<ArgMaxAttr::Axis>(); }
diff --git a/include/aidge/operator/AvgPooling.hpp b/include/aidge/operator/AvgPooling.hpp
index 6fc7b596a..54b40907e 100644
--- a/include/aidge/operator/AvgPooling.hpp
+++ b/include/aidge/operator/AvgPooling.hpp
@@ -77,6 +77,7 @@ public:
 
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::array<DimSize_t, DIM>& strideDims() const { return mAttributes->template getAttr<AvgPoolingAttr::StrideDims>(); }
diff --git a/include/aidge/operator/BatchNorm.hpp b/include/aidge/operator/BatchNorm.hpp
index f09b52de4..cdac7935f 100644
--- a/include/aidge/operator/BatchNorm.hpp
+++ b/include/aidge/operator/BatchNorm.hpp
@@ -79,6 +79,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline float& epsilon() const { return mAttributes->template getAttr<BatchNormAttr::Epsilon>(); }
diff --git a/include/aidge/operator/Cast.hpp b/include/aidge/operator/Cast.hpp
index 58969c0e1..3fa1bb22a 100644
--- a/include/aidge/operator/Cast.hpp
+++ b/include/aidge/operator/Cast.hpp
@@ -73,6 +73,7 @@ public:
     }
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline DataType& targetType() const { return mAttributes->template getAttr<CastAttr::TargetType>(); }
diff --git a/include/aidge/operator/Concat.hpp b/include/aidge/operator/Concat.hpp
index 97db803c6..98835dd2a 100644
--- a/include/aidge/operator/Concat.hpp
+++ b/include/aidge/operator/Concat.hpp
@@ -67,6 +67,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::int32_t& axis() const { return mAttributes->template getAttr<ConcatAttr::Axis>(); }
diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp
index 1a32b14b8..cd1a57dd9 100644
--- a/include/aidge/operator/Conv.hpp
+++ b/include/aidge/operator/Conv.hpp
@@ -97,6 +97,7 @@ public:
 
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     DimSize_t inChannels() const {
         if (!getInput(1)) {
diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp
index a4665239f..f0a55a299 100644
--- a/include/aidge/operator/ConvDepthWise.hpp
+++ b/include/aidge/operator/ConvDepthWise.hpp
@@ -83,6 +83,7 @@ public:
                           const IOIndex_t outputIdx = 0) const override;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     DimSize_t nbChannels() const {
         if (!getInput(1)) {
diff --git a/include/aidge/operator/DepthToSpace.hpp b/include/aidge/operator/DepthToSpace.hpp
index 0c74d4942..856cd0e85 100644
--- a/include/aidge/operator/DepthToSpace.hpp
+++ b/include/aidge/operator/DepthToSpace.hpp
@@ -68,6 +68,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::uint32_t& blockSize() const { return mAttributes->template getAttr<DepthToSpaceAttr::BlockSize>(); }
diff --git a/include/aidge/operator/Div.hpp b/include/aidge/operator/Div.hpp
index 22fed0371..5ed9e789d 100644
--- a/include/aidge/operator/Div.hpp
+++ b/include/aidge/operator/Div.hpp
@@ -57,6 +57,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input_1", "data_input_2"};
diff --git a/include/aidge/operator/Erf.hpp b/include/aidge/operator/Erf.hpp
index b5c4d80bc..88a4bfd29 100644
--- a/include/aidge/operator/Erf.hpp
+++ b/include/aidge/operator/Erf.hpp
@@ -44,6 +44,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/FC.hpp b/include/aidge/operator/FC.hpp
index aab7d925a..592ba4e2b 100644
--- a/include/aidge/operator/FC.hpp
+++ b/include/aidge/operator/FC.hpp
@@ -60,6 +60,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     DimSize_t inChannels() const {
         if (!getInput(1)) {
diff --git a/include/aidge/operator/Fold.hpp b/include/aidge/operator/Fold.hpp
index bbf838b0b..517d63adc 100644
--- a/include/aidge/operator/Fold.hpp
+++ b/include/aidge/operator/Fold.hpp
@@ -78,6 +78,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::array<DimSize_t, DIM>& outputDims() const { return mAttributes->template getAttr<FoldAttr::OutputDims>(); }
diff --git a/include/aidge/operator/Gather.hpp b/include/aidge/operator/Gather.hpp
index 2122e89ac..80dcdd678 100644
--- a/include/aidge/operator/Gather.hpp
+++ b/include/aidge/operator/Gather.hpp
@@ -73,6 +73,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::int8_t& axis() const { return mAttributes -> getAttr<GatherAttr::Axis>(); }
diff --git a/include/aidge/operator/GenericOperator.hpp b/include/aidge/operator/GenericOperator.hpp
index 106168c54..2812da066 100644
--- a/include/aidge/operator/GenericOperator.hpp
+++ b/include/aidge/operator/GenericOperator.hpp
@@ -57,6 +57,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override { return std::set<std::string>(); };
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
 
     template <class T>
diff --git a/include/aidge/operator/GlobalAveragePooling.hpp b/include/aidge/operator/GlobalAveragePooling.hpp
index 4c139e63d..ef440e8c6 100644
--- a/include/aidge/operator/GlobalAveragePooling.hpp
+++ b/include/aidge/operator/GlobalAveragePooling.hpp
@@ -46,6 +46,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
   void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
   static const std::vector<std::string> getInputsName() {
     return {"data_input"};
diff --git a/include/aidge/operator/GridSample.hpp b/include/aidge/operator/GridSample.hpp
index be18f9023..dc2b2059e 100644
--- a/include/aidge/operator/GridSample.hpp
+++ b/include/aidge/operator/GridSample.hpp
@@ -58,6 +58,7 @@ public:
 	bool forwardDims(bool /*allowDataDependencies*/ = false) override final;
 
 	void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
 	inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
 	inline Mode mode() const { return mAttributes->template getAttr<GridSampleAttr::Mode>(); }
diff --git a/include/aidge/operator/Identity.hpp b/include/aidge/operator/Identity.hpp
index 69ab82963..3059411fd 100644
--- a/include/aidge/operator/Identity.hpp
+++ b/include/aidge/operator/Identity.hpp
@@ -74,6 +74,7 @@ public:
     void setBackend(const std::string& /*name*/, DeviceIdx_t /*device*/ = 0) override final {
         // setBackend do nothing, Identity node has no backend it just pass the same Tensor
     }
+    std::set<std::string> getAvailableBackends() const override { return std::set<std::string>(); };
     void setDataType(const DataType& /*dataType*/) const override final {
         // setDatatype do nothing, Identity node has no backend it just pass the same Tensor
     }
diff --git a/include/aidge/operator/LeakyReLU.hpp b/include/aidge/operator/LeakyReLU.hpp
index a6188221d..179eb90b3 100644
--- a/include/aidge/operator/LeakyReLU.hpp
+++ b/include/aidge/operator/LeakyReLU.hpp
@@ -62,6 +62,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline float& negativeSlope() const noexcept { return mAttributes -> getAttr<LeakyReLUAttr::NegativeSlope>(); }
diff --git a/include/aidge/operator/Ln.hpp b/include/aidge/operator/Ln.hpp
index e606f670a..22fc51664 100755
--- a/include/aidge/operator/Ln.hpp
+++ b/include/aidge/operator/Ln.hpp
@@ -46,6 +46,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/MatMul.hpp b/include/aidge/operator/MatMul.hpp
index 25a60a429..bf6ab84c7 100644
--- a/include/aidge/operator/MatMul.hpp
+++ b/include/aidge/operator/MatMul.hpp
@@ -59,6 +59,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName() {
         return {"data_input1", "data_input2"};
diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp
index ff0208aa9..0cc43a6fb 100644
--- a/include/aidge/operator/MaxPooling.hpp
+++ b/include/aidge/operator/MaxPooling.hpp
@@ -69,6 +69,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::array<DimSize_t, DIM>& strideDims() const { return mAttributes->template getAttr<MaxPoolingAttr::StrideDims>(); }
diff --git a/include/aidge/operator/Memorize.hpp b/include/aidge/operator/Memorize.hpp
index bd37c0544..babef1579 100644
--- a/include/aidge/operator/Memorize.hpp
+++ b/include/aidge/operator/Memorize.hpp
@@ -72,6 +72,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     bool forwardDims(bool allowDataDependency = false) override final;
     bool dimsForwarded() const override;
diff --git a/include/aidge/operator/MetaOperator.hpp b/include/aidge/operator/MetaOperator.hpp
index fdbf3a181..09aba5691 100644
--- a/include/aidge/operator/MetaOperator.hpp
+++ b/include/aidge/operator/MetaOperator.hpp
@@ -82,6 +82,7 @@ public:
 
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     void setDataType(const DataType &datatype) const override {
         // The micro-graph should always be set to the right data type, since it
diff --git a/include/aidge/operator/Move.hpp b/include/aidge/operator/Move.hpp
index 2aed78f99..49d92cd12 100644
--- a/include/aidge/operator/Move.hpp
+++ b/include/aidge/operator/Move.hpp
@@ -50,6 +50,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Mul.hpp b/include/aidge/operator/Mul.hpp
index 519d4e1f9..bfe4fcb0d 100644
--- a/include/aidge/operator/Mul.hpp
+++ b/include/aidge/operator/Mul.hpp
@@ -50,6 +50,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input_1", "data_input_2"};
diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp
index c938fc362..8a1caab02 100644
--- a/include/aidge/operator/Operator.hpp
+++ b/include/aidge/operator/Operator.hpp
@@ -132,6 +132,8 @@ public:
     virtual void setDataType(const DataType& dataType) const = 0;
     virtual void setDataFormat(const DataFormat& dataFormat) const = 0;
 
+    virtual std::set<std::string> getAvailableBackends() const = 0;
+
     /**
      * @brief Set a new OperatorImpl to the Operator
      *
diff --git a/include/aidge/operator/Pad.hpp b/include/aidge/operator/Pad.hpp
index d47549151..2c670bf23 100644
--- a/include/aidge/operator/Pad.hpp
+++ b/include/aidge/operator/Pad.hpp
@@ -74,6 +74,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::array<DimSize_t, 2*DIM>& beginEndBorders() const noexcept { return mAttributes->template getAttr<PadAttr::BeginEndBorders>(); }
diff --git a/include/aidge/operator/Pop.hpp b/include/aidge/operator/Pop.hpp
index 1bdf30da8..d5898b363 100644
--- a/include/aidge/operator/Pop.hpp
+++ b/include/aidge/operator/Pop.hpp
@@ -65,6 +65,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     bool forwardDims(bool allowDataDependency = false) override final;
     void updateConsummerProducer() override;
diff --git a/include/aidge/operator/Pow.hpp b/include/aidge/operator/Pow.hpp
index d38cb1a33..f6762dd33 100644
--- a/include/aidge/operator/Pow.hpp
+++ b/include/aidge/operator/Pow.hpp
@@ -57,6 +57,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName() {
         return {"data_input_1", "data_input_2"};
diff --git a/include/aidge/operator/Producer.hpp b/include/aidge/operator/Producer.hpp
index 2b3d7684c..c073c9a90 100644
--- a/include/aidge/operator/Producer.hpp
+++ b/include/aidge/operator/Producer.hpp
@@ -89,6 +89,7 @@ public:
     inline const std::vector<DimSize_t> dims() const noexcept { return mOutputs[0]->dims(); }
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline bool& constant() const { return mAttributes->template getAttr<ProdAttr::Constant>(); }
diff --git a/include/aidge/operator/ReLU.hpp b/include/aidge/operator/ReLU.hpp
index 350f30bc7..9b264c1d3 100644
--- a/include/aidge/operator/ReLU.hpp
+++ b/include/aidge/operator/ReLU.hpp
@@ -46,6 +46,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/ReduceMean.hpp b/include/aidge/operator/ReduceMean.hpp
index 02ea9ec5c..5d5895a8f 100644
--- a/include/aidge/operator/ReduceMean.hpp
+++ b/include/aidge/operator/ReduceMean.hpp
@@ -74,6 +74,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::vector<std::int32_t>& axes() const noexcept { return mAttributes -> getAttr<ReduceMeanAttr::Axes>(); }
diff --git a/include/aidge/operator/ReduceSum.hpp b/include/aidge/operator/ReduceSum.hpp
index 73631dee1..bae03cb7d 100644
--- a/include/aidge/operator/ReduceSum.hpp
+++ b/include/aidge/operator/ReduceSum.hpp
@@ -92,6 +92,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::vector<std::int32_t>& axes() const noexcept { return mAttributes -> getAttr<ReduceSumAttr::Axes>(); }
diff --git a/include/aidge/operator/Reshape.hpp b/include/aidge/operator/Reshape.hpp
index 16d14a19c..721b964d3 100644
--- a/include/aidge/operator/Reshape.hpp
+++ b/include/aidge/operator/Reshape.hpp
@@ -47,7 +47,7 @@ private:
 public:
     Reshape_Op() = delete;
 
-    Reshape_Op(const std::vector<std::int64_t>& shape, bool allowzero);
+    Reshape_Op(const std::vector<std::int64_t>& shape = {}, bool allowzero = false);
 
     /**
      * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated).
@@ -65,6 +65,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::vector<std::int64_t>& shape() const { return mAttributes->template getAttr<ReshapeAttr::Shape>(); }
diff --git a/include/aidge/operator/Resize.hpp b/include/aidge/operator/Resize.hpp
index e3551d72d..a48b95aff 100644
--- a/include/aidge/operator/Resize.hpp
+++ b/include/aidge/operator/Resize.hpp
@@ -49,6 +49,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         //  roi, scales, sizes, even if considered as const parameters/input
diff --git a/include/aidge/operator/Scaling.hpp b/include/aidge/operator/Scaling.hpp
index 15393755f..4ef39f63a 100644
--- a/include/aidge/operator/Scaling.hpp
+++ b/include/aidge/operator/Scaling.hpp
@@ -57,6 +57,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline float& scalingFactor() const noexcept { return mAttributes -> getAttr<ScalingAttr::ScalingFactor>(); }
diff --git a/include/aidge/operator/Shape.hpp b/include/aidge/operator/Shape.hpp
index ebe345d15..cfd43fa0d 100644
--- a/include/aidge/operator/Shape.hpp
+++ b/include/aidge/operator/Shape.hpp
@@ -66,6 +66,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::int64_t& start() const noexcept { return mAttributes -> getAttr<ShapeAttr::Start>(); }
diff --git a/include/aidge/operator/ShiftGELU.hpp b/include/aidge/operator/ShiftGELU.hpp
index d157a9202..ee69ceb1e 100644
--- a/include/aidge/operator/ShiftGELU.hpp
+++ b/include/aidge/operator/ShiftGELU.hpp
@@ -48,6 +48,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/ShiftMax.hpp b/include/aidge/operator/ShiftMax.hpp
index c37948625..1e33f6068 100644
--- a/include/aidge/operator/ShiftMax.hpp
+++ b/include/aidge/operator/ShiftMax.hpp
@@ -48,6 +48,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Sigmoid.hpp b/include/aidge/operator/Sigmoid.hpp
index a18fc6df0..24bc33216 100644
--- a/include/aidge/operator/Sigmoid.hpp
+++ b/include/aidge/operator/Sigmoid.hpp
@@ -37,6 +37,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Slice.hpp b/include/aidge/operator/Slice.hpp
index 5eba32c1d..811402420 100644
--- a/include/aidge/operator/Slice.hpp
+++ b/include/aidge/operator/Slice.hpp
@@ -69,6 +69,7 @@ public:
     bool forwardDims(bool allowDataDependency = true) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::vector<std::int64_t>& starts() const noexcept { return mAttributes -> getAttr<SliceAttr::Starts>(); }
diff --git a/include/aidge/operator/Softmax.hpp b/include/aidge/operator/Softmax.hpp
index eb21cac38..72ea56dd6 100644
--- a/include/aidge/operator/Softmax.hpp
+++ b/include/aidge/operator/Softmax.hpp
@@ -57,6 +57,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
 
diff --git a/include/aidge/operator/Split.hpp b/include/aidge/operator/Split.hpp
index 66d23547d..8c3a111c4 100644
--- a/include/aidge/operator/Split.hpp
+++ b/include/aidge/operator/Split.hpp
@@ -68,6 +68,7 @@ public:
     bool forwardDims(bool allowDataDependency = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::int8_t& axis() const { return mAttributes->template getAttr<SplitAttr::Axis>(); }
diff --git a/include/aidge/operator/Sqrt.hpp b/include/aidge/operator/Sqrt.hpp
index e3c7ba28c..4858cdcd1 100644
--- a/include/aidge/operator/Sqrt.hpp
+++ b/include/aidge/operator/Sqrt.hpp
@@ -45,6 +45,7 @@ public:
     std::shared_ptr<Operator> clone() const override;
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Sub.hpp b/include/aidge/operator/Sub.hpp
index a7c3fd16f..170baf6fd 100644
--- a/include/aidge/operator/Sub.hpp
+++ b/include/aidge/operator/Sub.hpp
@@ -48,6 +48,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input_1", "data_input_2"};
diff --git a/include/aidge/operator/Tanh.hpp b/include/aidge/operator/Tanh.hpp
index 9731fc9c1..f1a30e3f0 100644
--- a/include/aidge/operator/Tanh.hpp
+++ b/include/aidge/operator/Tanh.hpp
@@ -44,6 +44,7 @@ public:
 
 
     void setBackend(const std::string& name, DeviceIdx_t device = 0) override final;
+    std::set<std::string> getAvailableBackends() const override;
 
     static const std::vector<std::string> getInputsName(){
         return {"data_input"};
diff --git a/include/aidge/operator/Transpose.hpp b/include/aidge/operator/Transpose.hpp
index ba96a6c69..155627f2c 100644
--- a/include/aidge/operator/Transpose.hpp
+++ b/include/aidge/operator/Transpose.hpp
@@ -67,6 +67,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::vector<DimSize_t>& outputDimsOrder() const noexcept { return mAttributes -> getAttr<TransposeAttr::OutputDimsOrder>(); }
diff --git a/include/aidge/operator/Unfold.hpp b/include/aidge/operator/Unfold.hpp
index 63b802595..09a689528 100644
--- a/include/aidge/operator/Unfold.hpp
+++ b/include/aidge/operator/Unfold.hpp
@@ -77,6 +77,7 @@ public:
     bool forwardDims(bool /*allowDataDependency*/ = false) override final;
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
+    std::set<std::string> getAvailableBackends() const override;
 
     inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
     inline std::array<DimSize_t, DIM>& strideDims() const { return mAttributes->template getAttr<UnfoldAttr::StrideDims>(); }
diff --git a/include/aidge/utils/Registrar.hpp b/include/aidge/utils/Registrar.hpp
index de5f6f80f..0468ae261 100644
--- a/include/aidge/utils/Registrar.hpp
+++ b/include/aidge/utils/Registrar.hpp
@@ -23,7 +23,7 @@
 
 #include <functional>
 #include <map>
-#include <vector>
+#include <set>
 
 namespace Aidge {
 #ifdef PYBIND
@@ -79,10 +79,10 @@ struct Registrar {
         AIDGE_ASSERT(exists(key), "missing or invalid registrar key: {} for registrable object {}\nDid you include/import the corresponding module?\nIf so, it is possible that the object is not yet supported.", key, typeid(C).name());
         return C::registry().at(key);
     }
-    static std::vector<registrar_key> getKeys(){
-        std::vector<registrar_key> keys;
+    static std::set<registrar_key> getKeys(){
+        std::set<registrar_key> keys;
         for(const auto& keyValue : C::registry())
-            keys.push_back(keyValue.first);
+            keys.insert(keyValue.first);
         return keys;
     }
 };
diff --git a/python_binding/backend/pybind_OperatorImpl.cpp b/python_binding/backend/pybind_OperatorImpl.cpp
index be1d26e78..e8a298f24 100644
--- a/python_binding/backend/pybind_OperatorImpl.cpp
+++ b/python_binding/backend/pybind_OperatorImpl.cpp
@@ -53,9 +53,9 @@ public:
         );
     }
 
-    std::vector<ImplSpec> getAvailableImplSpecs() const noexcept override {
+    std::set<ImplSpec> getAvailableImplSpecs() const noexcept override {
         PYBIND11_OVERRIDE_NAME(
-            std::vector<ImplSpec>,
+            std::set<ImplSpec>,
             OperatorImpl,
             "get_available_impl_specs",
             getAvailableImplSpecs
diff --git a/src/backend/OperatorImpl.cpp b/src/backend/OperatorImpl.cpp
index a62da5f8e..9a6929158 100644
--- a/src/backend/OperatorImpl.cpp
+++ b/src/backend/OperatorImpl.cpp
@@ -85,7 +85,8 @@ Aidge::ImplSpec Aidge::OperatorImpl::getRequiredSpec() const {
 Aidge::ImplSpec Aidge::OperatorImpl::getBestMatch(const ImplSpec& requiredSpecs) const {
     Log::debug("getBestMatch() for requirements: {}", requiredSpecs);
 
-    const auto availableSpecs = getAvailableImplSpecs();
+    const auto availableSpecsSet = getAvailableImplSpecs();
+    const std::vector<ImplSpec> availableSpecs(availableSpecsSet.begin(), availableSpecsSet.end());
     std::vector<int> matchingSpecs(availableSpecs.size(), -1);
 
     for (size_t s = 0; s < availableSpecs.size(); ++s) {
@@ -331,8 +332,8 @@ std::shared_ptr<Aidge::Node> Aidge::OperatorImpl::getBestAdaptation(const ImplSp
     using AdaptationCost = int;
     std::map<std::shared_ptr<Node>, AdaptationCost> adaptations;
 
-    for (size_t s = 0; s < availableSpecs.size(); ++s) {
-        auto adaptation = getAdaptation(availableSpecs[s], requiredSpecs);
+    for (const auto& availableSpec : availableSpecs) {
+        auto adaptation = getAdaptation(availableSpec, requiredSpecs);
 
         if (adaptation) {
             auto microGraph = std::dynamic_pointer_cast<MetaOperator_Op>(adaptation->getOperator())->getMicroGraph();
@@ -364,6 +365,6 @@ std::shared_ptr<Aidge::ProdConso> Aidge::OperatorImpl::getProdConso() const {
     return std::make_shared<ProdConso>(mOp);
 }
 
-std::vector<Aidge::ImplSpec> Aidge::OperatorImpl::getAvailableImplSpecs() const {
-    return std::vector<ImplSpec>();
+std::set<Aidge::ImplSpec> Aidge::OperatorImpl::getAvailableImplSpecs() const {
+    return std::set<ImplSpec>();
 }
diff --git a/src/operator/Abs.cpp b/src/operator/Abs.cpp
index a8ee706f6..1dd7836ad 100644
--- a/src/operator/Abs.cpp
+++ b/src/operator/Abs.cpp
@@ -23,3 +23,7 @@ void Aidge::Abs_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     SET_IMPL_MACRO(Abs_Op, *this, name);
     mOutputs[0]->setBackend(name, device);
 }
+
+std::set<std::string> Aidge::Abs_Op::getAvailableBackends() const {
+    return Registrar<Abs_Op>::getKeys();
+}
diff --git a/src/operator/Add.cpp b/src/operator/Add.cpp
index f9dc3335a..033c476c8 100644
--- a/src/operator/Add.cpp
+++ b/src/operator/Add.cpp
@@ -85,6 +85,10 @@ void Aidge::Add_Op::setBackend(const std::string& name, DeviceIdx_t device) {
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Add_Op::getAvailableBackends() const {
+    return Registrar<Add_Op>::getKeys();
+}
+
 std::shared_ptr<Aidge::Node> Aidge::Add(const IOIndex_t nbIn, const std::string& name) {
     return std::make_shared<Node>(std::make_shared<Add_Op>(nbIn), name);
 }
\ No newline at end of file
diff --git a/src/operator/And.cpp b/src/operator/And.cpp
index 43aeebe24..aebd5a717 100644
--- a/src/operator/And.cpp
+++ b/src/operator/And.cpp
@@ -56,3 +56,7 @@ void Aidge::And_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     SET_IMPL_MACRO(And_Op, *this, name);
     mOutputs[0]->setBackend(name, device);
 }
+
+std::set<std::string> Aidge::And_Op::getAvailableBackends() const {
+    return Registrar<And_Op>::getKeys();
+}
diff --git a/src/operator/ArgMax.cpp b/src/operator/ArgMax.cpp
index 58ade4754..4808b730d 100644
--- a/src/operator/ArgMax.cpp
+++ b/src/operator/ArgMax.cpp
@@ -50,4 +50,8 @@ bool Aidge::ArgMax_Op::forwardDims(bool /*allowDataDependency*/) {
 void Aidge::ArgMax_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device) {
     SET_IMPL_MACRO(ArgMax_Op, *this, name);
     mOutputs[0]->setBackend(name, device);
-}
\ No newline at end of file
+}
+
+std::set<std::string> Aidge::ArgMax_Op::getAvailableBackends() const {
+    return Registrar<ArgMax_Op>::getKeys();
+}
diff --git a/src/operator/AvgPooling.cpp b/src/operator/AvgPooling.cpp
index 296ae7891..f8c8e5e3f 100644
--- a/src/operator/AvgPooling.cpp
+++ b/src/operator/AvgPooling.cpp
@@ -113,6 +113,11 @@ void Aidge::AvgPooling_Op<DIM>::setBackend(const std::string &name, Aidge::Devic
     mOutputs[0]->setBackend(name, device);
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::AvgPooling_Op<DIM>::getAvailableBackends() const {
+    return Registrar<AvgPooling_Op<DIM>>::getKeys();
+}
+
 template class Aidge::AvgPooling_Op<1>;
 template class Aidge::AvgPooling_Op<2>;
 template class Aidge::AvgPooling_Op<3>;
diff --git a/src/operator/BatchNorm.cpp b/src/operator/BatchNorm.cpp
index a81cfc132..bcf3b29c4 100644
--- a/src/operator/BatchNorm.cpp
+++ b/src/operator/BatchNorm.cpp
@@ -95,6 +95,11 @@ void Aidge::BatchNorm_Op<DIM>::setBackend(const std::string &name, Aidge::Device
     }
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::BatchNorm_Op<DIM>::getAvailableBackends() const {
+    return Registrar<BatchNorm_Op<DIM>>::getKeys();
+}
+
 template class Aidge::BatchNorm_Op<2>;
 template class Aidge::BatchNorm_Op<3>;
 template class Aidge::BatchNorm_Op<4>;
diff --git a/src/operator/Cast.cpp b/src/operator/Cast.cpp
index b6164a77c..54eef17b6 100644
--- a/src/operator/Cast.cpp
+++ b/src/operator/Cast.cpp
@@ -47,6 +47,10 @@ void Aidge::Cast_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devi
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Cast_Op::getAvailableBackends() const {
+    return Registrar<Cast_Op>::getKeys();
+}
+
 std::shared_ptr<Aidge::Node> Aidge::Cast(const Aidge::DataType targetType, const std::string& name) {
     return std::make_shared<Node>(std::make_shared<Cast_Op>(targetType), name);
 }
\ No newline at end of file
diff --git a/src/operator/Concat.cpp b/src/operator/Concat.cpp
index c78afa866..55efdd51d 100644
--- a/src/operator/Concat.cpp
+++ b/src/operator/Concat.cpp
@@ -134,6 +134,10 @@ void Aidge::Concat_Op::setBackend(const std::string& name, DeviceIdx_t device) {
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Concat_Op::getAvailableBackends() const {
+    return Registrar<Concat_Op>::getKeys();
+}
+
 /////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Concat(const Aidge::IOIndex_t nbIn, const std::int32_t axis, const std::string& name) {
diff --git a/src/operator/Conv.cpp b/src/operator/Conv.cpp
index 92f4ec593..7250d896d 100644
--- a/src/operator/Conv.cpp
+++ b/src/operator/Conv.cpp
@@ -157,6 +157,11 @@ void Aidge::Conv_Op<DIM>::setBackend(const std::string &name, Aidge::DeviceIdx_t
     }
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::Conv_Op<DIM>::getAvailableBackends() const {
+    return Registrar<Conv_Op<DIM>>::getKeys();
+}
+
 template class Aidge::Conv_Op<1>;
 template class Aidge::Conv_Op<2>;
 
diff --git a/src/operator/ConvDepthWise.cpp b/src/operator/ConvDepthWise.cpp
index 9e95e78ea..45a49582f 100644
--- a/src/operator/ConvDepthWise.cpp
+++ b/src/operator/ConvDepthWise.cpp
@@ -156,6 +156,11 @@ void Aidge::ConvDepthWise_Op<DIM>::setBackend(const std::string &name, Aidge::De
     }
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::ConvDepthWise_Op<DIM>::getAvailableBackends() const {
+    return Registrar<ConvDepthWise_Op<DIM>>::getKeys();
+}
+
 template class Aidge::ConvDepthWise_Op<1>;
 template class Aidge::ConvDepthWise_Op<2>;
 
diff --git a/src/operator/DepthToSpace.cpp b/src/operator/DepthToSpace.cpp
index 0c858548e..6b8d05625 100644
--- a/src/operator/DepthToSpace.cpp
+++ b/src/operator/DepthToSpace.cpp
@@ -113,6 +113,10 @@ void Aidge::DepthToSpace_Op::setBackend(const std::string& name, Aidge::DeviceId
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::DepthToSpace_Op::getAvailableBackends() const {
+    return Registrar<DepthToSpace_Op>::getKeys();
+}
+
 //////////////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::DepthToSpace(const std::uint32_t blockSize,
diff --git a/src/operator/Div.cpp b/src/operator/Div.cpp
index 2140b17a3..96eea3df9 100644
--- a/src/operator/Div.cpp
+++ b/src/operator/Div.cpp
@@ -57,6 +57,10 @@ void Aidge::Div_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Div_Op::getAvailableBackends() const {
+    return Registrar<Div_Op>::getKeys();
+}
+
 ///////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Div(const std::string& name) {
diff --git a/src/operator/Erf.cpp b/src/operator/Erf.cpp
index ed1f79f79..bd5f76f8a 100644
--- a/src/operator/Erf.cpp
+++ b/src/operator/Erf.cpp
@@ -38,6 +38,10 @@ void Aidge::Erf_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Erf_Op::getAvailableBackends() const {
+    return Registrar<Erf_Op>::getKeys();
+}
+
 /////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Erf(const std::string& name) {
diff --git a/src/operator/FC.cpp b/src/operator/FC.cpp
index 577a1842d..dd3ed7aba 100644
--- a/src/operator/FC.cpp
+++ b/src/operator/FC.cpp
@@ -91,6 +91,10 @@ void Aidge::FC_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device
     }
 }
 
+std::set<std::string> Aidge::FC_Op::getAvailableBackends() const {
+    return Registrar<FC_Op>::getKeys();
+}
+
 std::shared_ptr<Aidge::Node> Aidge::FC(const Aidge::DimSize_t inChannels,
                                        const Aidge::DimSize_t outChannels,
                                        bool noBias,
diff --git a/src/operator/Fold.cpp b/src/operator/Fold.cpp
index 1a2ec88bb..99ccb7505 100644
--- a/src/operator/Fold.cpp
+++ b/src/operator/Fold.cpp
@@ -82,6 +82,11 @@ void Aidge::Fold_Op<DIM>::setBackend(const std::string &name, Aidge::DeviceIdx_t
     mOutputs[0]->setBackend(name, device);
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::Fold_Op<DIM>::getAvailableBackends() const {
+    return Registrar<Fold_Op<DIM>>::getKeys();
+}
+
 template class Aidge::Fold_Op<2>;
 
 ///////////////////////////////////////
diff --git a/src/operator/Gather.cpp b/src/operator/Gather.cpp
index 00d471f6d..0ebc3e3bc 100644
--- a/src/operator/Gather.cpp
+++ b/src/operator/Gather.cpp
@@ -142,6 +142,10 @@ void Aidge::Gather_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t de
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Gather_Op::getAvailableBackends() const {
+    return Registrar<Gather_Op>::getKeys();
+}
+
 /////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Gather(std::int8_t axis,
diff --git a/src/operator/GlobalAveragePooling.cpp b/src/operator/GlobalAveragePooling.cpp
index e7b2bdffb..bbcfd0d28 100644
--- a/src/operator/GlobalAveragePooling.cpp
+++ b/src/operator/GlobalAveragePooling.cpp
@@ -57,6 +57,10 @@ void Aidge::GlobalAveragePooling_Op::setBackend(const std::string &name, Aidge::
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::GlobalAveragePooling_Op::getAvailableBackends() const {
+    return Registrar<GlobalAveragePooling_Op>::getKeys();
+}
+
 ////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::GlobalAveragePooling(const std::string &name) {
diff --git a/src/operator/GridSample.cpp b/src/operator/GridSample.cpp
index fa1efc75a..d26679f83 100644
--- a/src/operator/GridSample.cpp
+++ b/src/operator/GridSample.cpp
@@ -95,6 +95,10 @@ void Aidge::GridSample_Op::setBackend(const std::string &name, Aidge::DeviceIdx_
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::GridSample_Op::getAvailableBackends() const {
+    return Registrar<GridSample_Op>::getKeys();
+}
+
 
 ////////////////////////////////////////////////
 
diff --git a/src/operator/LeakyReLU.cpp b/src/operator/LeakyReLU.cpp
index 9def23758..dea73f310 100644
--- a/src/operator/LeakyReLU.cpp
+++ b/src/operator/LeakyReLU.cpp
@@ -38,6 +38,10 @@ void Aidge::LeakyReLU_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::LeakyReLU_Op::getAvailableBackends() const {
+    return Registrar<LeakyReLU_Op>::getKeys();
+}
+
 /////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::LeakyReLU(float negativeSlope, const std::string& name) {
diff --git a/src/operator/Ln.cpp b/src/operator/Ln.cpp
index 31012cbb1..90ae8d8c7 100755
--- a/src/operator/Ln.cpp
+++ b/src/operator/Ln.cpp
@@ -38,6 +38,10 @@ void Aidge::Ln_Op::setBackend(const std::string& name, DeviceIdx_t device) {
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Ln_Op::getAvailableBackends() const {
+    return Registrar<Ln_Op>::getKeys();
+}
+
 /////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Ln(const std::string& name) {
diff --git a/src/operator/MatMul.cpp b/src/operator/MatMul.cpp
index c95fe544c..668ffd04b 100644
--- a/src/operator/MatMul.cpp
+++ b/src/operator/MatMul.cpp
@@ -97,6 +97,10 @@ void Aidge::MatMul_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t de
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::MatMul_Op::getAvailableBackends() const {
+    return Registrar<MatMul_Op>::getKeys();
+}
+
 ////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::MatMul(const std::string& name) {
diff --git a/src/operator/MaxPooling.cpp b/src/operator/MaxPooling.cpp
index 85f2dd930..5ce137fe6 100644
--- a/src/operator/MaxPooling.cpp
+++ b/src/operator/MaxPooling.cpp
@@ -83,6 +83,11 @@ void Aidge::MaxPooling_Op<DIM>::setBackend(const std::string &name, Aidge::Devic
     mOutputs[0]->setBackend(name, device);
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::MaxPooling_Op<DIM>::getAvailableBackends() const {
+    return Registrar<MaxPooling_Op<DIM>>::getKeys();
+}
+
 template class Aidge::MaxPooling_Op<1>;
 template class Aidge::MaxPooling_Op<2>;
 template class Aidge::MaxPooling_Op<3>;
diff --git a/src/operator/Memorize.cpp b/src/operator/Memorize.cpp
index 620eed407..c3d64d5bc 100644
--- a/src/operator/Memorize.cpp
+++ b/src/operator/Memorize.cpp
@@ -153,6 +153,10 @@ void Aidge::Memorize_Op::forward() {
     mAttributes->template getAttr<MemorizeAttr::ScheduleStep>() = 0;
 }
 
+std::set<std::string> Aidge::Memorize_Op::getAvailableBackends() const {
+    return Registrar<Memorize_Op>::getKeys();
+}
+
 /////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Memorize(const std::uint32_t endStep, const std::string& name) {
diff --git a/src/operator/MetaOperator.cpp b/src/operator/MetaOperator.cpp
index 1b4c73990..b467628d3 100644
--- a/src/operator/MetaOperator.cpp
+++ b/src/operator/MetaOperator.cpp
@@ -82,6 +82,16 @@ void Aidge::MetaOperator_Op::setBackend(const std::string &name, Aidge::DeviceId
     mGraph->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::MetaOperator_Op::getAvailableBackends() const {
+    std::set<std::string> backendsList;
+    for (const auto& tupleKey : Registrar<MetaOperator_Op>::getKeys()) {
+        if (std::get<1>(tupleKey) == type()) {
+            backendsList.insert(std::get<0>(tupleKey));
+        }
+    }
+    return backendsList;
+}
+
 std::shared_ptr<Aidge::Attributes> Aidge::MetaOperator_Op::attributes() const {
     auto attrs = std::make_shared<DynamicAttributes>();
 
diff --git a/src/operator/Move.cpp b/src/operator/Move.cpp
index 4190c10a0..adabcd0d3 100644
--- a/src/operator/Move.cpp
+++ b/src/operator/Move.cpp
@@ -50,6 +50,15 @@ void Aidge::Move_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devi
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Move_Op::getAvailableBackends() const {
+    std::set<std::string> backendsList;
+    for (const auto& tupleKey : Registrar<Move_Op>::getKeys()) {
+        backendsList.insert(std::get<0>(tupleKey));
+        backendsList.insert(std::get<1>(tupleKey));
+    }
+    return backendsList;
+}
+
 ////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Move(const std::string& name) {
diff --git a/src/operator/Mul.cpp b/src/operator/Mul.cpp
index e2e32805f..3f163c9d6 100644
--- a/src/operator/Mul.cpp
+++ b/src/operator/Mul.cpp
@@ -71,6 +71,10 @@ void Aidge::Mul_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Mul_Op::getAvailableBackends() const {
+    return Registrar<Mul_Op>::getKeys();
+}
+
 ///////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Mul(const std::string& name) {
diff --git a/src/operator/Pad.cpp b/src/operator/Pad.cpp
index 5b1428c16..39f61e328 100644
--- a/src/operator/Pad.cpp
+++ b/src/operator/Pad.cpp
@@ -53,6 +53,11 @@ void Aidge::Pad_Op<DIM>::setBackend(const std::string &name, Aidge::DeviceIdx_t
     mOutputs[0]->setBackend(name, device);
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::Pad_Op<DIM>::getAvailableBackends() const {
+    return Registrar<Pad_Op<DIM>>::getKeys();
+}
+
 template class Aidge::Pad_Op<1>;
 template class Aidge::Pad_Op<2>;
 
diff --git a/src/operator/Pop.cpp b/src/operator/Pop.cpp
index 70193d38b..cd5b18759 100644
--- a/src/operator/Pop.cpp
+++ b/src/operator/Pop.cpp
@@ -88,6 +88,10 @@ void Aidge::Pop_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Pop_Op::getAvailableBackends() const {
+    return Registrar<Pop_Op>::getKeys();
+}
+
 void Aidge::Pop_Op::forward() {
     Operator::forward();
     ++mAttributes->template getAttr<PopAttr::ForwardStep>();
diff --git a/src/operator/Pow.cpp b/src/operator/Pow.cpp
index 1602c8c2a..ada71d6cc 100644
--- a/src/operator/Pow.cpp
+++ b/src/operator/Pow.cpp
@@ -56,6 +56,10 @@ void Aidge::Pow_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Pow_Op::getAvailableBackends() const {
+    return Registrar<Pow_Op>::getKeys();
+}
+
 ////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Pow(const std::string& name) {
diff --git a/src/operator/Producer.cpp b/src/operator/Producer.cpp
index e5c4a3e9e..fdba4ac2e 100644
--- a/src/operator/Producer.cpp
+++ b/src/operator/Producer.cpp
@@ -84,6 +84,10 @@ void Aidge::Producer_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Producer_Op::getAvailableBackends() const {
+    return Registrar<Producer_Op>::getKeys();
+}
+
 void Aidge::Producer_Op::forward() {
     if (!backend().empty()) {
         mImpl->forward();
diff --git a/src/operator/ReLU.cpp b/src/operator/ReLU.cpp
index 03f9e0679..bda26fa33 100644
--- a/src/operator/ReLU.cpp
+++ b/src/operator/ReLU.cpp
@@ -38,6 +38,10 @@ void Aidge::ReLU_Op::setBackend(const std::string& name, DeviceIdx_t device) {
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::ReLU_Op::getAvailableBackends() const {
+    return Registrar<ReLU_Op>::getKeys();
+}
+
 /////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::ReLU(const std::string& name) {
diff --git a/src/operator/ReduceMean.cpp b/src/operator/ReduceMean.cpp
index 34bba95b0..7935edb05 100644
--- a/src/operator/ReduceMean.cpp
+++ b/src/operator/ReduceMean.cpp
@@ -94,6 +94,10 @@ void Aidge::ReduceMean_Op::setBackend(const std::string& name, Aidge::DeviceIdx_
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::ReduceMean_Op::getAvailableBackends() const {
+    return Registrar<ReduceMean_Op>::getKeys();
+}
+
 Aidge::ReduceMean_Op::~ReduceMean_Op() noexcept = default;
 
 ////////////////////////////////////////////
diff --git a/src/operator/ReduceSum.cpp b/src/operator/ReduceSum.cpp
index aa8271f4c..0786f53c6 100644
--- a/src/operator/ReduceSum.cpp
+++ b/src/operator/ReduceSum.cpp
@@ -69,4 +69,8 @@ bool Aidge::ReduceSum_Op::forwardDims(bool /*allowDataDependency*/) {
 void Aidge::ReduceSum_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device) {
     SET_IMPL_MACRO(ReduceSum_Op, *this, name);
     mOutputs[0]->setBackend(name, device);
-}
\ No newline at end of file
+}
+
+std::set<std::string> Aidge::ReduceSum_Op::getAvailableBackends() const {
+    return Registrar<ReduceSum_Op>::getKeys();
+}
diff --git a/src/operator/Reshape.cpp b/src/operator/Reshape.cpp
index 5139a0b0c..0fa9a6281 100644
--- a/src/operator/Reshape.cpp
+++ b/src/operator/Reshape.cpp
@@ -136,6 +136,10 @@ void Aidge::Reshape_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t d
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Reshape_Op::getAvailableBackends() const {
+    return Registrar<Reshape_Op>::getKeys();
+}
+
 //////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Reshape(const std::vector<std::int64_t>& shape,
diff --git a/src/operator/Resize.cpp b/src/operator/Resize.cpp
index f3a69848e..9e5762452 100644
--- a/src/operator/Resize.cpp
+++ b/src/operator/Resize.cpp
@@ -149,6 +149,10 @@ void Aidge::Resize_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t de
     }
 }
 
+std::set<std::string> Aidge::Resize_Op::getAvailableBackends() const {
+    return Registrar<Resize_Op>::getKeys();
+}
+
 /////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Resize(const std::string &name) {
diff --git a/src/operator/Scaling.cpp b/src/operator/Scaling.cpp
index a53695b58..5ac08cd22 100644
--- a/src/operator/Scaling.cpp
+++ b/src/operator/Scaling.cpp
@@ -48,6 +48,10 @@ void Aidge::Scaling_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t d
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Scaling_Op::getAvailableBackends() const {
+    return Registrar<Scaling_Op>::getKeys();
+}
+
 ////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Scaling(float scalingFactor,
diff --git a/src/operator/Shape.cpp b/src/operator/Shape.cpp
index f2ad10059..29a9ee625 100644
--- a/src/operator/Shape.cpp
+++ b/src/operator/Shape.cpp
@@ -91,6 +91,10 @@ void Aidge::Shape_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t dev
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Shape_Op::getAvailableBackends() const {
+    return Registrar<Shape_Op>::getKeys();
+}
+
 //////////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Shape(const std::int64_t start, const std::int64_t end, const std::string& name) {
diff --git a/src/operator/ShiftGELU.cpp b/src/operator/ShiftGELU.cpp
index 63480ffcc..bd229e6cf 100644
--- a/src/operator/ShiftGELU.cpp
+++ b/src/operator/ShiftGELU.cpp
@@ -42,6 +42,10 @@ void Aidge::ShiftGELU_Op::setBackend(const std::string& name, DeviceIdx_t device
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::ShiftGELU_Op::getAvailableBackends() const {
+    return Registrar<ShiftGELU_Op>::getKeys();
+}
+
 ///////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::ShiftGELU(const std::string& name) {
diff --git a/src/operator/ShiftMax.cpp b/src/operator/ShiftMax.cpp
index 5b0dd7ace..58d4bf461 100644
--- a/src/operator/ShiftMax.cpp
+++ b/src/operator/ShiftMax.cpp
@@ -46,6 +46,10 @@ void Aidge::ShiftMax_Op::setBackend(const std::string& name, DeviceIdx_t device)
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::ShiftMax_Op::getAvailableBackends() const {
+    return Registrar<ShiftMax_Op>::getKeys();
+}
+
 /////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::ShiftMax(const std::string& name) {
diff --git a/src/operator/Sigmoid.cpp b/src/operator/Sigmoid.cpp
index aa112378f..d97f8c523 100644
--- a/src/operator/Sigmoid.cpp
+++ b/src/operator/Sigmoid.cpp
@@ -42,6 +42,10 @@ void Aidge::Sigmoid_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t d
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Sigmoid_Op::getAvailableBackends() const {
+    return Registrar<Sigmoid_Op>::getKeys();
+}
+
 ///////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Sigmoid(const std::string& name) {
diff --git a/src/operator/Slice.cpp b/src/operator/Slice.cpp
index bd7a4750d..3bdee8c13 100644
--- a/src/operator/Slice.cpp
+++ b/src/operator/Slice.cpp
@@ -212,6 +212,10 @@ void Aidge::Slice_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t dev
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Slice_Op::getAvailableBackends() const {
+    return Registrar<Slice_Op>::getKeys();
+}
+
 ////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Slice(const std::vector<std::int64_t>& starts,
diff --git a/src/operator/Softmax.cpp b/src/operator/Softmax.cpp
index f425d6fff..ad894c5e5 100644
--- a/src/operator/Softmax.cpp
+++ b/src/operator/Softmax.cpp
@@ -46,6 +46,10 @@ void Aidge::Softmax_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t d
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Softmax_Op::getAvailableBackends() const {
+    return Registrar<Softmax_Op>::getKeys();
+}
+
 ////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Softmax(std::int32_t axis, const std::string& name) {
diff --git a/src/operator/Split.cpp b/src/operator/Split.cpp
index 9c56c6a2a..c4698f83c 100644
--- a/src/operator/Split.cpp
+++ b/src/operator/Split.cpp
@@ -167,6 +167,10 @@ void Aidge::Split_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t dev
 
 }
 
+std::set<std::string> Aidge::Split_Op::getAvailableBackends() const {
+    return Registrar<Split_Op>::getKeys();
+}
+
 ////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Split(Aidge::DimSize_t nbOutput,
diff --git a/src/operator/Sqrt.cpp b/src/operator/Sqrt.cpp
index 3af75a6ca..bd3286f09 100644
--- a/src/operator/Sqrt.cpp
+++ b/src/operator/Sqrt.cpp
@@ -41,6 +41,10 @@ void Aidge::Sqrt_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devi
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Sqrt_Op::getAvailableBackends() const {
+    return Registrar<Sqrt_Op>::getKeys();
+}
+
 ////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Sqrt(const std::string& name) {
diff --git a/src/operator/Sub.cpp b/src/operator/Sub.cpp
index ee4fd5b08..ca7348b3b 100644
--- a/src/operator/Sub.cpp
+++ b/src/operator/Sub.cpp
@@ -72,6 +72,10 @@ void Aidge::Sub_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devic
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Sub_Op::getAvailableBackends() const {
+    return Registrar<Sub_Op>::getKeys();
+}
+
 //////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Sub(const std::string& name) {
diff --git a/src/operator/Tanh.cpp b/src/operator/Tanh.cpp
index 1f936b6c8..fe295ab71 100644
--- a/src/operator/Tanh.cpp
+++ b/src/operator/Tanh.cpp
@@ -41,6 +41,10 @@ void Aidge::Tanh_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t devi
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Tanh_Op::getAvailableBackends() const {
+    return Registrar<Tanh_Op>::getKeys();
+}
+
 ////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Tanh(const std::string& name) {
diff --git a/src/operator/Transpose.cpp b/src/operator/Transpose.cpp
index bd1acee8a..0cb1717f1 100644
--- a/src/operator/Transpose.cpp
+++ b/src/operator/Transpose.cpp
@@ -79,6 +79,10 @@ void Aidge::Transpose_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t
     mOutputs[0]->setBackend(name, device);
 }
 
+std::set<std::string> Aidge::Transpose_Op::getAvailableBackends() const {
+    return Registrar<Transpose_Op>::getKeys();
+}
+
 //////////////////////////////////////////////////
 
 std::shared_ptr<Aidge::Node> Aidge::Transpose(const std::vector<Aidge::DimSize_t> &outputDimsOrder,
diff --git a/src/operator/Unfold.cpp b/src/operator/Unfold.cpp
index 2b12f3358..53b8bd544 100644
--- a/src/operator/Unfold.cpp
+++ b/src/operator/Unfold.cpp
@@ -138,6 +138,11 @@ void Aidge::Unfold_Op<DIM>::setBackend(const std::string &name, Aidge::DeviceIdx
     mOutputs[0]->setBackend(name, device);
 }
 
+template <Aidge::DimIdx_t DIM>
+std::set<std::string> Aidge::Unfold_Op<DIM>::getAvailableBackends() const {
+    return Registrar<Unfold_Op<DIM>>::getKeys();
+}
+
 template class Aidge::Unfold_Op<2>;
 
 ///////////////////////////////////////////////////////////
-- 
GitLab