Skip to content

Commit

Permalink
Fix for bug #2033:
Browse files Browse the repository at this point in the history
- Rewrote Static.promoteExp to be more efficient and not mess up the types.
- Added simplification min/max(multi-dim array) => min/max(flat array).


git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@15061 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
perost committed Feb 5, 2013
1 parent 75e0837 commit afcb08d
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 106 deletions.
154 changes: 154 additions & 0 deletions Compiler/FrontEnd/Expression.mo
Original file line number Diff line number Diff line change
Expand Up @@ -9151,5 +9151,159 @@ algorithm
end match;
end equationExpEqual;

public function promoteExp
"This function corresponds to the promote function described in the Modelica
spec. It takes an expression, the type of the expression and a number of
dimensions, and adds dimensions of size 1 to the right of the expression
until the expression has as many dimensions as given. It also returns the
type of the promoted expression. E.g.:
promoteExp({1, 2, 3}, Integer[3], 3) =>
({{{1}}, {{2}}, {{3}}}, Integer[3,1,1])

The reason why this function takes a type instead of using the type of the
expression is because it's used by Static.promoteExp, which already knows the
type."
input DAE.Exp inExp;
input DAE.Type inType;
input Integer inDims;
output DAE.Exp outExp;
output DAE.Type outType;
algorithm
(outExp, outType) := matchcontinue(inExp, inType, inDims)
local
Integer dim_count, dims_to_add;
DAE.Type ty, res_ty;
DAE.Exp exp;
list<DAE.Type> tys;
list<DAE.Dimension> dims, added_dims;
Boolean is_array_ty;

case (_, _, _)
equation
// Figure out how many dimensions we need to add.
dims_to_add = inDims - Types.numberOfDimensions(inType);
// If the expression already has at least as many dimensions as we want,
// fail and return the unchanged expression.
true = dims_to_add > 0;

// Construct all the types we will need here, to avoid having to
// construct new types for all the subexpressions created.
dims = Types.getDimensions(inType);
// Add as many dimensions of size 1 as needed.
added_dims = List.fill(DAE.DIM_INTEGER(1), dims_to_add);
dims = listAppend(dims, added_dims);
// Construct the result type.
ty = Types.arrayElementType(inType);
res_ty = Types.liftArrayListDims(ty, dims);
// Construct the expression types.
ty = Types.simplifyType(ty);
tys = makePromotedTypes(dims, ty, {});

// Use the constructed types to promote the expression.
is_array_ty = Types.isArray(inType, {});
exp = promoteExp2(inExp, is_array_ty, dims_to_add, tys);
then
(exp, res_ty);

else (inExp, inType);

end matchcontinue;
end promoteExp;

protected function makePromotedTypes
"Creates a lift of types given a list of dimensions and an element type. The
types are created by removing the head of the dimension list one by one and
creating types from the remaining dimensions. E.g.:
makePromotedTypes({[2], [3], [1]}, Real) =>
{Real[2,3,1], Real[3,1], Real[1]}
"
input list<DAE.Dimension> inDimensions;
input DAE.Type inElementType;
input list<DAE.Type> inAccumTypes;
output list<DAE.Type> outAccumTypes;
algorithm
outAccumTypes := match(inDimensions, inElementType, inAccumTypes)
local
list<DAE.Dimension> rest_dims;
DAE.Type ty;

case (_ :: rest_dims, _, _)
equation
ty = DAE.T_ARRAY(inElementType, inDimensions, DAE.emptyTypeSource);
then
makePromotedTypes(rest_dims, inElementType, ty :: inAccumTypes);

case ({}, _, _) then listReverse(inAccumTypes);

end match;
end makePromotedTypes;

protected function promoteExp2
"Helper function to promoteExp."
input DAE.Exp inExp;
input Boolean inIsArray;
input Integer inDims;
input list<DAE.Type> inTypes;
output DAE.Exp outExp;
algorithm
outExp := match(inExp, inIsArray, inDims, inTypes)
local
DAE.Type ty;
list<DAE.Exp> expl;
list<DAE.Type> rest_ty;

// No types left, we're done!
case (_, _, _, {}) then inExp;

// An array, promote each element in the array.
case (DAE.ARRAY(_, _, expl), _, _, ty :: rest_ty)
equation
expl = List.map3(expl, promoteExp2, false, inDims, rest_ty);
then
DAE.ARRAY(ty, false, expl);

// An expression with array type, but which is not an array expression. Such
// an expression can't be promoted here, so we create a promote call instead.
case (_, true, _, ty :: _)
then makeBuiltinCall("promote", {inExp, DAE.ICONST(inDims)}, ty);

// Any other expression, call promoteExp3.
else promoteExp3(inExp, inTypes);

end match;
end promoteExp2;

protected function promoteExp3
"Helper function to promoteExp2. Promotes a scalar expression as many times as
the number of types given."
input DAE.Exp inExp;
input list<DAE.Type> inTypes;
output DAE.Exp outExp;
algorithm
outExp := match(inExp, inTypes)
local
DAE.Type ty;
list<DAE.Type> rest_ty;
DAE.Exp exp;

