private double multiLL(DoubleMatrix2D coeffs, Node dep, List<Node> indep) {

    DoubleMatrix2D indepData =
        factory2D.make(internalData.subsetColumns(indep).getDoubleData().toArray());
    List<Node> depList = new ArrayList<>();
    depList.add(dep);
    DoubleMatrix2D depData =
        factory2D.make(internalData.subsetColumns(depList).getDoubleData().toArray());

    int N = indepData.rows();
    DoubleMatrix2D probs =
        Algebra.DEFAULT.mult(factory2D.appendColumns(factory2D.make(N, 1, 1.0), indepData), coeffs);

    probs =
        factory2D
            .appendColumns(factory2D.make(indepData.rows(), 1, 1.0), probs)
            .assign(Functions.exp);
    double ll = 0;
    for (int i = 0; i < N; i++) {
      DoubleMatrix1D curRow = probs.viewRow(i);
      curRow.assign(Functions.div(curRow.zSum()));
      ll += Math.log(curRow.get((int) depData.get(i, 0)));
    }
    return ll;
  }
  /**
   * Constructs a new on-the-fly BayesIM that will calculate conditional probabilities on the fly
   * from the given discrete data set, for the given Bayes PM.
   *
   * @param bayesPm the given Bayes PM, which specifies a directed acyclic graph for a Bayes net and
   *     parametrization for the Bayes net, but not actual values for the parameters.
   * @param dataSet the discrete data set from which conditional probabilities should be estimated
   *     on the fly.
   */
  public OnTheFlyMarginalCalculator(BayesPm bayesPm, DataSet dataSet)
      throws IllegalArgumentException {
    if (bayesPm == null) {
      throw new NullPointerException();
    }

    if (dataSet == null) {
      throw new NullPointerException();
    }

    // Make sure all of the variables in the PM are in the data set;
    // otherwise, estimation is impossible.
    BayesUtils.ensureVarsInData(bayesPm.getVariables(), dataSet);
    //        DataUtils.ensureVariablesExist(bayesPm, dataSet);

    this.bayesPm = new BayesPm(bayesPm);

    // Get the nodes from the BayesPm. This fixes the order of the nodes
    // in the BayesIm, independently of any change to the BayesPm.
    // (This order must be maintained.)
    Graph graph = bayesPm.getDag();
    this.nodes = graph.getNodes().toArray(new Node[0]);

    // Initialize.
    initialize();

    // Create a subset of the data set with the variables of the IM, in
    // the order of the IM.
    List<Node> variables = getVariables();
    this.dataSet = dataSet.subsetColumns(variables);

    // Create a tautologous proposition for evidence.
    this.evidence = new Evidence(Proposition.tautology(this));
  }