code: private static void outsideAdjoint(final Hypergraph graph, final Hyperpotential w, final Algebra s,
              final Scores scores) {
          final double[] beta = scores.beta;
          final double[] alphaAdj = scores.alphaAdj;
  
          graph.applyTopoSort(new HyperedgeFn() {
              
              @Override
              public void apply(Hyperedge e) {
                  int i = e.getHeadNode().getId();
                  // \forall j \in T(e):
                  // \adj{\alpha_i} += \adj{\alpha_j} * w_e * \prod_{k \in T(e): k \neq j} \beta_k
                  for (Hypernode j : e.getTailNodes()) {
                      double prod = s.times(alphaAdj[j.getId()], w.getScore(e, s));
                      for (Hypernode k : e.getTailNodes()) {
                          if (k == j) { continue; }
                          prod = s.times(prod, beta[k.getId()]);
                      }
                      alphaAdj[i] = s.plus(alphaAdj[i], prod);
                  }
              }
              
          });
          scores.alphaAdj = alphaAdj;
      }
docs: Computes the adjoints of the outside scores only.
  Performs only a partial backwards pass through the outside algorithm.
  
  INPUT: scores.beta, scores.alphaAdj.
  OUTPUT: scores.alphaAdj.
  
  @param graph The hypergraph
  @param w The potential function.
  @param s The semiring.
  @param scores Input and output struct.