old_contents: from miniflow import *
  
  def topological_sort(feed_dict):
      """
      Sort generic nodes in topological order using Kahn's Algorithm.
  
      `feed_dict`: A dictionary where the key is a `Input` node and the value is the respective value feed to that node.
  
      Returns a list of sorted nodes.
      """
  
      input_nodes = [n for n in feed_dict.keys()]
  
      G = {}
      nodes = [n for n in input_nodes]
      while len(nodes) > 0:
          n = nodes.pop(0)
          if n not in G:
              G[n] = {'in': set(), 'out': set()}
          for m in n.outbound_nodes:
              if m not in G:
                  G[m] = {'in': set(), 'out': set()}
              G[n]['out'].add(m)
              G[m]['in'].add(n)
              nodes.append(m)
  
      L = []
      S = set(input_nodes)
      while len(S) > 0:
          n = S.pop()
  
          if isinstance(n, Input):
              n.value = feed_dict[n]
  
          L.append(n)
          for m in n.outbound_nodes:
              G[n]['out'].remove(m)
              G[m]['in'].remove(n)
              # if no other incoming edges add to S
              if len(G[m]['in']) == 0:
                  S.add(m)
      return L
  
  def forward_pass(output_node, sorted_nodes):
      """
      Performs a forward pass through a list of sorted nodes.
  
      Arguments:
  
          `output_node`: A node in the graph, should be the output node (have no outgoing edges).
          `sorted_nodes`: A topologically sorted list of nodes.
  
      Returns the output Node's value
      """
  
      for n in sorted_nodes:
          n.forward()
  
      return output_node.value
  
  def forward_and_backward(graph):
      """
      Performs a forward pass and a backward pass through a list of sorted nodes.
  
      Arguments:
  
          `graph`: The result of calling `topological_sort`.
      """
      # Forward pass
      for n in graph:
          n.forward()
  
      # Backward pass
      for n in graph[::-1]:
          n.backward()
  
new_contents: from miniflow import *
  
  def topological_sort(feed_dict):
      """
      Sort generic nodes in topological order using Kahn's Algorithm.
  
      `feed_dict`: A dictionary where the key is a `Input` node and the value is the respective value feed to that node.
  
      Returns a list of sorted nodes.
      """
  
      input_nodes = [n for n in feed_dict.keys()]
  
      G = {}
      nodes = [n for n in input_nodes]
      while len(nodes) > 0:
          n = nodes.pop(0)
          if n not in G:
              G[n] = {'in': set(), 'out': set()}
          for m in n.outbound_nodes:
              if m not in G:
                  G[m] = {'in': set(), 'out': set()}
              G[n]['out'].add(m)
              G[m]['in'].add(n)
              nodes.append(m)
  
      L = []
      S = set(input_nodes)
      while len(S) > 0:
          n = S.pop()
  
          if isinstance(n, Input):
              n.value = feed_dict[n]
  
          L.append(n)
          for m in n.outbound_nodes:
              G[n]['out'].remove(m)
              G[m]['in'].remove(n)
              # if no other incoming edges add to S
              if len(G[m]['in']) == 0:
                  S.add(m)
      return L
  
  def forward_pass(output_node, sorted_nodes):
      """
      Performs a forward pass through a list of sorted nodes.
  
      Arguments:
  
          `output_node`: A node in the graph, should be the output node (have no outgoing edges).
          `sorted_nodes`: A topologically sorted list of nodes.
  
      Returns the output Node's value
      """
  
      for n in sorted_nodes:
          n.forward()
  
      return output_node.value
  
  def forward_and_backward(graph):
      """
      Performs a forward pass and a backward pass through a list of sorted nodes.
  
      Arguments:
  
          `graph`: The result of calling `topological_sort`.
      """
      # Forward pass
      for n in graph:
          n.forward()
  
      # Backward pass
      for n in graph[::-1]:
          n.backward()
  
  def sgd_update(trainables, learning_rate=1e-2):
      """
      Updates the value of each trainable with SGD.
  
      Arguments:
  
          `trainables`: A list of `Input` Nodes representing weights/biases.
          `learning_rate`: The learning rate.
      """
      # TODO: update all the `trainables` with SGD
      # You can access and assign the value of a trainable with `value` attribute.
      # Example:
      for t in trainables:
          t.value -= learning_rate * t.gradients[t]
  
subject: Add sgd_update function