in base/src/main/java/org/arend/typechecking/implicitargs/equations/LevelEquationsSolver.java [212:311]
public LevelSubstitution solveLevels() {
Map<InferenceLevelVariable, Integer> basedSolution = new HashMap<>();
List<LevelEquation<InferenceLevelVariable>> cycle = myHBased ? myBasedHLevelEquations.solve(basedSolution) : null;
Set<InferenceLevelVariable> unBased = new HashSet<>();
if (myHBased) {
calculateUnBased(myBasedHLevelEquations, unBased, basedSolution);
} else {
unBased.addAll(myHLevelEquations.getVariables());
}
boolean ok = cycle == null;
if (!ok) {
reportCycle(cycle, unBased);
}
Map<InferenceLevelVariable, Integer> solution = new HashMap<>();
cycle = myHLevelEquations.solve(solution);
for (Map.Entry<InferenceLevelVariable, Integer> entry : solution.entrySet()) {
if (entry.getValue() != LevelEquations.INFINITY) {
entry.setValue(entry.getValue() + 1);
}
}
if (ok && cycle != null) {
reportCycle(cycle, unBased);
}
if (!myHBased || !unBased.isEmpty()) {
for (Pair<InferenceLevelVariable, InferenceLevelVariable> vars : myBoundVariables) {
if (!myHBased || unBased.contains(vars.proj2)) {
Integer sol = solution.get(vars.proj2);
if (sol == 0 || sol == 1) {
myPLevelEquations.getEquations().removeIf(equation -> !equation.isInfinity() && (equation.getVariable1() == vars.proj1 || equation.getVariable2() == vars.proj1));
myBasedPLevelEquations.getEquations().removeIf(equation -> !equation.isInfinity() && (equation.getVariable1() == vars.proj1 || equation.getVariable2() == vars.proj1));
myConstantUpperBounds.remove(vars.proj1);
}
}
}
}
Set<InferenceLevelVariable> pUnBased = new HashSet<>();
if (myPBased) {
cycle = myBasedPLevelEquations.solve(basedSolution);
calculateUnBased(myBasedPLevelEquations, pUnBased, basedSolution);
}
ok = cycle == null;
if (!ok) {
reportCycle(cycle, pUnBased);
}
cycle = myPLevelEquations.solve(solution);
if (ok && cycle != null) {
reportCycle(cycle, pUnBased);
}
unBased.addAll(myPBased ? pUnBased : myPLevelEquations.getVariables());
SimpleLevelSubstitution result = new SimpleLevelSubstitution();
for (InferenceLevelVariable var : unBased) {
int sol = solution.get(var);
assert sol != LevelEquations.INFINITY || var.getType() == LevelVariable.LvlType.HLVL;
result.add(var, sol == LevelEquations.INFINITY ? Level.INFINITY : new Level(-sol));
}
boolean useStd = true;
loop:
for (Set<LevelVariable> vars : myLowerBounds.values()) {
for (LevelVariable var : vars) {
if (!(var instanceof InferenceLevelVariable) && var != LevelVariable.PVAR && var != LevelVariable.HVAR) {
useStd = false;
break loop;
}
}
}
for (Map.Entry<InferenceLevelVariable, Integer> entry : basedSolution.entrySet()) {
assert entry.getValue() != LevelEquations.INFINITY || entry.getKey().getType() == LevelVariable.LvlType.HLVL;
if (!unBased.contains(entry.getKey())) {
int sol = solution.get(entry.getKey());
assert sol != LevelEquations.INFINITY || entry.getKey().getType() == LevelVariable.LvlType.HLVL;
result.add(entry.getKey(), sol == LevelEquations.INFINITY || entry.getValue() == LevelEquations.INFINITY ? Level.INFINITY : new Level(useStd ? entry.getKey().getStd() : getLowerBound(entry.getKey()), -entry.getValue(), -sol));
}
}
for (Map.Entry<InferenceLevelVariable, Level> entry : myConstantUpperBounds.entrySet()) {
Level level = result.get(entry.getKey());
if (!Level.compare(level, entry.getValue(), CMP.LE, DummyEquations.getInstance(), null)) {
int maxConstant = entry.getValue().getMaxConstant();
List<LevelEquation<LevelVariable>> equations = new ArrayList<>(2);
if (!Level.compare(level.withMaxConstant() ? new Level(level.getVar(), level.getConstant()) : level, entry.getValue(), CMP.LE, DummyEquations.getInstance(), null)) {
equations.add(level.isInfinity() ? new LevelEquation<>(entry.getKey()) : new LevelEquation<>(level.getVar(), entry.getKey(), -level.getConstant()));
}
if (level.withMaxConstant() && !Level.compare(new Level(level.getMaxConstant()), entry.getValue(), CMP.LE, DummyEquations.getInstance(), null)) {
equations.add(new LevelEquation<>(null, entry.getKey(), -level.getMaxConstant()));
}
equations.add(new LevelEquation<>(entry.getKey(), entry.getValue().getVar(), entry.getValue().getConstant(), maxConstant));
myErrorReporter.report(new SolveLevelEquationsError(equations, entry.getKey().getSourceNode()));
}
}
return result;
}