Skip to content

Commit

Permalink
Perform incomplete matching for over/underdet syst
Browse files Browse the repository at this point in the history
This performs an incomplete matching after producing the message unbalanced
equation system, and instead of just a number differing OMC will try to
perform a sanity check to figure out if for example a variable is never
referenced in any equation or if two variables must be matched by the same
equation.
  • Loading branch information
sjoelund authored and OpenModelica-Hudson committed Aug 10, 2017
1 parent 1355755 commit 24c3047
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 20 deletions.
18 changes: 7 additions & 11 deletions Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -115,6 +115,7 @@ protected
list<BackendDAE.TimeEvent> timeEvents;
String neqStr, nvarStr;
Integer varSize, eqnSize, numCheckpoints;
BackendDAE.EqSystem syst;
algorithm
numCheckpoints:=ErrorExt.getNumCheckpoints();
try
Expand Down Expand Up @@ -148,7 +149,8 @@ algorithm
ieqnarr := BackendEquation.listEquation(ieqns);
einfo := BackendDAE.EVENT_INFO(timeEvents, ZeroCrossings.new(), DoubleEndedList.fromList({}), ZeroCrossings.new(), 0);
symjacs := {(NONE(), ({}, {}, ({}, {}), -1), {}), (NONE(), ({}, {}, ({}, {}), -1), {}), (NONE(), ({}, {}, ({}, {}), -1), {}), (NONE(), ({}, {}, ({}, {}), -1), {})};
outBackendDAE := BackendDAE.DAE(BackendDAEUtil.createEqSystem(vars_1, eqnarr, {}, BackendDAE.UNKNOWN_PARTITION(), reqnarr)::{},
syst := BackendDAEUtil.createEqSystem(vars_1, eqnarr, {}, BackendDAE.UNKNOWN_PARTITION(), reqnarr);
outBackendDAE := BackendDAE.DAE(syst::{},
BackendDAE.SHARED(globalKnownVars,
localKnownVars,
extVars,
Expand All @@ -167,17 +169,11 @@ algorithm
BackendDAEUtil.emptyPartitionsInfo()
));
BackendDAEUtil.checkBackendDAEWithErrorMsg(outBackendDAE);
varSize := BackendVariable.varsSize(vars_1);
eqnSize := BackendEquation.equationArraySize(eqnarr);
neqStr := intString(eqnSize);
nvarStr := intString(varSize);

if varSize <> eqnSize then
Error.addMessage(if varSize > eqnSize then Error.UNDERDET_EQN_SYSTEM else Error.OVERDET_EQN_SYSTEM, {neqStr, nvarStr});
fail();
end if;
BackendDAEUtil.checkIncidenceMatrixSolvability(syst, functionTree);

Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.DUMP_BACKENDDAE_INFO),Error.BACKENDDAEINFO_LOWER,{neqStr,nvarStr},Absyn.dummyInfo);
if Flags.isSet(Flags.DUMP_BACKENDDAE_INFO) then
Error.addSourceMessage(Error.BACKENDDAEINFO_LOWER,{String(BackendEquation.equationArraySize(syst.orderedEqs)), String(BackendVariable.varsSize(syst.orderedVars))},Absyn.dummyInfo);
end if;
execStat("Generate backend data structure");
return;
else
Expand Down
2 changes: 1 addition & 1 deletion Compiler/BackEnd/BackendDAEOptimize.mo
Expand Up @@ -1662,7 +1662,7 @@ algorithm
b = i > 1;
// bcall2(b,BackendDump.dumpBackendDAE,BackendDAE.DAE({syst},shared), "partitionIndependentBlocksHelper");
// printPartition(b,ixs);
systs = if b then SynchronousFeatures.partitionIndependentBlocksSplitBlocks(i, syst, eqPartMap, rixs, mT, rmT, throwNoError) else {syst};
systs = if b then SynchronousFeatures.partitionIndependentBlocksSplitBlocks(i, syst, eqPartMap, rixs, mT, rmT, throwNoError, funcs) else {syst};
// print("Number of partitioned systems: " + intString(listLength(systs)) + "\n");
// List.map1_0(systs, BackendDump.dumpEqSystem, "System");
GC.free(eqPartMap);
Expand Down
179 changes: 177 additions & 2 deletions Compiler/BackEnd/BackendDAEUtil.mo
Expand Up @@ -156,8 +156,10 @@ algorithm
Boolean samesize;
BackendDAE.Variables vars;
BackendDAE.EquationArray orderedEqs;
BackendDAE.EqSystem syst;
DAE.FunctionTree functionTree;

