docs: public GraphIndices calculateIndices(){
          if(graphIndices != null)
              return graphIndices;
  
  
          //Get cached topological sort order from config, if present
          if(configuration.getTopologicalOrder() != null && configuration.getTopologicalOrderStr() != null){
              int[] t = configuration.getTopologicalOrder();
              List<String> s = configuration.getTopologicalOrderStr();
              Map<String,Integer> m1 = new HashMap<>();
              Map<Integer,String> m2 = new HashMap<>();
              for( int i=0; i<t.length; i++ ){
                  m1.put(s.get(i), t[i]);
                  m2.put(t[i], s.get(i));
              }
  
              graphIndices = GraphIndices.builder()
                      .topologicalSortOrder(t)
                      .nameToIdx(m1)
                      .idxToName(m2)
                      .build();
              return graphIndices;
          }
  
  
          //https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm
          Map<String, org.deeplearning4j.nn.conf.graph.GraphVertex> nodeMap = configuration.getVertices();
          List<String> networkInputNames = configuration.getNetworkInputs();
          int numVertices = networkInputNames.size() + configuration.getVertices().size();
          int[] out = new int[numVertices];
          int outCounter = 0;
  
          //First: represent the graph more usefully as a Map<Integer,Set<Integer>>, where map represents edges i -> j
          // key represents j, set is set of i (inputs) for vertices j
          Map<Integer, String> vertexNamesMap = new HashMap<>();
          Map<String, Integer> vertexNamesMap2 = new HashMap<>();
          int i = 0;
          for (String inputName : configuration.getNetworkInputs()) {
              vertexNamesMap.put(i, inputName);
              vertexNamesMap2.put(inputName, i);
              i++;
          }
          for (Map.Entry<String, org.deeplearning4j.nn.conf.graph.GraphVertex> entry : nodeMap.entrySet()) {
              String name = entry.getKey();
              vertexNamesMap.put(i, name);
              vertexNamesMap2.put(name, i);
              i++;
          }
  
          Map<Integer, Set<Integer>> inputEdges = new HashMap<>(); //key: vertex. Values: vertices that the key vertex receives input from
          Map<Integer, Set<Integer>> outputEdges = new HashMap<>(); //key: vertex. Values: vertices that the key vertex outputs to
  
          for (String s : configuration.getNetworkInputs()) {
              int idx = vertexNamesMap2.get(s);
              inputEdges.put(idx, null);
          }
  
          for (Map.Entry<String, org.deeplearning4j.nn.conf.graph.GraphVertex> entry : nodeMap.entrySet()) {
              String thisVertexName = entry.getKey();
              int idx = vertexNamesMap2.get(thisVertexName);
              List<String> inputsToThisVertex = configuration.getVertexInputs().get(thisVertexName);
  
              if (inputsToThisVertex == null || inputsToThisVertex.isEmpty()) {
                  inputEdges.put(idx, null);
                  continue;
              }
  
              Set<Integer> inputSet = new HashSet<>();
              for (String s : inputsToThisVertex) {
                  Integer inputIdx = vertexNamesMap2.get(s);
                  inputSet.add(inputIdx);
                  Set<Integer> outputSetForInputIdx = outputEdges.get(inputIdx);
                  if (outputSetForInputIdx == null) {
                      outputSetForInputIdx = new HashSet<>();
                      outputEdges.put(inputIdx, outputSetForInputIdx);
                  }
                  outputSetForInputIdx.add(idx); //input vertex outputs to the current vertex
              }
  
              inputEdges.put(idx, inputSet);
          }
  
          //Now: do topological sort
          //Set of all nodes with no incoming edges: (this would be: input vertices)
          LinkedList<Integer> noIncomingEdges = new LinkedList<>();
          for (Map.Entry<Integer, Set<Integer>> entry : inputEdges.entrySet()) {
              Set<Integer> inputsFrom = entry.getValue();
              if (inputsFrom == null || inputsFrom.isEmpty()) {
                  noIncomingEdges.add(entry.getKey());
              }
          }
  
          while (!noIncomingEdges.isEmpty()) {
              int next = noIncomingEdges.removeFirst();
              out[outCounter++] = next; //Add to sorted list
  
              Set<Integer> vertexOutputsTo = outputEdges.get(next);
  
              //Remove edges next -> vertexOuputsTo[...] from graph;
              if (vertexOutputsTo != null) {
                  for (Integer v : vertexOutputsTo) {
                      Set<Integer> set = inputEdges.get(v);
                      set.remove(next);
                      if (set.isEmpty()) {
                          noIncomingEdges.add(v); //No remaining edges for vertex i -> add to list for processing
                      }
                  }
              }
          }
  
          //If any edges remain in the graph: graph has cycles:
          for (Map.Entry<Integer, Set<Integer>> entry : inputEdges.entrySet()) {
              Set<Integer> set = entry.getValue();
              if (set == null)
                  continue;
              if (!set.isEmpty())
                  throw new IllegalStateException(
                          "Invalid configuration: cycle detected in graph. Cannot calculate topological ordering with graph cycle ("
                                  + "cycle includes vertex \"" + vertexNamesMap.get(entry.getKey())
                                  + "\")");
          }
  
          //Store: the topological sort order in the configuraation... this is to ensure that when the config is
          // deserialized, it has exactly the same topological sort order on all platforms
          List<String> s = new ArrayList<>(out.length);
          for( int idx : out){
              s.add(vertexNamesMap.get(idx));
          }
          configuration.setTopologicalOrder(out);
          configuration.setTopologicalOrderStr(s);
  
          graphIndices = GraphIndices.builder()
                  .topologicalSortOrder(out)
                  .nameToIdx(vertexNamesMap2)
                  .idxToName(vertexNamesMap)
                  .build();
          return graphIndices;
      }