private void updateStatistics(
      BranchAndBoundAlgorithm<DiscreteMaxSumDecisionNode> bb, DiscreteVariable<?> targetVariable) {
    nodesExpanded += bb.getExpandedNodes();

    int nodesAtLevel = 1;
    totalNodes++;

    for (DiscreteVariable variable : variableExpansionOrder) {
      if (!variable.equals(targetVariable)) {
        nodesAtLevel *= variable.getDomainSize();
        totalNodes += nodesAtLevel;
      }
    }

    Validate.isTrue(nodesExpanded <= totalNodes);
  }
  public MarginalValues<?> calculateMarginalMaxFunction(
      Map<Variable<?, ?>, MarginalValues<?>> sortedMessages, Variable<?, ?> variable) {

    DiscreteVariable<?> destinationVariable = (DiscreteVariable<?>) variable;

    DiscreteMarginalValues<?> values = new DiscreteMarginalValues();

    for (DiscreteVariableState state : destinationVariable.getDomain()) {
      values.put(state, findMaxValue(destinationVariable, state, sortedMessages));
    }

    for (DiscreteVariable<?> var : function.getVariableExpansionOrder()) {
      if (!sortedMessages.containsKey(var)) continue;

      DiscreteVariable var2 = (DiscreteVariable) function.getVariableDependency(var);

      // if (var2 == null) {
      // System.out.println(function.getVariableExpansionOrder());
      // System.out.println(var);
      // System.out.println(function.getVariableDependencies());
      // }
      //
      // if (!var.getDomain().equals(var2.getDomain())) {
      // System.out.println(var.getDomain());
      // System.out.println(var2.getDomain());
      // throw new IllegalArgumentException();
      // }

      DiscreteMarginalValues<?> marginalValues =
          (DiscreteMarginalValues<?>) sortedMessages.get(var);

      if (marginalValues == null) {
        System.out.println(sortedMessages);
        System.out.println(var);
        throw new IllegalArgumentException();
      }

      // if
      // (!marginalValues.getValues().keySet().equals(var.getDomain().getStates()))
      // {
      // System.out.println(marginalValues);
      // System.out.println(var.getDomain());
      // throw new IllegalArgumentException();
      // }

    }

    if (validate) {
      DiscreteMarginalValues<?> expectedValues =
          (DiscreteMarginalValues<?>)
              groundTruth.calculateMarginalMaxFunction(sortedMessages, variable);

      boolean error = false;

      for (DiscreteVariableState state : values.getValues().keySet()) {
        if (Math.abs(values.getValues().get(state) - expectedValues.getValues().get(state))
            > 1e-10) {
          error = true;
          break;
        }
      }

      if (error) {
        System.out.println(
            "Value from OptimisedMarginalMaximisation is not equal to BBDiscreteMarginalMaximisation");
        System.out.println(sortedMessages);

        System.out.println("Expected: " + expectedValues);
        System.out.println("Got " + values);

        for (DiscreteVariableState state : values.getValues().keySet()) {
          System.out.println(state);
          System.out.println(values.getValues().get(state));
          System.out.println(expectedValues.getValues().get(state));
        }

        throw new IllegalArgumentException();
      }
    }

    return values;
  }