ArmNN
 22.11
SubgraphView.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 
8 #include <Graph.hpp>
9 
13 
14 #include <utility>
15 
16 namespace armnn
17 {
18 
19 namespace
20 {
21 
22 template <class C>
23 void AssertIfNullsOrDuplicates(const C& container, const std::string& errorMessage)
24 {
25  using T = typename C::value_type;
26  std::unordered_set<T> duplicateSet;
27  std::for_each(container.begin(), container.end(), [&duplicateSet, &errorMessage](const T& i)
28  {
29  // Ignore unused for release builds
30  IgnoreUnused(errorMessage);
31 
32  // Check if the item is valid
33  ARMNN_ASSERT_MSG(i, errorMessage.c_str());
34 
35  // Check if a duplicate has been found
36  ARMNN_ASSERT_MSG(duplicateSet.find(i) == duplicateSet.end(), errorMessage.c_str());
37 
38  duplicateSet.insert(i);
39  });
40 }
41 
42 } // anonymous namespace
43 
45  : m_InputSlots{}
46  , m_OutputSlots{}
47  , m_Layers(graph.begin(), graph.end())
48  , m_IConnectableLayers(graph.begin(), graph.end())
49 {
50  ArrangeBySortOrder();
51  CheckSubgraph();
52 }
53 
54 /// IConnectable Duplication to maintain backwards compatibility
56  : m_InputSlots{InputSlots{inputs.begin(), inputs.end()}}
57  , m_IInputSlots{IInputSlots{inputs.begin(), inputs.end()}}
58  , m_OutputSlots{OutputSlots{outputs.begin(), outputs.end()}}
59  , m_IOutputSlots{IOutputSlots{outputs.begin(), outputs.end()}}
60  , m_Layers(layers)
61  , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
62 {
63  ArrangeBySortOrder();
64  CheckSubgraph();
65 }
66 
67 /// IConnectable Duplication to maintain backwards compatibility
71  : m_IInputSlots{inputs}
72  , m_IOutputSlots{outputs}
73  , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
74 {
75  // Cast from IConnectableLayer to Layer for backward compatibility
76  auto f = [](IConnectableLayer* value)
77  {
78  return PolymorphicDowncast<Layer*>(value);
79  };
80  std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
81 
82  m_InputSlots.resize(inputs.size());
83  m_IInputSlots.resize(inputs.size());
84  for (unsigned int i = 0; i < inputs.size(); i++)
85  {
86  m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
87  m_IInputSlots.at(i) = inputs[i];
88  }
89 
90  m_OutputSlots.resize(outputs.size());
91  m_IOutputSlots.resize(outputs.size());
92  for (unsigned int i = 0; i < outputs.size(); i++)
93  {
94  m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
95  m_IOutputSlots.at(i) = outputs[i];
96  }
97 
98  ArrangeBySortOrder();
99  CheckSubgraph();
100 }
101 
102 /// IConnectable Duplication to maintain backwards compatibility
104  SubgraphView::IInputSlots&& inputs,
106  std::shared_ptr<SubgraphViewWorkingCopy> ptr)
107  : m_IInputSlots{inputs}
108  , m_IOutputSlots{outputs}
109  , m_IConnectableLayers(IConnectableLayers{layers.begin(), layers.end()})
110  , p_WorkingCopyImpl(std::move(ptr))
111 {
112  // Cast from IConnectableLayer to Layer for backward compatibility
113  auto f = [](IConnectableLayer* value)
114  {
115  return PolymorphicDowncast<Layer*>(value);
116  };
117  std::transform(layers.begin(), layers.end(), std::back_inserter(m_Layers), f);
118 
119  m_InputSlots.resize(inputs.size());
120  m_IInputSlots.resize(inputs.size());
121  for (unsigned int i = 0; i < inputs.size(); i++)
122  {
123  m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(inputs[i]);
124  m_IInputSlots.at(i) = inputs[i];
125  }
126 
127  m_OutputSlots.resize(outputs.size());
128  m_IOutputSlots.resize(outputs.size());
129  for (unsigned int i = 0; i < outputs.size(); i++)
130  {
131  m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(outputs[i]);
132  m_IOutputSlots.at(i) = outputs[i];
133  }
134 
135  ArrangeBySortOrder();
136  CheckSubgraph();
137 }
138 
140  : m_InputSlots(subgraph.m_InputSlots.begin(), subgraph.m_InputSlots.end())
141  , m_IInputSlots(subgraph.m_IInputSlots.begin(), subgraph.m_IInputSlots.end())
142  , m_OutputSlots(subgraph.m_OutputSlots.begin(), subgraph.m_OutputSlots.end())
143  , m_IOutputSlots(subgraph.m_IOutputSlots.begin(), subgraph.m_IOutputSlots.end())
144  , m_Layers(subgraph.m_Layers.begin(), subgraph.m_Layers.end())
145  , m_IConnectableLayers(IConnectableLayers{subgraph.m_IConnectableLayers.begin(),
146  subgraph.m_IConnectableLayers.end()})
147 {
148  ArrangeBySortOrder();
149  CheckSubgraph();
150 }
151 
153  : m_InputSlots(std::move(subgraph.m_InputSlots))
154  , m_IInputSlots(std::move(subgraph.m_IInputSlots))
155  , m_OutputSlots(std::move(subgraph.m_OutputSlots))
156  , m_IOutputSlots(std::move(subgraph.m_IOutputSlots))
157  , m_Layers(std::move(subgraph.m_Layers))
158  , m_IConnectableLayers(std::move(subgraph.m_IConnectableLayers))
159 {
160  ArrangeBySortOrder();
161  CheckSubgraph();
162 }
163 
165  : m_Layers{PolymorphicDowncast<Layer*>(layer)}
166  , m_IConnectableLayers{layer}
167 {
168  unsigned int numInputSlots = layer->GetNumInputSlots();
169  m_InputSlots.resize(numInputSlots);
170  m_IInputSlots.resize(numInputSlots);
171  for (unsigned int i = 0; i < numInputSlots; i++)
172  {
173  m_InputSlots.at(i) = PolymorphicDowncast<InputSlot*>(&(layer->GetInputSlot(i)));
174  m_IInputSlots.at(i) = &(layer->GetInputSlot(i));
175  }
176 
177  unsigned int numOutputSlots = layer->GetNumOutputSlots();
178  m_OutputSlots.resize(numOutputSlots);
179  m_IOutputSlots.resize(numOutputSlots);
180  for (unsigned int i = 0; i < numOutputSlots; i++)
181  {
182  m_OutputSlots.at(i) = PolymorphicDowncast<OutputSlot*>(&(layer->GetOutputSlot(i)));
183  m_IOutputSlots.at(i) = &(layer->GetOutputSlot(i));
184  }
185 
186  CheckSubgraph();
187 }
188 
190 {
191  m_InputSlots = std::move(other.m_InputSlots);
192  m_IInputSlots = std::move(other.m_IInputSlots);
193  m_OutputSlots = std::move(other.m_OutputSlots);
194  m_IOutputSlots = std::move(other.m_IOutputSlots);
195  m_Layers = std::move(other.m_Layers);
196  m_IConnectableLayers = std::move(other.m_IConnectableLayers);
197 
198  CheckSubgraph();
199 
200  return *this;
201 }
202 
203 void SubgraphView::CheckSubgraph()
204 {
205  // Check for invalid or duplicate input slots
206  AssertIfNullsOrDuplicates(m_InputSlots, "Sub-graphs cannot contain null or duplicate input slots");
207 
208  // Check for invalid or duplicate output slots
209  AssertIfNullsOrDuplicates(m_OutputSlots, "Sub-graphs cannot contain null or duplicate output slots");
210 
211  // Check for invalid or duplicate layers
212  AssertIfNullsOrDuplicates(m_Layers, "Sub-graphs cannot contain null or duplicate layers");
213 
214  // Check for invalid or duplicate input slots
215  AssertIfNullsOrDuplicates(m_IInputSlots, "Sub-graphs cannot contain null or duplicate IInputSlots");
216 
217  // Check for invalid or duplicate output slots
218  AssertIfNullsOrDuplicates(m_IOutputSlots, "Sub-graphs cannot contain null or duplicate IOutputSlots");
219 
220  // Check for invalid or duplicate layers
221  AssertIfNullsOrDuplicates(m_IConnectableLayers,
222  "Sub-graphs cannot contain null or duplicate IConnectableLayers");
223 }
224 
225 const SubgraphView::InputSlots& SubgraphView::GetInputSlots() const
226 {
227  return m_InputSlots;
228 }
229 
231 {
232  return m_IInputSlots;
233 }
234 
235 const SubgraphView::OutputSlots& SubgraphView::GetOutputSlots() const
236 {
237  return m_OutputSlots;
238 }
239 
241 {
242  return m_IOutputSlots;
243 }
244 
245 const InputSlot* SubgraphView::GetInputSlot(unsigned int index) const
246 {
247  return m_InputSlots.at(index);
248 }
249 
250 const IInputSlot* SubgraphView::GetIInputSlot(unsigned int index) const
251 {
252  return m_IInputSlots.at(index);
253 }
254 
255 InputSlot* SubgraphView::GetInputSlot(unsigned int index)
256 {
257  return m_InputSlots.at(index);
258 }
259 
261 {
262  return m_IInputSlots.at(index);
263 }
264 
265 const OutputSlot* SubgraphView::GetOutputSlot(unsigned int index) const
266 {
267  return m_OutputSlots.at(index);
268 }
269 
270 const IOutputSlot* SubgraphView::GetIOutputSlot(unsigned int index) const
271 {
272  return m_IOutputSlots.at(index);
273 }
274 
275 OutputSlot* SubgraphView::GetOutputSlot(unsigned int index)
276 {
277  return m_OutputSlots.at(index);
278 }
279 
281 {
282  return m_IOutputSlots.at(index);
283 }
284 
285 unsigned int SubgraphView::GetNumInputSlots() const
286 {
287  return armnn::numeric_cast<unsigned int>(m_IInputSlots.size());
288 }
289 
291 {
292  return armnn::numeric_cast<unsigned int>(m_IOutputSlots.size());
293 }
294 
295 const SubgraphView::Layers& SubgraphView::GetLayers() const
296 {
297  return m_Layers;
298 }
299 
301 {
302  return m_IConnectableLayers;
303 }
304 
305 SubgraphView::Iterator SubgraphView::begin()
306 {
307  return m_Layers.begin();
308 }
309 
310 SubgraphView::Iterator SubgraphView::end()
311 {
312  return m_Layers.end();
313 }
314 
315 // IConnectable Duplication to maintain backwards compatibility
317 {
318  return m_IConnectableLayers.begin();
319 }
320 
322 {
323  return m_IConnectableLayers.end();
324 }
325 
326 SubgraphView::ConstIterator SubgraphView::begin() const
327 {
328  return m_Layers.begin();
329 }
330 
331 SubgraphView::ConstIterator SubgraphView::end() const
332 {
333  return m_Layers.end();
334 }
335 
336 // IConnectable Duplication to maintain backwards compatibility
338 {
339  return m_IConnectableLayers.begin();
340 }
341 
343 {
344  return m_IConnectableLayers.end();
345 }
346 
347 SubgraphView::ConstIterator SubgraphView::cbegin() const
348 {
349  // Ignore deprecated call as this is internal to SubgraphView
351  return begin();
353 }
354 
355 SubgraphView::ConstIterator SubgraphView::cend() const
356 {
357  // Ignore deprecated call as this is internal to SubgraphView
359  return end();
361 }
362 
363 // IConnectable Duplication to maintain backwards compatibility
365 {
366  return beginIConnectable();
367 }
368 
370 {
371  return endIConnectable();
372 }
373 
375 {
376  m_InputSlots.clear();
377  m_OutputSlots.clear();
378  m_Layers.clear();
379 
380  m_IInputSlots.clear();
381  m_IOutputSlots.clear();
382  m_IConnectableLayers.clear();
383 }
384 
385 void SubgraphView::ArrangeBySortOrder()
386 {
387  using LayerList = std::list<Layer*>;
388  auto compareLayerPriority = [](const LayerList::value_type& layerA, const LayerList::value_type& layerB)
389  {
390  return layerA->GetPriority() < layerB->GetPriority();
391  };
392 
393  m_Layers.sort(compareLayerPriority);
394 
395  using IConnectableLayersList = std::list<IConnectableLayer*>;
396  auto compareIConnectableLayerPriority = [](const IConnectableLayersList::value_type& layerA,
397  const IConnectableLayersList::value_type& layerB)
398  {
399  return PolymorphicDowncast<Layer*>(layerA)->GetPriority() <
400  PolymorphicDowncast<Layer*>(layerB)->GetPriority();
401  };
402 
403  m_IConnectableLayers.sort(compareIConnectableLayerPriority);
404 }
405 
406 struct SubgraphView::SubgraphViewWorkingCopy
407 {
408 public:
409 
410  SubgraphViewWorkingCopy() = default;
411  SubgraphViewWorkingCopy(Graph graph)
412  : m_Graph(graph)
413  {};
414 
415  Graph m_Graph;
416 
417 };
418 
420 {
421  if (p_WorkingCopyImpl)
422  {
423  throw Exception("The SubgraphView calling GetWorkingCopy() is already a working copy. This function "
424  "should be called on original SubgraphView obtained from OptimizeSubgraphView()");
425  }
426 
427  // Create a cut down SubgraphView with underlying graph containing only the relevant layers.
428  // It needs its own underlying layers so that they can be replaced safely.
429  auto ptr = std::make_shared<SubgraphViewWorkingCopy>(Graph());
430 
431  std::unordered_map<const IConnectableLayer*, IConnectableLayer*> originalToClonedLayerMap;
432  std::list<armnn::IConnectableLayer*> originalSubgraphLayers = GetIConnectableLayers();
433 
434  for (auto&& originalLayer : originalSubgraphLayers)
435  {
436  Layer* const layer = PolymorphicDowncast<const Layer*>(originalLayer)->Clone(ptr->m_Graph);
437  originalToClonedLayerMap.emplace(originalLayer, layer);
438  }
439 
440  SubgraphView::IInputSlots workingCopyInputs;
441  // Add IInputSlots to workingCopy
442  for (auto originalSubgraphInputSlot : GetIInputSlots())
443  {
444  const IConnectableLayer& originalSubgraphLayer =
445  PolymorphicDowncast<InputSlot*>(originalSubgraphInputSlot)->GetOwningLayer();
446 
447  auto* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
448 
449  workingCopyInputs.push_back(&clonedLayer->GetInputSlot(originalSubgraphInputSlot->GetSlotIndex()));
450  }
451 
452  for (auto originalSubgraphLayer : originalSubgraphLayers)
453  {
454  IConnectableLayer* const clonedLayer = originalToClonedLayerMap[originalSubgraphLayer];
455 
456  // OutputLayers have no OutputSlots to be connected
457  if (clonedLayer->GetType() != LayerType::Output)
458  {
459  // connect all cloned layers as per original subgraph
460  for (unsigned int i = 0; i < clonedLayer->GetNumOutputSlots(); i++)
461  {
462  auto& originalOutputSlot = originalSubgraphLayer->GetOutputSlot(i);
463  auto& clonedOutputSlot = clonedLayer->GetOutputSlot(i);
464  for (unsigned int j = 0; j < originalOutputSlot.GetNumConnections(); j++)
465  {
466  // nextLayer is the layer with IInputSlot connected to IOutputSlot we are working on
467  const IConnectableLayer& nextLayerOnOriginalSubgraph =
468  originalOutputSlot.GetConnection(j)->GetOwningIConnectableLayer();
469 
470  // Check the layer is in our map and so has a clonedLayer
471  if (originalToClonedLayerMap.find(&nextLayerOnOriginalSubgraph) != originalToClonedLayerMap.end())
472  {
473  auto* nextLayerOnClonedSubgraph = originalToClonedLayerMap[&nextLayerOnOriginalSubgraph];
474 
475  auto index = PolymorphicDowncast<OutputSlot*>(
476  &originalOutputSlot)->GetConnection(j)->GetSlotIndex();
477 
478  IInputSlot& inputSlot = nextLayerOnClonedSubgraph->GetInputSlot(index);
479 
480  // Then make the connection
481  clonedOutputSlot.Connect(inputSlot);
482  }
483  }
484  // Copy the tensorInfo to the clonedOutputSlot
485  clonedOutputSlot.SetTensorInfo(originalOutputSlot.GetTensorInfo());
486  }
487  }
488  }
489 
490  SubgraphView::IOutputSlots workingCopyOutputs;
491 
492  // Add IOutputSlots to workingCopy
493  for (auto outputSlot : GetIOutputSlots())
494  {
495  auto outputSlotIndex = outputSlot->CalculateIndexOnOwner();
496  const IConnectableLayer& originalSubgraphLayer = outputSlot->GetOwningIConnectableLayer();
497 
498  // OutputLayers have no OutputSlots to be connected
499  if (originalSubgraphLayer.GetType() != LayerType::Output)
500  {
501  IConnectableLayer* clonedLayer = originalToClonedLayerMap[&originalSubgraphLayer];
502 
503  // Add the OutputSlot of clonedLayer to WorkingCopy OutputSlots
504  workingCopyOutputs.push_back(&clonedLayer->GetOutputSlot(outputSlotIndex));
505  }
506  }
507 
508  SubgraphView::IConnectableLayers workingCopyLayers;
509  for (auto& pair : originalToClonedLayerMap)
510  {
511  workingCopyLayers.push_back(pair.second);
512  }
513 
514  return {std::move(workingCopyLayers),
515  std::move(workingCopyInputs),
516  std::move(workingCopyOutputs),
517  ptr};
518 }
519 
521 {
522  ARMNN_ASSERT(substituteLayer != nullptr);
523  SubgraphView substituteSubgraph(substituteLayer);
524 
525  SubstituteSubgraph(subgraph, substituteSubgraph);
526 }
527 
528 void SubgraphView::UpdateSubgraphViewSlotPointers(SubgraphView& patternSubgraph,
529  const SubgraphView& substituteSubgraph)
530 {
531  std::vector<IInputSlot*>::iterator inputSlotPosition;
532  // search for and erase any InputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
533  for (auto slot : patternSubgraph.GetIInputSlots())
534  {
535  inputSlotPosition = std::find(m_IInputSlots.begin(), m_IInputSlots.end(), slot);
536  if (inputSlotPosition != m_IInputSlots.end())
537  {
538  m_IInputSlots.erase(inputSlotPosition);
539  }
540  }
541 
542  std::vector<IOutputSlot*>::iterator outputSlotPosition;
543  // search for and erase any OutputSlots that appear in the WorkingCopy that match those in the PatternSubgraph
544  for (auto slot : patternSubgraph.GetIOutputSlots())
545  {
546  outputSlotPosition = std::find(m_IOutputSlots.begin(), m_IOutputSlots.end(), slot);
547  if (outputSlotPosition != m_IOutputSlots.end())
548  {
549  m_IOutputSlots.erase(outputSlotPosition);
550  }
551  }
552 
553  // append InputSlots from the SubstituteSubgraph to the WorkingCopy m_IInputSlots vector variable
554  // at the position in the vector where PatternSubgraph InputSlots were last removed
555  m_IInputSlots.insert(inputSlotPosition,
556  std::make_move_iterator(substituteSubgraph.m_IInputSlots.begin()),
557  std::make_move_iterator(substituteSubgraph.m_IInputSlots.end()));
558 
559  // append OutputSlots from the SubstituteSubgraph to the WorkingCopy m_IOutputSlots vector variable
560  // at the position in the vector where PatternSubgraph OutputSlots were last removed
561  m_IOutputSlots.insert(outputSlotPosition,
562  std::make_move_iterator(substituteSubgraph.m_OutputSlots.begin()),
563  std::make_move_iterator(substituteSubgraph.m_OutputSlots.end()));
564 }
565 
566 void SubgraphView::SubstituteSubgraph(SubgraphView& patternSubgraph, const SubgraphView& substituteSubgraph)
567 {
568  if (!p_WorkingCopyImpl)
569  {
570  throw NullPointerException("The SubgraphView calling SubstituteSubgraphView is not a working copy. "
571  "Call this function on SubgraphView returned from SubgraphView::GetWorkingCopy()");
572  }
573 
574  // Add substitute layer to the Main graph i.e. graph in p_WorkingCopyImpl
575  auto workingCopyGraph = &p_WorkingCopyImpl->m_Graph;
576  substituteSubgraph.ForEachIConnectableLayer([workingCopyGraph](IConnectableLayer* iConnectableLayer)
577  {
578  // Search WorkingCopy Graph for substituteLayer and add if missing
579  if (std::find(std::begin(workingCopyGraph->m_Layers),
580  std::end(workingCopyGraph->m_Layers),
581  iConnectableLayer) ==
582  std::end(workingCopyGraph->m_Layers))
583  {
584  auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
585 
586  layer->Reparent(*workingCopyGraph,
587  (workingCopyGraph->m_Layers).end());
588 
589  workingCopyGraph->m_LayersInOrder = false;
590  }
591  });
592 
593  // Replace the old connections with connections to new layer
594  workingCopyGraph->ReplaceSubgraphConnections(patternSubgraph, substituteSubgraph);
595 
596  // Update input/outputSlot pointers
597  UpdateSubgraphViewSlotPointers(patternSubgraph, substituteSubgraph);
598 
599  // Delete the old layers.
600  workingCopyGraph->EraseSubgraphLayers(patternSubgraph);
601 
602  // Sort
603  workingCopyGraph->TopologicalSort();
604 
605  // Update SubgraphView layer pointers to match those of the internal WorkingCopy layer pointers
606  m_IConnectableLayers = IConnectableLayers{ workingCopyGraph->m_Layers.begin(),
607  workingCopyGraph->m_Layers.end() };
608 }
609 
610 
611 } // namespace armnn
IConnectableLayers::iterator IConnectableLayerIterator
IConnectableLayerIterator endIConnectable()
virtual unsigned int GetNumOutputSlots() const =0
Returns the number of connectable output slots.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:68
Layers::iterator Iterator
const IOutputSlots & GetIOutputSlots() const
const IConnectableLayers & GetIConnectableLayers() const
const IInputSlots & GetIInputSlots() const
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
SubgraphView & operator=(SubgraphView &&other)
Move-assignment operator.
OutputSlots && outputs
std::vector< OutputSlot * > OutputSlots
unsigned int GetNumInputSlots() const
IConnectableLayerIterator beginIConnectable()
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
ConstIConnectableIterator cendIConnectable() const
void SubstituteSubgraph(SubgraphView &, IConnectableLayer *)
These methods should be called on a working copy subgraph created from GetWorkingCopy.
const IOutputSlot * GetIOutputSlot(unsigned int index) const
The SubgraphView class represents a subgraph of a Graph.
OutputSlots Layers && layers
std::list< IConnectableLayer * > IConnectableLayers
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
An output connection slot for a layer.
Definition: INetwork.hpp:41
std::vector< IOutputSlot * > IOutputSlots
void ForEachIConnectableLayer(Func func) const
std::vector< IInputSlot * > IInputSlots
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
virtual LayerType GetType() const =0
Returns the armnn::LayerType of this layer.
std::vector< InputSlot * > InputSlots
SubgraphView(Graph &graph)
Constructs a sub-graph from the entire given graph.
IConnectableLayers::const_iterator ConstIConnectableIterator
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
SubgraphView GetWorkingCopy() const
This method returns a copy of the original SubgraphView provided by OptimizeSubgraphView with a separ...
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
std::list< Layer * > Layers
An input connection slot for a layer.
Definition: INetwork.hpp:25
Layers::const_iterator ConstIterator
const IInputSlot * GetIInputSlot(unsigned int index) const
unsigned int GetNumOutputSlots() const
ConstIConnectableIterator cbeginIConnectable() const