case (BackendDAE.DAE(eqs=BackendDAE.EQSYSTEM(orderedVars=vars, orderedEqs=orderedEqs)::{})) equation
case BackendDAE.DAE(eqs=(syst as BackendDAE.EQSYSTEM(orderedVars=vars, orderedEqs=orderedEqs))::{}, shared=BackendDAE.SHARED(functionTree=functionTree)) equation
//true = Flags.isSet(Flags.CHECK_BACKEND_DAE);
//Check for correct size
nVars = BackendVariable.varsSize(vars);
Expand Down Expand Up @@ -271,7 +273,7 @@ algorithm
equation
allvars = BackendVariable.mergeVariables(syst.orderedVars, shared.globalKnownVars);
((_, expcrefs)) = traverseBackendDAEExpsVars(syst.orderedVars, checkBackendDAEExp, (allvars, {}));
((_, expcrefs)) = traverseBackendDAEExpsEqns(shared.removedEqs, checkBackendDAEExp, (allvars, expcrefs));
((_, expcrefs)) = traverseBackendDAEExpsEqns(shared.removedEqs, checkBackendDAEExp, (allvars, expcrefs));
((_, expcrefs)) = traverseBackendDAEExpsVars(shared.globalKnownVars, checkBackendDAEExp, (allvars, expcrefs));
((_, expcrefs)) = traverseBackendDAEExpsEqns(syst.orderedEqs, checkBackendDAEExp, (allvars, expcrefs));
((_, expcrefs)) = traverseBackendDAEExpsEqns(syst.removedEqs, checkBackendDAEExp, (allvars, expcrefs));
Expand Down Expand Up @@ -9060,5 +9062,178 @@ algorithm
end for;
end getNoDerivativeInputPosition;

public function checkIncidenceMatrixSolvability "Performs a limited matching algorithm to sometimes figure out which equations are superflours or which variables are never solved for."
input BackendDAE.EqSystem syst;
input DAE.FunctionTree functionTree;
protected
Integer varSize, eqnSize, v, eq, count;
BackendDAE.IncidenceMatrix m, mT, mOrig, mTOrig;
list<Integer> vars, eqs, varsInOrig, eqsInOrig;
array<Integer> solvedVars;
array<list<tuple<DAE.ComponentRef,Integer>>> solvedEqs;
list<SourceInfo> infos;
list<tuple<DAE.ComponentRef,Integer>> names;
Integer errors = 0, numSolved = 0, eqSize, lenInfos, lenVars;
Boolean cont = true;
BackendDAE.Variables varsArray;
BackendDAE.Var var;
BackendDAE.EquationArray eqsArray;
BackendDAE.Equation _equation;
constant Boolean debug=false;
constant Boolean alwaysCheck=false;
SourceInfo info;
algorithm
varsArray := syst.orderedVars;
eqsArray := syst.orderedEqs;
varSize := BackendVariable.varsSize(varsArray);
eqnSize := BackendEquation.equationArraySize(eqsArray);
if varSize <> eqnSize then
Error.addMessage(if varSize > eqnSize then Error.UNDERDET_EQN_SYSTEM else Error.OVERDET_EQN_SYSTEM, {String(eqnSize), String(varSize)});
elseif not alwaysCheck then
return;
end if;
(_, mOrig, mTOrig) := BackendDAEUtil.getIncidenceMatrixfromOption(syst, BackendDAE.ABSOLUTE(), SOME(functionTree));

m := arrayCopy(mOrig);
mT := arrayCopy(mTOrig);

solvedVars := arrayCreate(arrayLength(mT), 0);
solvedEqs := arrayCreate(arrayLength(m), {});

if debug then
print("Got adjacency matrix "+String(varSize)+" "+String(arrayLength(m))+" "+String(eqnSize)+" "+String(arrayLength(mT))+"...\n");
end if;
count := 0;
while cont and count < 1000 loop
cont := false;
count := count+1;
for i in 1:arrayLength(m) /* Not eqnSize; that is the size including arrays */ loop
if not listEmpty(arrayGet(solvedEqs, i)) then
continue;
end if;
_equation := BackendEquation.get(eqsArray, i);
info := BackendEquation.equationInfo(_equation);
eqSize := BackendEquation.equationSize(_equation);
vars := arrayGet(m, i);
lenVars := listLength(vars);
if eqSize == 0 then
arrayUpdate(solvedEqs, i, {(DAE.emptyCref,0)});
continue;
end if;
if lenVars <= eqSize then
if lenVars < eqSize then
variableDoesNotFitInEquation(i, vars, mOrig, eqsArray, varsArray, solvedVars);
errors := errors+1;
if lenVars == 0 then
arrayUpdate(solvedEqs, i, (DAE.emptyCref,0)::arrayGet(solvedEqs,i));
end if;
end if;
for v in vars loop
var := BackendVariable.getVarAt(varsArray, v);
arrayUpdate(solvedEqs, i, (var.varName,v)::arrayGet(solvedEqs,i));
arrayUpdate(solvedVars, v, i);
eqs := arrayGet(mT, v);
for eq in eqs loop
// Remove references to the variable in other equations since we can't solve it there
arrayUpdate(m, eq, List.setDifference(arrayGet(m, eq), vars));
end for;
numSolved := numSolved+1;
end for;
cont := true;
end if;
end for;

