@NotNull
  private Map<DfaVariableValue, Change> getChangeMap(TrackingDfaMemoryState previous) {
    Map<DfaVariableValue, Change> changeMap = new HashMap<>();
    Set<DfaVariableValue> varsToCheck = new HashSet<>();
    previous.forRecordedVariableTypes((value, state) -> varsToCheck.add(value));
    forRecordedVariableTypes((value, state) -> varsToCheck.add(value));
    for (DfaVariableValue value : varsToCheck) {
      DfType newType = getDfType(value);
      DfType oldType = previous.getDfType(value);
      if (!newType.equals(oldType)) {
        changeMap.put(value, new Change(Collections.emptySet(), Collections.emptySet(), oldType, newType));
      }
    }
    Map<DfaVariableValue, Set<Relation>> oldRelations = previous.getRelations();
    Map<DfaVariableValue, Set<Relation>> newRelations = getRelations();
    varsToCheck.clear();
    varsToCheck.addAll(oldRelations.keySet());
    varsToCheck.addAll(newRelations.keySet());
    for (DfaVariableValue value : varsToCheck) {
      Set<Relation> oldValueRelations = oldRelations.getOrDefault(value, Collections.emptySet());
      Set<Relation> newValueRelations = newRelations.getOrDefault(value, Collections.emptySet());
      if (!oldValueRelations.equals(newValueRelations)) {
        Set<Relation> added = new HashSet<>(newValueRelations);
        added.removeAll(oldValueRelations);
        Set<Relation> removed = new HashSet<>(oldValueRelations);
        removed.removeAll(newValueRelations);
        changeMap.compute(
          value, (v, change) -> change == null
                                ? Change.create(removed, added, DfType.BOTTOM, DfType.BOTTOM)
                                : Change.create(removed, added, change.myOldType, change.myNewType));
      }
    }
    return changeMap;
  }
@NotNull
  private Map<DfaVariableValue, Change> getChangeMap(TrackingDfaMemoryState previous)