xref: /aosp_15_r20/external/armnn/src/armnn/SubgraphView.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017, 2019-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnn/backends/SubgraphView.hpp>
7 
8 #include <Graph.hpp>
9 
10 #include <armnn/utility/IgnoreUnused.hpp>
11 #include <armnn/utility/NumericCast.hpp>
12 #include <armnn/utility/PolymorphicDowncast.hpp>
13 
14 #include <fmt/format.h>
15 #include <utility>
16 
17 namespace armnn
18 {
19 
20 namespace
21 {
22 
23 template <class C>
AssertIfNullsOrDuplicates(const C & container,const std::string & errorMessage)24 void AssertIfNullsOrDuplicates(const C& container, const std::string& errorMessage)
25 {
26     using T = typename C::value_type;
27     std::unordered_set<T> duplicateSet;
28     std::for_each(container.begin(), container.end(), [&duplicateSet, &errorMessage](const T& i)
29     {
30         // Ignore unused for release builds
31         IgnoreUnused(errorMessage);
32 
33         // Check if the item is valid
34         ARMNN_ASSERT_MSG(i, errorMessage.c_str());
35 
36         // Check if a duplicate has been found
37         ARMNN_ASSERT_MSG(duplicateSet.find(i) == duplicateSet.end(), errorMessage.c_str());
38 
39         duplicateSet.insert(i);
40     });
41 }
42 
43 } // anonymous namespace
44 
SubgraphView(Graph & graph)45 SubgraphView::SubgraphView(Graph& graph)
46     : enable_shared_from_this()
47     , m_InputSlots{}
48     , m_OutputSlots{}
49     , m_Layers(graph.begin(), graph.end())
50     , m_IConnectableLayers(graph.begin(), graph.end())
51 {
52     ArrangeBySortOrder();
53     CheckSubgraph();
54 }
55 
56 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(InputSlots && inputs,OutputSlots && outputs,Layers && layers)57 SubgraphView::SubgraphView(InputSlots&& inputs, OutputSlots&& outputs, Layers&& layers)
58     : enable_shared_from_this()
59     , m_InputSlots{InputSlots{inputs.begin(), inputs.end()}}
60     , m_IInputSlots{IInputSlots{inputs.begin(), inputs.end()}}
61     , m_OutputSlots{OutputSlots{outputs.begin(), outputs.end()}}
62     , m_IOutputSlots{IOutputSlots{outputs.begin(), outputs.end()}}
63     , m_Layers(layers)
64     , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
65 {
66     ArrangeBySortOrder();
67     CheckSubgraph();
68 }
69 
70 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(SubgraphView::IConnectableLayers && layers,SubgraphView::IInputSlots && inputs,SubgraphView::IOutputSlots && outputs)71 SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers,
72                            SubgraphView::IInputSlots&& inputs,
73                            SubgraphView::IOutputSlots&& outputs)
74         : enable_shared_from_this()
75         , m_IInputSlots{inputs}
76         , m_IOutputSlots{outputs}
77         , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
78 {
79     // Cast from IConnectableLayer to Layer for backward compatibility
80     auto f = [](IConnectableLayer* value)
__anon0060705c0302(IConnectableLayer* value) 81     {
82         return PolymorphicDowncast<Layer*>(value);
83     };
84     std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
85 
86     m_InputSlots.resize(inputs.size());
87     m_IInputSlots.resize(inputs.size());
88     for (unsigned int i = 0; i < inputs.size(); i++)
89     {
90         m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
91         m_IInputSlots.at(i) = inputs[i];
92     }
93 
94     m_OutputSlots.resize(outputs.size());
95     m_IOutputSlots.resize(outputs.size());
96     for (unsigned int i = 0; i < outputs.size(); i++)
97     {
98         m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
99         m_IOutputSlots.at(i) = outputs[i];
100     }
101 
102     ArrangeBySortOrder();
103     CheckSubgraph();
104 }
105 
106 /// IConnectable Duplication to maintain backwards compatibility
SubgraphView(SubgraphView::IConnectableLayers && layers,SubgraphView::IInputSlots && inputs,SubgraphView::IOutputSlots && outputs,std::shared_ptr<SubgraphViewWorkingCopy> ptr)107 SubgraphView::SubgraphView(SubgraphView::IConnectableLayers&& layers,
108                            SubgraphView::IInputSlots&& inputs,
109                            SubgraphView::IOutputSlots&& outputs,
110                            std::shared_ptr<SubgraphViewWorkingCopy> ptr)
111         : enable_shared_from_this()
112         , m_IInputSlots{inputs}
113         , m_IOutputSlots{outputs}
114         , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
115         , p_WorkingCopyImpl(std::move(ptr))
116 {
117     // Cast from IConnectableLayer to Layer for backward compatibility
118     auto f = [](IConnectableLayer* value)
__anon0060705c0402(IConnectableLayer* value) 119     {
120         return PolymorphicDowncast<Layer*>(value);
121     };
122     std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
123 
124     m_InputSlots.resize(inputs.size());
125     m_IInputSlots.resize(inputs.size());
126     for (unsigned int i = 0; i < inputs.size(); i++)
127     {
128         m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
129         m_IInputSlots.at(i) = inputs[i];
130     }
131 
132     m_OutputSlots.resize(outputs.size());
133     m_IOutputSlots.resize(outputs.size());
134     for (unsigned int i = 0; i < outputs.size(); i++)
135     {
136         m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
137         m_IOutputSlots.at(i) = outputs[i];
138     }
139 
140     ArrangeBySortOrder();
141     CheckSubgraph();
142 }
143 
SubgraphView(const SubgraphView & subgraph)144 SubgraphView::SubgraphView(const SubgraphView& subgraph)
145     : enable_shared_from_this()
146     , m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end())
147     , m_IInputSlots(subgraph.m_IInputSlots.begin(), subgraph.m_IInputSlots.end())
148     , m_OutputSlots(subgraph.m_OutputSlots.begin(), subgraph.m_OutputSlots.end())
149     , m_IOutputSlots(subgraph.m_IOutputSlots.begin(), subgraph.m_IOutputSlots.end())
150     , m_Layers(subgraph.m_Layers.begin(), subgraph.m_Layers.end())
151     , m_IConnectableLayers(IConnectableLayers{subgraph.m_IConnectableLayers.begin(),
152                                               subgraph.m_IConnectableLayers.end()})
153 {
154     ArrangeBySortOrder();
155     CheckSubgraph();
156 }
157 
SubgraphView(SubgraphView && subgraph)158 SubgraphView::SubgraphView(SubgraphView&& subgraph)
159     : enable_shared_from_this()
160     , m_InputSlots(std::move(subgraph.m_InputSlots))
161     , m_IInputSlots(std::move(subgraph.m_IInputSlots))
162     , m_OutputSlots(std::move(subgraph.m_OutputSlots))
163     , m_IOutputSlots(std::move(subgraph.m_IOutputSlots))
164     , m_Layers(std::move(subgraph.m_Layers))
165     , m_IConnectableLayers(std::move(subgraph.m_IConnectableLayers))
166 {
167     ArrangeBySortOrder();
168     CheckSubgraph();
169 }
170 
SubgraphView(IConnectableLayer * layer)171 SubgraphView::SubgraphView(IConnectableLayer* layer)
172     : enable_shared_from_this()
173     , m_Layers{PolymorphicDowncast<Layer*>(layer)}
174     , m_IConnectableLayers{layer}
175 {
176     unsigned int numInputSlots = layer->GetNumInputSlots();
177     m_InputSlots.resize(numInputSlots);
178     m_IInputSlots.resize(numInputSlots);
179     for (unsigned int i = 0; i < numInputSlots; i++)
180     {
181         m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(&(layer->GetInputSlot(i)));
182         m_IInputSlots.at(i) = &(layer->GetInputSlot(i));
183     }
184 
185     unsigned int numOutputSlots = layer->GetNumOutputSlots();
186     m_OutputSlots.resize(numOutputSlots);
187     m_IOutputSlots.resize(numOutputSlots);
188     for (unsigned int i = 0; i < numOutputSlots; i++)
189     {
190         m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(&(layer->GetOutputSlot(i)));
191         m_IOutputSlots.at(i) = &(layer->GetOutputSlot(i));
192     }
193 
194     CheckSubgraph();
195 }
196 
operator =(SubgraphView && other)197 SubgraphView& SubgraphView::operator=(SubgraphView&& other)
198 {
199     m_InputSlots = std::move(other.m_InputSlots);
200     m_IInputSlots = std::move(other.m_IInputSlots);
201     m_OutputSlots = std::move(other.m_OutputSlots);
202     m_IOutputSlots = std::move(other.m_IOutputSlots);
203     m_Layers = std::move(other.m_Layers);
204     m_IConnectableLayers = std::move(other.m_IConnectableLayers);
205 
206     CheckSubgraph();
207 
208     return *this;
209 }
210 
CheckSubgraph()211 void SubgraphView::CheckSubgraph()
212 {
213     // Check for invalid or duplicate input slots
214     AssertIfNullsOrDuplicates(m_InputSlots, "Sub-graphs cannot contain null or duplicate input slots");
215 
216     // Check for invalid or duplicate output slots
217     AssertIfNullsOrDuplicates(m_OutputSlots, "Sub-graphs cannot contain null or duplicate output slots");
218 
219     // Check for invalid or duplicate layers
220     AssertIfNullsOrDuplicates(m_Layers, "Sub-graphs cannot contain null or duplicate layers");
221 
222     // Check for invalid or duplicate input slots
223     AssertIfNullsOrDuplicates(m_IInputSlots, "Sub-graphs cannot contain null or duplicate IInputSlots");
224 
225     // Check for invalid or duplicate output slots
226     AssertIfNullsOrDuplicates(m_IOutputSlots, "Sub-graphs cannot contain null or duplicate IOutputSlots");
227 
228     // Check for invalid or duplicate layers
229     AssertIfNullsOrDuplicates(m_IConnectableLayers,
230                               "Sub-graphs cannot contain null or duplicate IConnectableLayers");
231 }
232 
GetInputSlots() const233 const SubgraphView::InputSlots& SubgraphView::GetInputSlots() const
234 {
235     return m_InputSlots;
236 }
237 
GetIInputSlots() const238 const SubgraphView::IInputSlots& SubgraphView::GetIInputSlots() const
239 {
240     return m_IInputSlots;
241 }
242 
GetOutputSlots() const243 const SubgraphView::OutputSlots& SubgraphView::GetOutputSlots() const
244 {
245     return m_OutputSlots;
246 }
247 
GetIOutputSlots() const248 const SubgraphView::IOutputSlots& SubgraphView::GetIOutputSlots() const
249 {
250     return m_IOutputSlots;
251 }
252 
GetInputSlot(unsigned int index) const253 const InputSlot* SubgraphView::GetInputSlot(unsigned int index) const
254 {
255     return m_InputSlots.at(index);
256 }
257 
GetIInputSlot(unsigned int index) const258 const IInputSlot* SubgraphView::GetIInputSlot(unsigned int index) const
259 {
260     return m_IInputSlots.at(index);
261 }
262 
GetInputSlot(unsigned int index)263 InputSlot* SubgraphView::GetInputSlot(unsigned int index)
264 {
265     return m_InputSlots.at(index);
266 }
267 
GetIInputSlot(unsigned int index)268 IInputSlot* SubgraphView::GetIInputSlot(unsigned int index)
269 {
270     return m_IInputSlots.at(index);
271 }
272 
GetOutputSlot(unsigned int index) const273 const OutputSlot* SubgraphView::GetOutputSlot(unsigned int index) const
274 {
275     return m_OutputSlots.at(index);
276 }
277 
GetIOutputSlot(unsigned int index) const278 const IOutputSlot* SubgraphView::GetIOutputSlot(unsigned int index) const
279 {
280     return m_IOutputSlots.at(index);
281 }
282 
GetOutputSlot(unsigned int index)283 OutputSlot* SubgraphView::GetOutputSlot(unsigned int index)
284 {
285     return m_OutputSlots.at(index);
286 }
287 
GetIOutputSlot(unsigned int index)288 IOutputSlot* SubgraphView::GetIOutputSlot(unsigned int index)
289 {
290     return m_IOutputSlots.at(index);
291 }
292 
GetNumInputSlots() const293 unsigned int SubgraphView::GetNumInputSlots() const
294 {
295     return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
296 }
297 
GetNumOutputSlots() const298 unsigned int SubgraphView::GetNumOutputSlots() const
299 {
300     return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
301 }
302 
GetLayers() const303 const SubgraphView::Layers& SubgraphView::GetLayers() const
304 {
305     return m_Layers;
306 }
307 
GetIConnectableLayers() const308 const SubgraphView::IConnectableLayers& SubgraphView::GetIConnectableLayers() const
309 {
310     return m_IConnectableLayers;
311 }
312 
begin()313 SubgraphView::Iterator SubgraphView::begin()
314 {
315     return m_Layers.begin();
316 }
317 
end()318 SubgraphView::Iterator SubgraphView::end()
319 {
320     return m_Layers.end();
321 }
322 
323 // IConnectable Duplication to maintain backwards compatibility
beginIConnectable()324 SubgraphView::IConnectableLayerIterator SubgraphView::beginIConnectable()
325 {
326     return m_IConnectableLayers.begin();
327 }
328 
endIConnectable()329 SubgraphView::IConnectableLayerIterator SubgraphView::endIConnectable()
330 {
331     return m_IConnectableLayers.end();
332 }
333 
begin() const334 SubgraphView::ConstIterator SubgraphView::begin() const
335 {
336     return m_Layers.begin();
337 }
338 
end() const339 SubgraphView::ConstIterator SubgraphView::end() const
340 {
341     return m_Layers.end();
342 }
343 
344 // IConnectable Duplication to maintain backwards compatibility
beginIConnectable() const345 SubgraphView::ConstIConnectableIterator SubgraphView::beginIConnectable() const
346 {
347     return m_IConnectableLayers.begin();
348 }
349 
endIConnectable() const350 SubgraphView::ConstIConnectableIterator SubgraphView::endIConnectable() const
351 {
352     return m_IConnectableLayers.end();
353 }
354 
cbegin() const355 SubgraphView::ConstIterator SubgraphView::cbegin() const
356 {
357     // Ignore deprecated call as this is internal to SubgraphView
358     ARMNN_NO_DEPRECATE_WARN_BEGIN
359     return begin();
360     ARMNN_NO_DEPRECATE_WARN_END
361 }
362 
cend() const363 SubgraphView::ConstIterator SubgraphView::cend() const
364 {
365     // Ignore deprecated call as this is internal to SubgraphView
366     ARMNN_NO_DEPRECATE_WARN_BEGIN
367     return end();
368     ARMNN_NO_DEPRECATE_WARN_END
369 }
370 
371 // IConnectable Duplication to maintain backwards compatibility
cbeginIConnectable() const372 SubgraphView::ConstIConnectableIterator SubgraphView::cbeginIConnectable() const
373 {
374     return beginIConnectable();
375 }
376 
cendIConnectable() const377 SubgraphView::ConstIConnectableIterator SubgraphView::cendIConnectable() const
378 {
379     return endIConnectable();
380 }
381 
Clear()382 void SubgraphView::Clear()
383 {
384     m_InputSlots.clear();
385     m_OutputSlots.clear();
386     m_Layers.clear();
387 
388     m_IInputSlots.clear();
389     m_IOutputSlots.clear();
390     m_IConnectableLayers.clear();
391 }
392 
ArrangeBySortOrder()393 void SubgraphView::ArrangeBySortOrder()
394 {
395     using LayerList = std::list<Layer*>;
396     auto compareLayerPriority = [](const LayerList::value_type& layerA, const LayerList::value_type& layerB)
397         {
398             return layerA->GetPriority() < layerB->GetPriority();
399         };
400 
401     m_Layers.sort(compareLayerPriority);
402 
403     using IConnectableLayersList = std::list<IConnectableLayer*>;
404     auto compareIConnectableLayerPriority = [](const IConnectableLayersList::value_type& layerA,
405                                                const IConnectableLayersList::value_type& layerB)
406         {
407             return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
408                    PolymorphicDowncast<Layer*>(layerB)->GetPriority();
409         };
410 
411     m_IConnectableLayers.sort(compareIConnectableLayerPriority);
412 }
413 
414 struct SubgraphView::SubgraphViewWorkingCopy
415 {
416 public:
417 
418     SubgraphViewWorkingCopy() = default;
SubgraphViewWorkingCopyarmnn::SubgraphView::SubgraphViewWorkingCopy419     SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView)
420                             : m_Graph(graph)
421                             , m_OriginalSubgraphView(originalSubgraphView)
422     {};
423 
424     Graph m_Graph;
425     std::shared_ptr<const SubgraphView> m_OriginalSubgraphView;
426 
427 };
428 
GetWorkingCopy() const429 SubgraphView SubgraphView::GetWorkingCopy() const
430 {
431     if (p_WorkingCopyImpl)
432     {
433         throw Exception("The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
434                         "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
435     }
436 
437     // Create a cut down SubgraphView with underlying graph containing only the relevant layers.
438     // It needs its own underlying layers so that they can be replaced safely.
439     auto ptr = std::make_shared<SubgraphViewWorkingCopy>(Graph(), shared_from_this());
440 
441     std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
442     std::list<armnn::IConnectableLayer*> originalSubgraphLayers = GetIConnectableLayers();
443 
444     for (auto&& originalLayer : originalSubgraphLayers)
445     {
446         Layer* const layer = PolymorphicDowncast<const Layer*>(originalLayer)->Clone(ptr->m_Graph);
447         originalToClonedLayerMap.emplace(originalLayer, layer);
448     }
449 
450     SubgraphView::IInputSlots workingCopyInputs;
451     // Add IInputSlots to workingCopy
452     for (auto originalSubgraphInputSlot : GetIInputSlots())
453     {
454         const IConnectableLayer& originalSubgraphLayer =
455                 PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
456 
457         auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
458 
459         workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
460     }
461 
462     for (auto originalSubgraphLayer : originalSubgraphLayers)
463     {
464         IConnectableLayer* const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
465 
466         // OutputLayers have no OutputSlots to be connected
467         if (clonedLayer->GetType() != LayerType::Output)
468         {
469             // connect all cloned layers as per original subgraph
470             for (unsigned int i = 0; i < clonedLayer->GetNumOutputSlots(); i++)
471             {
472                 auto& originalOutputSlot = originalSubgraphLayer->GetOutputSlot(i);
473                 auto& clonedOutputSlot   = clonedLayer->GetOutputSlot(i);
474                 for (unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
475                 {
476                     // nextLayer is the layer with IInputSlot connected to IOutputSlot we are working on
477                     const IConnectableLayer& nextLayerOnOriginalSubgraph =
478                             originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
479 
480                     // Check the layer is in our map and so has a clonedLayer
481                     if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
482                     {
483                         auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
484 
485                         auto index = PolymorphicDowncast<OutputSlot*>(
486                                 &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
487 
488                         IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
489 
490                         // Then make the connection
491                         clonedOutputSlot.Connect(inputSlot);
492                     }
493                 }
494                 // Copy the tensorInfo to the clonedOutputSlot
495                 clonedOutputSlot.SetTensorInfo(originalOutputSlot.GetTensorInfo());
496             }
497         }
498     }
499 
500     SubgraphView::IOutputSlots workingCopyOutputs;
501 
502     // Add IOutputSlots to workingCopy
503     for (auto outputSlot : GetIOutputSlots())
504     {
505         auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
506         const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
507 
508         // OutputLayers have no OutputSlots to be connected
509         if (originalSubgraphLayer.GetType() != LayerType::Output)
510         {
511             IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
512 
513             // Add the OutputSlot of clonedLayer to WorkingCopy OutputSlots
514             workingCopyOutputs.push_back(&clonedLayer->GetOutputSlot(outputSlotIndex));
515         }
516     }
517 
518     SubgraphView::IConnectableLayers workingCopyLayers;
519     for (auto& pair : originalToClonedLayerMap)
520     {
521         workingCopyLayers.push_back(pair.second);
522     }
523 
524     return {std::move(workingCopyLayers),
525             std::move(workingCopyInputs),
526             std::move(workingCopyOutputs),
527             ptr};
528 }
529 
SubstituteSubgraph(SubgraphView & subgraph,IConnectableLayer * substituteLayer)530 void SubgraphView::SubstituteSubgraph(SubgraphView& subgraph, IConnectableLayer* substituteLayer)
531 {
532     ARMNN_ASSERT(substituteLayer != nullptr);
533     SubgraphView substituteSubgraph(substituteLayer);
534 
535     SubstituteSubgraph(subgraph, substituteSubgraph);
536 }
537 
UpdateSubgraphViewSlotPointers(SubgraphView & patternSubgraph,const SubgraphView & substituteSubgraph)538 void SubgraphView::UpdateSubgraphViewSlotPointers(SubgraphView& patternSubgraph,
539                                                   const SubgraphView& substituteSubgraph)
540 {
541     std::vector<IInputSlot*>::iterator inputSlotPosition;
542     // search for and erase any InputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
543     for (unsigned long idx = 0; idx < patternSubgraph.GetIInputSlots().size(); idx++)
544     {
545         IInputSlot *slot = patternSubgraph.GetIInputSlots()[idx];
546         inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
547         if (inputSlotPosition != m_IInputSlots.end())
548         {
549             m_IInputSlots.erase(inputSlotPosition);
550 
551             // while here, with correct position, add in replacement InputSlot from the substituteSubgraph
552             m_IInputSlots.insert(inputSlotPosition, substituteSubgraph.GetIInputSlots()[idx]);
553         }
554     }
555 
556     std::vector<IOutputSlot*>::iterator outputSlotPosition;
557     // search for and erase any OutputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
558     for (unsigned long idx = 0; idx < patternSubgraph.GetIOutputSlots().size(); idx++)
559     {
560         IOutputSlot *slot = patternSubgraph.GetIOutputSlots()[idx];
561         outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
562         if (outputSlotPosition != m_IOutputSlots.end())
563         {
564             m_IOutputSlots.erase(outputSlotPosition);
565 
566             // while here, with correct position, add in replacement OutputSlot from the substituteSubgraph
567             m_IOutputSlots.insert(outputSlotPosition, substituteSubgraph.GetIOutputSlots()[idx]);
568         }
569     }
570 }
571 
SubstituteSubgraph(SubgraphView & patternSubgraph,const SubgraphView & substituteSubgraph)572 void SubgraphView::SubstituteSubgraph(SubgraphView& patternSubgraph, const SubgraphView& substituteSubgraph)
573 {
574     if (!p_WorkingCopyImpl)
575     {
576         throw NullPointerException("The SubgraphView calling SubstituteSubgraphView is not a working copy. "
577                                    "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
578     }
579 
580     auto numPatternInputs = patternSubgraph.GetIInputSlots().size();
581     auto numSubInputs = substituteSubgraph.GetIInputSlots().size();
582     if (numPatternInputs != numSubInputs)
583     {
584         throw armnn::InvalidArgumentException(
585            fmt::format("Number of InputSlots on substitute SubgraphView ({}) must equal the number of"
586                        " InputSlots on pattern SubgraphView ({})",
587                        numSubInputs,
588                        numPatternInputs));
589     }
590 
591     auto numPatternOutputs = patternSubgraph.GetIOutputSlots().size();
592     auto numSubOutputs = substituteSubgraph.GetIOutputSlots().size();
593     if (numPatternOutputs != numSubOutputs)
594     {
595         throw armnn::InvalidArgumentException(
596            fmt::format("Number of OutputSlots on substitute SubgraphView ({}) must equal the number of"
597                        " OutputSlots on pattern SubgraphView ({})",
598                        numSubOutputs,
599                        numPatternOutputs));
600     }
601 
602     // Add substitute layer to the Main graph i.e. graph in p_WorkingCopyImpl
603     auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
604     substituteSubgraph.ForEachIConnectableLayer([workingCopyGraph](IConnectableLayer* iConnectableLayer)
605                                                 {
606                                                     // Search WorkingCopy Graph for substituteLayer and add if missing
607                                                     if (std::find(std::begin(workingCopyGraph->m_Layers),
608                                                                   std::end(workingCopyGraph->m_Layers),
609                                                                   iConnectableLayer) ==
610                                                         std::end(workingCopyGraph->m_Layers))
611                                                     {
612                                                         auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
613 
614                                                         layer->Reparent(*workingCopyGraph,
615                                                                         (workingCopyGraph->m_Layers).end());
616 
617                                                         workingCopyGraph->m_LayersInOrder = false;
618                                                     }
619                                                 });
620 
621     // Replace the old connections with connections to new layer
622     workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
623 
624     // Update input/outputSlot pointers
625     UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
626 
627     // Delete the old layers.
628     workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
629 
630     // Sort
631     workingCopyGraph->TopologicalSort();
632 
633     // Update SubgraphView layer pointers to match those of the internal WorkingCopy layer pointers
634     m_IConnectableLayers = IConnectableLayers{ workingCopyGraph->m_Layers.begin(),
635                                                workingCopyGraph->m_Layers.end() };
636 }
637 
GetOriginalInputSlots() const638 const SubgraphView::IInputSlots& SubgraphView::GetOriginalInputSlots() const
639 {
640     if (!p_WorkingCopyImpl)
641     {
642         throw NullPointerException("The SubgraphView calling GetOriginalInputSlots is not a working copy. "
643                                    "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
644     }
645     if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
646     {
647         throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null.");
648     }
649     return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots();
650 }
GetOriginalOutputSlots() const651 const SubgraphView::IOutputSlots& SubgraphView::GetOriginalOutputSlots() const
652 {
653     if (!p_WorkingCopyImpl)
654     {
655         throw NullPointerException("The SubgraphView calling GetOriginalOutputSlots is not a working copy. "
656                                    "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
657     }
658     if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
659     {
660         throw NullPointerException("The working copy SubgraphView pointer to its original SubgraphView is null.");
661     }
662     return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots();
663 }
664 
665 
666 } // namespace armnn
667