if debug then
print("Number of equations solved: " + String(numSolved-errors) + "\n");
print("Number of errors: " + String(errors) + "\n");
end if;

for i in 1:arrayLength(mT) /* = varSize */ loop
if 0 <> arrayGet(solvedVars, i) then
continue;
end if;
eqs := arrayGet(mT, i);
var := BackendVariable.getVarAt(varsArray, i);
info := var.source.info;
if listLength(eqs) == 0 then
Error.addSourceMessage(Error.VAR_NO_REMAINING_EQN, {
ComponentReference.printComponentRefStr(var.varName),
stringAppendList(list("\n Equation " + String(eq) + ": " + BackendDump.equationString(BackendEquation.get(eqsArray, eq)) + ", which needs to solve for " + stringDelimitList(list(ComponentReference.printComponentRefStr(Util.tuple21(tpl)) for tpl in arrayGet(solvedEqs, eq)), ", ") for eq in arrayGet(mTOrig, i)))
}, info);
arrayUpdate(solvedVars, i, -1);
elseif listLength(eqs) == 1 then
{eq} := eqs;
eqSize := BackendEquation.equationSize(BackendEquation.get(eqsArray, eq));
names := arrayGet(solvedEqs, eq);
lenInfos := listLength(names);
arrayUpdate(solvedVars, i, eq);
arrayUpdate(solvedEqs, eq, (var.varName,i)::names);
if lenInfos >= eqSize then
variableDoesNotFitInEquation(eq, {i}, mOrig, eqsArray, varsArray, solvedVars);
errors := errors+1;
end if;
vars := arrayGet(m, eq);
if lenInfos+1 >= eqSize then // TODO: FIXME
for v in vars loop
// Remove references to the equation in other variables since we can't solve it there
arrayUpdate(mT, v, List.setDifference(arrayGet(mT, v), eqs));
end for;
end if;
numSolved := numSolved+1;
cont := true;
end if;
end for;

if debug then
print("Number of equations solved: " + String(numSolved-errors) + "\n");
print("Number of errors: " + String(errors) + "\n");
end if;
end while;
true := 0 == errors;
if alwaysCheck and varSize == eqnSize then
return;
end if;
fail();
end checkIncidenceMatrixSolvability;

protected function variableDoesNotFitInEquation
input Integer eq;
input list<Integer> vars;
input BackendDAE.IncidenceMatrix m;
input BackendDAE.EquationArray eqsArray;
input BackendDAE.Variables varsArray;
input array<Integer> solvedVars;
protected
BackendDAE.Equation _equation;
list<Integer> varsInOrig, eqsInOrig;
String eqsString;
SourceInfo info;
Integer eqSize;
algorithm
_equation := BackendEquation.get(eqsArray, eq);
info := BackendEquation.equationInfo(_equation);
eqSize := BackendEquation.equationSize(_equation);

varsInOrig := List.setDifference(arrayGet(m, eq), vars);
eqsInOrig := List.sortedUnique(List.sort(list(arrayGet(solvedVars,myVar) for myVar guard arrayGet(solvedVars,myVar)>0 in varsInOrig), intGt), intEq);
eqsString := stringAppendList(list("\n Equation " + String(eqNum) + " (size: "+String(BackendEquation.equationSize(BackendEquation.get(eqsArray, eqNum)))+"): " + BackendDump.equationString(BackendEquation.get(eqsArray, eqNum)) for eqNum in eqsInOrig));
Error.addSourceMessage(Error.EQN_NO_SPACE_TO_SOLVE, {
String(eq),
String(eqSize),
BackendDump.equationString(_equation),
getVariableNamesForErrorMessage(varsArray, vars),
getVariableNamesForErrorMessage(varsArray, varsInOrig),
eqsString
}, info);
end variableDoesNotFitInEquation;

protected function getVariableNamesForErrorMessage
input BackendDAE.Variables varsArray;
input list<Integer> vars;
output String names;
algorithm
names := stringDelimitList(list(ComponentReference.printComponentRefStr(BackendVariable.varCref(BackendVariable.getVarAt(varsArray, v))) for v in vars), ", ");
end getVariableNamesForErrorMessage;