// No types left, were' done!
case (_, {}) then inExp;

// Only one type left, create a scalar array with it.
case (_, {ty}) then makeArray({inExp}, ty, true);

// Several types left. Promote the expression using the rest of the types,
// and then create an non-scalar array of the expression with the first type.
case (_, ty :: rest_ty)
equation
exp = promoteExp3(inExp, rest_ty);
then
makeArray({exp}, ty, false);

end match;
end promoteExp3;

end Expression;

13 changes: 13 additions & 0 deletions Compiler/FrontEnd/ExpressionSimplify.mo
Original file line number Diff line number Diff line change
Expand Up @@ -906,10 +906,23 @@ algorithm
Integer i,i1,i2,dim;
Real r1;
array<array<DAE.Exp>> marr;
String name;

// If the argument to min/max is an array, try to flatten it.
case (DAE.CALL(path=Absyn.IDENT(name),expLst={e as DAE.ARRAY(array=_)},
attr=DAE.CALL_ATTR(ty=tp)))
equation
true = stringEq(name, "max") or stringEq(name, "min");
expl = Expression.flattenArrayExpToList(e);
e1 = Expression.makeScalarArray(expl, tp);
false = Expression.expEqual(e, e1);
then
Expression.makeBuiltinCall(name, {e1}, tp);

// min/max function on arrays of only 1 element
case (DAE.CALL(path=Absyn.IDENT("min"),expLst={DAE.ARRAY(array={e})})) then e;
case (DAE.CALL(path=Absyn.IDENT("max"),expLst={DAE.ARRAY(array={e})})) then e;

// Try to unify the expressions :)
case (DAE.CALL(path=Absyn.IDENT("min"),expLst={DAE.ARRAY(array=es)},attr=DAE.CALL_ATTR(ty=tp)))
equation
Expand Down
125 changes: 19 additions & 106 deletions Compiler/FrontEnd/Static.mo
Original file line number Diff line number Diff line change
Expand Up @@ -2656,7 +2656,7 @@ algorithm
DAE.Exp el_1,el_2;
DAE.Properties prop,prop1,prop1_1,prop2;
DAE.Type t1,t1_1;
Integer t1_dim1,nmax_2,nmax,t1_ndims;
Integer t1_dim1,nmax;
DAE.Dimension t1_dim1_1,t1_dim2_1,dim1,dim2,dim2_1;
Boolean array,impl,havereal,a,scalar,doVect;
DAE.Type at;
Expand All @@ -2669,19 +2669,15 @@ algorithm

case (cache,env,{el_1},{prop as DAE.PROP(t1,_)},impl,st,havereal,nmax,doVect,pre,_) /* implicit inst. have real nmax dim1 dim2 */
equation
t1_dim1 = Types.numberOfDimensions(t1);
nmax_2 = nmax - t1_dim1;
(el_2,(prop as DAE.PROP(t1_1,_))) = promoteExp(el_1, prop, nmax_2);
(el_2,(prop as DAE.PROP(t1_1,_))) = promoteExp(el_1, prop, nmax);
(_,t1_dim1_1 :: (t1_dim2_1 :: _)) = Types.flattenArrayTypeOpt(t1_1);
at = Types.simplifyType(t1_1);
at = Expression.liftArrayLeft(at, DAE.DIM_INTEGER(1));
then
(cache,DAE.ARRAY(at,false,{el_2}),prop,t1_dim1_1,t1_dim2_1);
case (cache,env,(el_1 :: els),(prop1 as DAE.PROP(t1,_))::props,impl,st,havereal,nmax,doVect,pre,_)
equation
t1_ndims = Types.numberOfDimensions(t1);
nmax_2 = nmax - t1_ndims;
(el_2,(prop1_1 as DAE.PROP(t1_1,_))) = promoteExp(el_1, prop1, nmax_2);
(el_2,(prop1_1 as DAE.PROP(t1_1,_))) = promoteExp(el_1, prop1, nmax);
(_,t1_dim1_1 :: (t1_dim2_1 :: _)) = Types.flattenArrayTypeOpt(t1_1);
(cache,el_1 as DAE.ARRAY(at,a,els_1),prop2,dim1,dim2) = elabMatrixComma(cache,env, els, props, impl, st, havereal, nmax,doVect,pre,info);
dim2_1 = Expression.dimensionsAdd(t1_dim2_1,dim2)"comma between matrices => concatenation along second dimension" ;
Expand Down Expand Up @@ -2853,120 +2849,37 @@ algorithm
DAE.ARRAY(ty = DAE.T_ARRAY(dims = dim2 :: _), array = expl2) := inArray2;
expl := listAppend(expl1, expl2);
dim := Expression.dimensionsAdd(dim1, dim2);
outExp := DAE.ARRAY(DAE.T_ARRAY(ety, dim1 :: dim_rest, ts), at, expl);
outExp := DAE.ARRAY(DAE.T_ARRAY(ety, dim :: dim_rest, ts), at, expl);
end elabMatrixCatOne2;

