+function DAG:createNode(nnm)
+ if not self.node[nnm] then
+ self:add(nnm) -- Add it to the object as a Container
+ local node = {}
+ node.succ = {}
+ node.pred = {}
+ node.index = #self.modules
+ self.node[nnm] = node
+ end
+end
+
+function DAG:putInOrder()
+ if self.sorted then
+ return
+ end
+
+ local distance = {}
+ self:nestedApply(
+ function(m) distance[m] = 1 end,
+ self.inputModules
+ )
+
+ local nc
+ local nl = 0
+ repeat
+ nc = 0
+ for nnma, node in pairs(self.node) do
+ for _, nnmb in pairs(node.succ) do
+ if distance[nnma] and (not distance[nnmb] or distance[nnmb] < distance[nnma] + 1) then
+ distance[nnmb] = distance[nnma] + 1
+ nc = nc + 1
+ end
+ end
+ end
+ assert(nl < #self.modules, 'Cycle detected in the graph.')
+ nl = nl + 1
+ until nc == 0
+
+ for _, nnm in pairs(self.modules) do
+ assert(distance[nnm], 'Some modules are not connected to inputs')
+ end
+
+ self.sorted = {}
+ for m, d in pairs(distance) do
+ table.insert(self.sorted, { distance = d, nnm = m })
+ end
+
+ table.sort(self.sorted, function(a, b) return a.distance < b.distance end)
+
+ for i, a in ipairs(self.sorted) do self.sorted[i] = a.nnm end
+end
+
+-- This accumulates x in a, where they are both nested tables of
+-- tensors with same structures / keys. If first is true, set a = x
+-- (in which case a can be nil) otherwise a = a + x. The behavior is
+-- undefined if a and x do not have the exact same structure.
+function DAG:nestedAccTensor(a, x, first)
+ if torch.type(x) == 'table' then
+ local b = {}
+ for i in pairs(x) do
+ b[i] = self:nestedAccTensor(a[i], x[i], first)
+ end
+ a = b
+ else
+ if first then
+ if a then
+ a:resizeAs(x):copy(x)
+ else
+ a = x:clone()
+ end
+ else
+ a:add(x)
+ end
+ end
+ return a
+end
+
+function DAG:updateGradOutput(node)
+ local gradInputSucc = node.gradInputSucc
+ if #gradInputSucc == 1 then
+ node.gradOutput = gradInputSucc[1]
+ elseif #gradInputSucc > 1 then
+ for k = 1, #gradInputSucc do
+ node.gradOutput = self:nestedAccTensor(node.gradOutput, gradInputSucc[k], k == 1)
+ end
+ end
+end
+
+----------------------------------------------------------------------
+
+-- Connect a sequence of modules
+function DAG:connect(...)
+ self.sorted = nil
+ local prev
+ for _, nnm in pairs({...}) do
+ self:createNode(nnm)
+ if prev then
+ table.insert(self.node[nnm].pred, prev)
+ table.insert(self.node[prev].succ, nnm)
+ end
+ prev = nnm
+ end
+end
+
+function DAG:setLabel(nnm, label)
+ self.node[nnm].label = label
+end
+