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");
240 return m_IInputSlots;
245 return m_OutputSlots;
250 return m_IOutputSlots;
253 const InputSlot* SubgraphView::GetInputSlot(
unsigned int index)
const
255 return m_InputSlots.at(index);
260 return m_IInputSlots.at(index);
263 InputSlot* SubgraphView::GetInputSlot(
unsigned int index)
265 return m_InputSlots.at(index);
270 return m_IInputSlots.at(index);
273 const OutputSlot* SubgraphView::GetOutputSlot(
unsigned int index)
const
275 return m_OutputSlots.at(index);
280 return m_IOutputSlots.at(index);
283 OutputSlot* SubgraphView::GetOutputSlot(
unsigned int index)
285 return m_OutputSlots.at(index);
290 return m_IOutputSlots.at(index);
295 return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
300 return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
310 return m_IConnectableLayers;
315 return m_Layers.begin();
320 return m_Layers.end();
326 return m_IConnectableLayers.begin();
331 return m_IConnectableLayers.end();
336 return m_Layers.begin();
341 return m_Layers.end();
347 return m_IConnectableLayers.begin();
352 return m_IConnectableLayers.end();
384 m_InputSlots.clear();
385 m_OutputSlots.clear();
388 m_IInputSlots.clear();
389 m_IOutputSlots.clear();
390 m_IConnectableLayers.clear();
393 void SubgraphView::ArrangeBySortOrder()
395 using LayerList = std::list<Layer*>;
396 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
398 return layerA->GetPriority() < layerB->GetPriority();
401 m_Layers.sort(compareLayerPriority);
403 using IConnectableLayersList = std::list<IConnectableLayer*>;
404 auto compareIConnectableLayerPriority = [](
const IConnectableLayersList::value_type& layerA,
405 const IConnectableLayersList::value_type& layerB)
407 return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
408 PolymorphicDowncast<Layer*>(layerB)->GetPriority();
411 m_IConnectableLayers.sort(compareIConnectableLayerPriority);
414 struct SubgraphView::SubgraphViewWorkingCopy
418 SubgraphViewWorkingCopy() =
default;
419 SubgraphViewWorkingCopy(Graph graph, std::shared_ptr<const SubgraphView> originalSubgraphView)
421 , m_OriginalSubgraphView(originalSubgraphView)
425 std::shared_ptr<const SubgraphView> m_OriginalSubgraphView;
431 if (p_WorkingCopyImpl)
433 throw Exception(
"The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
434 "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
439 auto ptr = std::make_shared<SubgraphViewWorkingCopy>(
Graph(), shared_from_this());
441 std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
444 for (
auto&& originalLayer : originalSubgraphLayers)
446 Layer*
const layer = PolymorphicDowncast<const Layer*>(originalLayer)->
Clone(ptr->m_Graph);
447 originalToClonedLayerMap.emplace(originalLayer, layer);
455 PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
457 auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
459 workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
462 for (
auto originalSubgraphLayer : originalSubgraphLayers)
464 IConnectableLayer*
const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
472 auto& originalOutputSlot = originalSubgraphLayer->
GetOutputSlot(i);
474 for (
unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
478 originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
481 if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
483 auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
485 auto index = PolymorphicDowncast<OutputSlot*>(
486 &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
488 IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
491 clonedOutputSlot.Connect(inputSlot);
495 clonedOutputSlot.SetTensorInfo(originalOutputSlot.GetTensorInfo());
505 auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
506 const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
511 IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
514 workingCopyOutputs.push_back(&clonedLayer->
GetOutputSlot(outputSlotIndex));
519 for (
auto& pair : originalToClonedLayerMap)
521 workingCopyLayers.push_back(pair.second);
524 return {std::move(workingCopyLayers),
525 std::move(workingCopyInputs),
526 std::move(workingCopyOutputs),
538 void SubgraphView::UpdateSubgraphViewSlotPointers(
SubgraphView& patternSubgraph,
541 std::vector<IInputSlot*>::iterator inputSlotPosition;
543 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIInputSlots().size(); idx++)
546 inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
547 if (inputSlotPosition != m_IInputSlots.end())
549 m_IInputSlots.erase(inputSlotPosition);
552 m_IInputSlots.insert(inputSlotPosition, substituteSubgraph.
GetIInputSlots()[idx]);
556 std::vector<IOutputSlot*>::iterator outputSlotPosition;
558 for (
unsigned long idx = 0; idx < patternSubgraph.
GetIOutputSlots().size(); idx++)
561 outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
562 if (outputSlotPosition != m_IOutputSlots.end())
564 m_IOutputSlots.erase(outputSlotPosition);
567 m_IOutputSlots.insert(outputSlotPosition, substituteSubgraph.
GetIOutputSlots()[idx]);
574 if (!p_WorkingCopyImpl)
576 throw NullPointerException(
"The SubgraphView calling SubstituteSubgraphView is not a working copy. "
577 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
582 if (numPatternInputs != numSubInputs)
585 fmt::format(
"Number of InputSlots on substitute SubgraphView ({}) must equal the number of"
586 " InputSlots on pattern SubgraphView ({})",
593 if (numPatternOutputs != numSubOutputs)
596 fmt::format(
"Number of OutputSlots on substitute SubgraphView ({}) must equal the number of"
597 " OutputSlots on pattern SubgraphView ({})",
603 auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
607 if (std::find(std::begin(workingCopyGraph->m_Layers),
608 std::end(workingCopyGraph->m_Layers),
609 iConnectableLayer) ==
610 std::end(workingCopyGraph->m_Layers))
612 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
614 layer->Reparent(*workingCopyGraph,
615 (workingCopyGraph->m_Layers).end());
617 workingCopyGraph->m_LayersInOrder = false;
622 workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
625 UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
628 workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
631 workingCopyGraph->TopologicalSort();
635 workingCopyGraph->m_Layers.end() };
640 if (!p_WorkingCopyImpl)
642 throw NullPointerException(
"The SubgraphView calling GetOriginalInputSlots is not a working copy. "
643 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
645 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
647 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
649 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIInputSlots();
653 if (!p_WorkingCopyImpl)
655 throw NullPointerException(
"The SubgraphView calling GetOriginalOutputSlots is not a working copy. "
656 "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
658 if (!p_WorkingCopyImpl->m_OriginalSubgraphView)
660 throw NullPointerException(
"The working copy SubgraphView pointer to its original SubgraphView is null.");
662 return p_WorkingCopyImpl->m_OriginalSubgraphView->GetIOutputSlots();