annotation(__OpenModelica_Interface="backend");
end BackendDAEUtil;
2 changes: 2 additions & 0 deletions Compiler/BackEnd/Causalize.mo
Expand Up @@ -100,6 +100,7 @@ algorithm
esize_str = intString(neqns);
vsize_str = intString(nvars);
Error.addMessage(Error.UNDERDET_EQN_SYSTEM, {esize_str,vsize_str});
BackendDAEUtil.checkIncidenceMatrixSolvability(isyst, ishared.functionTree);
then
fail();

Expand All @@ -109,6 +110,7 @@ algorithm
esize_str = intString(neqns) ;
vsize_str = intString(nvars);
Error.addMessage(Error.OVERDET_EQN_SYSTEM, {esize_str,vsize_str});
BackendDAEUtil.checkIncidenceMatrixSolvability(isyst, ishared.functionTree);
then
fail();

Expand Down
10 changes: 4 additions & 6 deletions Compiler/BackEnd/SynchronousFeatures.mo
Expand Up @@ -2600,7 +2600,7 @@ algorithm
partitionCnt := partitionIndependentBlocks0(m, mT, rm, rmT, eqPartMap, varPartMap, reqsPartition, varsPartition, rvarsPartition);

if partitionCnt > 1 then
(systs, outUnpartRemEqs) := partitionIndependentBlocksSplitBlocks(partitionCnt, syst, eqPartMap, reqsPartition, mT, rmT, false);
(systs, outUnpartRemEqs) := partitionIndependentBlocksSplitBlocks(partitionCnt, syst, eqPartMap, reqsPartition, mT, rmT, false, funcs);
else
(systs, outUnpartRemEqs) := ({syst}, {});
end if;
Expand Down Expand Up @@ -3049,14 +3049,14 @@ public function partitionIndependentBlocksSplitBlocks
input BackendDAE.IncidenceMatrix mT;
input BackendDAE.IncidenceMatrix rmT;
input Boolean throwNoError;
input DAE.FunctionTree funcs;
output list<BackendDAE.EqSystem> systs = {};
output list<BackendDAE.Equation> unpartRemovedEqs;
output array<Integer> varPartMap;
protected
array<list<BackendDAE.Equation>> ea, rea;
array<list<BackendDAE.Var>> va;
Integer i1, i2;
String s1, s2;
Boolean b, b1 = true;
BackendDAE.EqSystem syst;
array<Integer> varsPartition;
Expand All @@ -3070,10 +3070,8 @@ algorithm
i2 := BackendVariable.varsSize(inSyst.orderedVars);

if i1 <> i2 and not throwNoError then
s1 := intString(i1);
s2 := intString(i2);
Error.addSourceMessage(if i1 > i2 then Error.OVERDET_EQN_SYSTEM else Error.UNDERDET_EQN_SYSTEM,
{s1, s2}, Absyn.dummyInfo);
Error.addSourceMessage(if i1 > i2 then Error.OVERDET_EQN_SYSTEM else Error.UNDERDET_EQN_SYSTEM, {String(i1), String(i2)}, Absyn.dummyInfo);
BackendDAEUtil.checkIncidenceMatrixSolvability(inSyst, funcs);
fail();
end if;

Expand Down
4 changes: 4 additions & 0 deletions Compiler/Util/Error.mo
Expand Up @@ -879,6 +879,10 @@ public constant Message CLASS_EXTENDS_TARGET_NOT_FOUND = MESSAGE(579, TRANSLATIO
Util.gettext("Base class targeted by class extends %s not found in the inherited classes."));
public constant Message ASSIGN_PARAM_FIXED_ERROR = MESSAGE(580, TRANSLATION(), ERROR(),
Util.gettext("Trying to assign to parameter component %s(fixed=true) in %s := %s"));
public constant Message EQN_NO_SPACE_TO_SOLVE = MESSAGE(581, SYMBOLIC(), WARNING(),
Util.gettext("Equation %s (size: %s) %s is not big enough to solve for enough variables.\n Remaining unsolved variables are: %s\n Already solved: %s\n Equations used to solve those variables:%s"));
public constant Message VAR_NO_REMAINING_EQN = MESSAGE(582, SYMBOLIC(), WARNING(),
Util.gettext("Variable %s does not have any remaining equation to be solved in.\n The original equations were:%s"));

public constant Message MATCH_SHADOWING = MESSAGE(5001, TRANSLATION(), ERROR(),
Util.gettext("Local variable '%s' shadows another variable."));
Expand Down

0 comments on commit 24c3047

Please sign in to comment.