protected function promoteExp "function: promoteExp
author: PA
Adds onesized array dimensions to an expressions n times to the right
of array dimensions.
For instance
promote_exp( {1,2},1) => {{1},{2}}
promote_exp( {1,2},2) => { {{1}},{{2}} }
See also promote_real_array in real_array.c"
protected function promoteExp
"Wrapper function for Expression.promoteExp which also handles Properties."
input DAE.Exp inExp;
input DAE.Properties inProperties;
input Integer inInteger;
input Integer inDims;
output DAE.Exp outExp;
output DAE.Properties outProperties;
algorithm
(outExp,outProperties) := matchcontinue (inExp,inProperties,inInteger)
(outExp, outProperties) := matchcontinue(inExp, inProperties, inDims)
local
DAE.Exp e,e_1,e_2;
DAE.Properties prop,prop_1;
Integer n_1,n;
DAE.Type tp_1,tp;
DAE.Type ty;
DAE.Const c;
case (e,prop,-1) then (e,prop); /* n */
case (e,prop,0) then (e,prop);
case (e,DAE.PROP(type_ = tp,constFlag = c),n)
equation
n_1 = n - 1;
//e_tp = Types.simplifyType(tp);
tp_1 = Types.liftArrayRight(tp, DAE.DIM_INTEGER(1));
//e_tp_1 = Types.simplifyType(tp_1);
//array = Expression.typeBuiltin(e_tp);
e_1 = promoteExp2(e, (n,tp));
(e_2,prop_1) = promoteExp(e_1, DAE.PROP(tp_1,c), n_1);
then
(e_2,prop_1);
case(_,_,_) equation
Debug.fprint(Flags.FAILTRACE,"-promoteExp failed\n");
then fail();
end matchcontinue;
end promoteExp;
DAE.Exp exp;

protected function promoteExp2
"function: promoteExp2
Helper function to promoteExp, adds
dimension to the right of the expression."
input DAE.Exp inExp;
input tuple<Integer, DAE.Type> inTplIntegerTypesType;
output DAE.Exp outExp;
algorithm
outExp := matchcontinue (inExp,inTplIntegerTypesType)
local
Integer n_1,n;
DAE.Type tp_1,tp,tp2;
list<DAE.Exp> expl_1,expl;
DAE.Type a,at,etp,tp1;
Boolean sc;
DAE.Exp e;
Ident es;

case (DAE.ARRAY(ty = a,scalar = sc,array = expl),(n,tp))
case (_, DAE.PROP(ty, c), _)
equation
n_1 = n - 1;
tp_1 = Types.unliftArray(tp);
a = Expression.liftArrayLeft(a, DAE.DIM_INTEGER(1));
expl_1 = List.map1(expl, promoteExp2, (n_1,tp_1));
(exp, ty) = Expression.promoteExp(inExp, ty, inDims);
then
DAE.ARRAY(a,false,expl_1);

// scalars can be promoted from s to {s}
case (e,(_,tp))
equation
false = Types.isArray(tp, {});
at = Expression.typeof(e);
then
DAE.ARRAY(DAE.T_ARRAY(at, {DAE.DIM_INTEGER(1)}, DAE.emptyTypeSource),true,{e});

// arrays of one dimension can be promoted from a to {a}
case (e,(_,DAE.T_ARRAY(dims = {DAE.DIM_INTEGER(integer = 1)}, ty = tp2)))
equation
at = Expression.typeof(e);
false = Types.isArray(tp2, {});
then
DAE.ARRAY(DAE.T_ARRAY(at,{DAE.DIM_INTEGER(1)},DAE.emptyTypeSource),true,{e});

// fallback, use builtin operator promote
case (e,(n,tp))
(exp, DAE.PROP(ty, c));

else
equation
es = ExpressionDump.printExpStr(e);
etp = Types.simplifyType(tp);
tp1 = promoteExpType(etp,n);
e = Expression.makeBuiltinCall("promote", {e, DAE.ICONST(n)}, tp1);
Debug.fprintln(Flags.FAILTRACE, "- Static.promoteExp failed");
then
e;
end matchcontinue;
end promoteExp2;
fail();

function promoteExpType "lifts the type using liftArrayRight n times"
input DAE.Type inType;
input Integer n;
output DAE.Type outType;
algorithm
outType := matchcontinue(inType,n)
local
DAE.Type tp1,tp2;
case (_,0) then inType;
case(_,_)
equation
tp1=Expression.liftArrayRight(inType, DAE.DIM_INTEGER(1));
tp2 = promoteExpType(tp1,n-1);
then tp2;
end matchcontinue;
end promoteExpType;
end promoteExp;

protected function elabMatrixSemi
"function: elabMatrixSemi
Expand Down Expand Up @@ -6091,7 +6004,7 @@ algorithm
case (_, _, _, _, _, _)
equation
1 = Types.numberOfDimensions(inType);
(exp, props) = promoteExp(inArg, inProperties, 1);
(exp, props) = promoteExp(inArg, inProperties, 2);
then
(exp, props);

Expand Down

0 comments on commit afcb08d

Please sign in to comment.