14 #include <fmt/format.h>
24 void AssertIfNullsOrDuplicates(
const C& container,
const std::string& errorMessage)
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)
31 IgnoreUnused(errorMessage);
34 ARMNN_ASSERT_MSG(i, errorMessage.c_str());
37 ARMNN_ASSERT_MSG(duplicateSet.find(i) == duplicateSet.end(), errorMessage.c_str());
39 duplicateSet.insert(i);
46 : enable_shared_from_this()
49 , m_Layers(graph.begin(), graph.end())
50 , m_IConnectableLayers(graph.begin(), graph.end())
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()}}
64 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
74 : enable_shared_from_this()
75 , m_IInputSlots{inputs}
76 , m_IOutputSlots{outputs}
77 , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
80 auto f = [](IConnectableLayer* value)
82 return PolymorphicDowncast<Layer*>(value);
84 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
86 m_InputSlots.resize(inputs.size());
87 m_IInputSlots.resize(inputs.size());
88 for (
unsigned int i = 0; i < inputs.size(); i++)
90 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
91 m_IInputSlots.at(i) = inputs[i];
94 m_OutputSlots.resize(outputs.size());
95 m_IOutputSlots.resize(outputs.size());
96 for (
unsigned int i = 0; i < outputs.size(); i++)
98 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
99 m_IOutputSlots.at(i) = outputs[i];
102 ArrangeBySortOrder();
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))
118 auto f = [](IConnectableLayer* value)
120 return PolymorphicDowncast<Layer*>(value);
122 std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
124 m_InputSlots.resize(inputs.size());
125 m_IInputSlots.resize(inputs.size());
126 for (
unsigned int i = 0; i < inputs.size(); i++)
128 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
129 m_IInputSlots.at(i) = inputs[i];
132 m_OutputSlots.resize(outputs.size());
133 m_IOutputSlots.resize(outputs.size());
134 for (
unsigned int i = 0; i < outputs.size(); i++)
136 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
137 m_IOutputSlots.at(i) = outputs[i];
140 ArrangeBySortOrder();
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())
152 subgraph.m_IConnectableLayers.end()})
154 ArrangeBySortOrder();
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))
167 ArrangeBySortOrder();
172 : enable_shared_from_this()
173 , m_Layers{PolymorphicDowncast<Layer*>(layer)}
174 , m_IConnectableLayers{layer}
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++)
181 m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(&(layer->GetInputSlot(i)));
182 m_IInputSlots.at(i) = &(layer->GetInputSlot(i));
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++)
190 m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(&(layer->GetOutputSlot(i)));
191 m_IOutputSlots.at(i) = &(layer->GetOutputSlot(i));
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);
211 void SubgraphView::CheckSubgraph()
214 AssertIfNullsOrDuplicates(m_InputSlots,
"Sub-graphs cannot contain null or duplicate input slots");
217 AssertIfNullsOrDuplicates(m_OutputSlots,
"Sub-graphs cannot contain null or duplicate output slots");
220 AssertIfNullsOrDuplicates(m_Layers,
"Sub-graphs cannot contain null or duplicate layers");
223 AssertIfNullsOrDuplicates(m_IInputSlots,
"Sub-graphs cannot contain null or duplicate IInputSlots");
226 AssertIfNullsOrDuplicates(m_IOutputSlots,
"Sub-graphs cannot contain null or duplicate IOutputSlots");
229 AssertIfNullsOrDuplicates(m_IConnectableLayers,
230 "Sub-graphs cannot contain null or duplicate IConnectableLayers");
235 return m_IInputSlots;
240 return m_IOutputSlots;
245 return m_IInputSlots.at(index);
250 return m_IInputSlots.at(index);
255 return m_IOutputSlots.at(index);
260 return m_OutputSlots.at(index);
265 return m_IOutputSlots.at(index);
270 return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
275 return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
280 return m_IConnectableLayers;
285 return m_IConnectableLayers.begin();
290 return m_IConnectableLayers.end();
296 return m_IConnectableLayers.begin();
301 return m_IConnectableLayers.end();
306 return m_IConnectableLayers.begin();
311 return m_IConnectableLayers.end();
317 return m_IConnectableLayers.begin();
322 return m_IConnectableLayers.end();
348 m_InputSlots.clear();
349 m_OutputSlots.clear();
352 m_IInputSlots.clear();
353 m_IOutputSlots.clear();
354 m_IConnectableLayers.clear();
357 void SubgraphView::ArrangeBySortOrder()
359 using LayerList = std::list<Layer*>;
360 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
362 return layerA->GetPriority() < layerB->GetPriority();
365 m_Layers.sort(compareLayerPriority);
367 using IConnectableLayersList = std::list<IConnectableLayer*>;
368 auto compareIConnectableLayerPriority = [](
const IConnectableLayersList::value_type& layerA,
369 const IConnectableLayersList::value_type& layerB)
371 return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
372 PolymorphicDowncast<Layer*>(layerB)->GetPriority();
375 m_IConnectableLayers.sort(compareIConnectableLayerPriority);
378 struct SubgraphView::SubgraphViewWorkingCopy
382 SubgraphViewWorkingCopy() =
default;
383 SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView)
385 , m_OriginalSubgraphView(originalSubgraphView)
389 std::shared_ptr<const SubgraphView> m_OriginalSubgraphView;
395 if (p_WorkingCopyImpl)
397 throw Exception(
"The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
398 "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
403 auto ptr = std::make_shared<SubgraphViewWorkingCopy>(
Graph(), shared_from_this());
405 std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
408 for (
auto&& originalLayer : originalSubgraphLayers)
410 Layer*
const layer = PolymorphicDowncast<const Layer*>(originalLayer)->
Clone(ptr->m_Graph);
411 originalToClonedLayerMap.emplace(originalLayer, layer);
419 PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
421 auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
423 workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
426 for (
auto originalSubgraphLayer : originalSubgraphLayers)
428 IConnectableLayer*
const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
436 auto& originalOutputSlot = originalSubgraphLayer->
GetOutputSlot(i);
438 for (
unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
442 originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
445 if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
447 auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
449 auto index = PolymorphicDowncast<OutputSlot*>(
450 &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
452 IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
455 clonedOutputSlot.Connect(inputSlot);
459 clonedOutputSlot.
SetTensorInfo(originalOutputSlot.GetTensorInfo());
469 auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
470 const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
475 IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
478 workingCopyOutputs.push_back(&clonedLayer->
GetOutputSlot(outputSlotIndex));
483 for (
auto& pair : originalToClonedLayerMap)
485 workingCopyLayers.push_back(pair.second);
488 return {std::move(workingCopyLayers),
489 std::move(workingCopyInputs),
490 std::move(workingCopyOutputs),
502 void SubgraphView::UpdateSubgraphViewSlotPointers(
SubgraphView& patternSubgraph,
505 std::vector<IInputSlot*>::iterator inputSlotPosition;
507 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIInputSlots().size(); idx++)
510 inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
511 if (inputSlotPosition != m_IInputSlots.end())
513 m_IInputSlots.erase(inputSlotPosition);
516 m_IInputSlots.insert(inputSlotPosition, substituteSubgraph.
GetIInputSlots()[idx]);
520 std::vector<IOutputSlot*>::iterator outputSlotPosition;
522 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIOutputSlots().size(); idx++)
525 outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
526 if (outputSlotPosition != m_IOutputSlots.end())
528 m_IOutputSlots.erase(outputSlotPosition);
531 m_IOutputSlots.insert(outputSlotPosition, substituteSubgraph.
GetIOutputSlots()[idx]);
538 if (!p_WorkingCopyImpl)
540 throw NullPointerException(
"The SubgraphView calling SubstituteSubgraphView is not a working copy. "
541 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
546 if (numPatternInputs != numSubInputs)
549 fmt::format(
"Number of InputSlots on substitute SubgraphView ({}) must equal the number of"
550 " InputSlots on pattern SubgraphView ({})",
557 if (numPatternOutputs != numSubOutputs)
560 fmt::format(
"Number of OutputSlots on substitute SubgraphView ({}) must equal the number of"
561 " OutputSlots on pattern SubgraphView ({})",
567 auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
571 if (std::find(std::begin(workingCopyGraph->m_Layers),
572 std::end(workingCopyGraph->m_Layers),
573 iConnectableLayer) ==
574 std::end(workingCopyGraph->m_Layers))
576 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
578 layer->Reparent(*workingCopyGraph,
579 (workingCopyGraph->m_Layers).end());
581 workingCopyGraph->m_LayersInOrder = false;
586 workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
589 UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
592 workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
595 workingCopyGraph->TopologicalSort();
599 workingCopyGraph->m_Layers.end() };
604 if (!p_WorkingCopyImpl)
606 throw NullPointerException(
"The SubgraphView calling GetOriginalInputSlots is not a working copy. "
607 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
609 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
611 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
613 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots();
617 if (!p_WorkingCopyImpl)
619 throw NullPointerException(
"The SubgraphView calling GetOriginalOutputSlots is not a working copy. "
620 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
622 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
624 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
626 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots();