boolean areAbstractSuccessors(
      AbstractState pElement,
      CFAEdge pCfaEdge,
      Collection<? extends AbstractState> pSuccessors,
      List<ConfigurableProgramAnalysis> cpas)
      throws CPATransferException, InterruptedException {
    Preconditions.checkNotNull(pCfaEdge);

    CompositeState compositeState = (CompositeState) pElement;

    int resultCount = 1;
    boolean result = true;
    for (int i = 0; i < size; ++i) {
      Set<AbstractState> componentSuccessors = new HashSet<>();
      for (AbstractState successor : pSuccessors) {
        CompositeState compositeSuccessor = (CompositeState) successor;
        if (compositeSuccessor.getNumberOfStates() != size) {
          return false;
        }
        componentSuccessors.add(compositeSuccessor.get(i));
      }
      resultCount *= componentSuccessors.size();
      ProofChecker componentProofChecker = (ProofChecker) cpas.get(i);
      if (!componentProofChecker.areAbstractSuccessors(
          compositeState.get(i), pCfaEdge, componentSuccessors)) {
        result =
            false; // if there are no successors it might be still ok if one of the other components
                   // is fine with the empty set
      } else {
        if (componentSuccessors.isEmpty()) {
          assert pSuccessors.isEmpty();
          return true; // another component is indeed fine with the empty set as set of successors;
                       // transition is ok
        }
      }
    }

    if (resultCount > pSuccessors.size()) {
      return false;
    }

    HashSet<List<AbstractState>> states = new HashSet<>();
    for (AbstractState successor : pSuccessors) {
      states.add(((CompositeState) successor).getWrappedStates());
    }
    if (resultCount != states.size()) {
      return false;
    }

    return result;
  }