Skip to content

Commit

Permalink
[NF] Change behaviour of ClassTree.flatten.
Browse files Browse the repository at this point in the history
- Change ClassTree.flatten to completely remove duplicate components,
  instead of replacing them with empty nodes. This is slightly slower
  when there are duplicates since the lookup tree also needs to be
  updated, but removes the need to check for empty nodes when
  iterating over components (so probably faster in general since
  duplicate elements are not that common).

  This also fixes issues with field lookup in record expressions, which
  did not take into account the possibility of gaps in the component
  arrays for records with duplicate fields, leading to the expression
  for the wrong field sometimes being returned.
  • Loading branch information
perost committed Feb 20, 2020
1 parent 98eb3e7 commit fa23154
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 77 deletions.
121 changes: 110 additions & 11 deletions OMCompiler/Compiler/NFFrontEnd/NFClassTree.mo
Expand Up @@ -852,46 +852,143 @@ public
end appendComponentsToInstTree;

function flatten
"Flattens a class tree by creating new arrays for the classes and
components with any duplicates removed and with the elements no longer
being mutable references."
input output ClassTree tree;
algorithm
tree := match tree
local
array<InstNode> clss, comps;
array<Integer> comp_offsets;
Integer clsc, compc;
list<Integer> dup_cls, dup_comp;
list<Integer> dup_comp;
LookupTree.Tree ltree;

case INSTANTIATED_TREE()
algorithm
(dup_cls, dup_comp) := enumerateDuplicates(tree.duplicates);
// Create a list of indices for any duplicates.
(_, dup_comp) := enumerateDuplicates(tree.duplicates);

// Allocate new arrays for classes and components.
clsc := arrayLength(tree.classes);
compc := arrayLength(tree.components);
compc := arrayLength(tree.components) - listLength(dup_comp);
clss := arrayCreateNoInit(clsc, InstNode.EMPTY_NODE());
comps := arrayCreateNoInit(compc, InstNode.EMPTY_NODE());

flatten2(tree.classes, clss, dup_cls);
flatten2(tree.components, comps, dup_comp);
// Class duplicates can be ignored since classes are only accessed
// through name lookup and not index, so there's no need to spend
// time on filtering them out.
flattenElements(tree.classes, clss);

// Component duplicates should be removed though, since we don't
// want any duplicates in the flat model.
if listEmpty(dup_comp) then
// No duplicates, just copy to new array.
flattenElements(tree.components, comps);
ltree := tree.tree;
else
// Duplicates, create an array of offsets and use it to fill the
// new array and update the lookup tree.
comp_offsets := createFlatOffsets(arrayLength(tree.components), dup_comp);
flattenElementsWithOffset(tree.components, comps, comp_offsets);
ltree := flattenLookupTree(tree.tree, comp_offsets);
end if;
then
FLAT_TREE(tree.tree, clss, comps, tree.imports, tree.duplicates);
FLAT_TREE(ltree, clss, comps, tree.imports, tree.duplicates);

else tree;
end match;
end flatten;

function flatten2
function flattenElements
"Copies elements from one array to another while removing the Mutable
container for each element."
input array<Mutable<InstNode>> elements;
input array<InstNode> flatElements;
input list<Integer> duplicates;
algorithm
for i in 1:arrayLength(elements) loop
arrayUpdateNoBoundsChecking(flatElements, i,
Mutable.access(arrayGetNoBoundsChecking(elements, i)));
end for;
end flattenElements;

function flattenElementsWithOffset
input array<Mutable<InstNode>> elements;
input array<InstNode> flatElements;
input array<Integer> offsets;
protected
Integer offset;
algorithm
for i in 1:arrayLength(elements) loop
offset := arrayGetNoBoundsChecking(offsets, i);

if offset >= 0 then
arrayUpdateNoBoundsChecking(flatElements, i - offset,
Mutable.access(arrayGetNoBoundsChecking(elements, i)));
end if;
end for;
end flattenElementsWithOffset;

function createFlatOffsets
"Creates an array of offsets given an element count and a sorted list of
duplicate indices. The offsets indicate how many positions each element
is shifted when removing the duplicate elements. The duplicates are
marked with -1 in the array. For example:
createFlatOffsets(7, {2, 4, 5}) => {0, -1, 1, -1, -1, 3, 3}
"
input Integer elementCount;
input list<Integer> duplicates;
output array<Integer> offsets;
protected
Integer offset = 0;
Integer dup;
list<Integer> rest_dups;
algorithm
offsets := arrayCreateNoInit(elementCount, 0);
dup :: rest_dups := duplicates;

for i in duplicates loop
arrayUpdateNoBoundsChecking(flatElements, i, InstNode.EMPTY_NODE());
for i in 1:elementCount loop

if i == dup then
if listEmpty(rest_dups) then
dup := 0;
else
dup :: rest_dups := rest_dups;
end if;

offset := offset + 1;
arrayUpdateNoBoundsChecking(offsets, i, -1);
else
arrayUpdateNoBoundsChecking(offsets, i, offset);
end if;
end for;
end flatten2;
end createFlatOffsets;

function flattenLookupTree
"Traverses a lookup tree and shifts the index of each component entry by
using the given offset array, such that the lookup tree can be used to
look up components when any duplicates have been removed from the
component array."
input output LookupTree.Tree tree;
input array<Integer> offsets;
algorithm
tree := LookupTree.map(tree, function flattenLookupTree2(offsets = offsets));
end flattenLookupTree;

function flattenLookupTree2
input LookupTree.Key key;
input LookupTree.Entry entry;
input array<Integer> offsets;
output LookupTree.Entry outEntry;
algorithm
outEntry := match entry
case LookupTree.Entry.COMPONENT()
then LookupTree.Entry.COMPONENT(entry.index - arrayGetNoBoundsChecking(offsets, entry.index));

else entry;
end match;
end flattenLookupTree2;

function lookupElement
"Returns the class or component with the given name in the class tree."
Expand Down Expand Up @@ -1949,6 +2046,8 @@ public
components := {};
else
(classes, components) := DuplicateTree.fold_2(duplicates, enumerateDuplicates2, {}, {});
classes := List.sort(classes, intGt);
components := List.sort(components, intGt);
end if;
end enumerateDuplicates;

Expand Down
5 changes: 2 additions & 3 deletions OMCompiler/Compiler/NFFrontEnd/NFConvertDAE.mo
Expand Up @@ -1131,11 +1131,10 @@ protected
algorithm
typeVars := match cls as InstNode.getClass(complexCls)
case Class.INSTANCED_CLASS(restriction = Restriction.RECORD())
then list(makeTypeRecordVar(c) for c guard not InstNode.isEmpty(c)
in ClassTree.getComponents(cls.elements));
then list(makeTypeRecordVar(c) for c in ClassTree.getComponents(cls.elements));

case Class.INSTANCED_CLASS(elements = ClassTree.FLAT_TREE())
then list(makeTypeVar(c) for c guard not (InstNode.isOnlyOuter(c) or InstNode.isEmpty(c))
then list(makeTypeVar(c) for c guard not InstNode.isOnlyOuter(c)
in ClassTree.getComponents(cls.elements));

else {};
Expand Down
14 changes: 4 additions & 10 deletions OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo
Expand Up @@ -254,7 +254,7 @@ protected
Visibility vis;
algorithm
// Remove components that are only outer.
if InstNode.isOnlyOuter(component) or InstNode.isEmpty(component) then
if InstNode.isOnlyOuter(component) then
return;
end if;

Expand Down Expand Up @@ -348,11 +348,9 @@ algorithm
return;
end if;

if not InstNode.isEmpty(compNode) then
comp := InstNode.component(compNode);
InstNode.updateComponent(Component.DELETED_COMPONENT(comp), compNode);
deleteClassComponents(Component.classInstance(comp));
end if;
comp := InstNode.component(compNode);
InstNode.updateComponent(Component.DELETED_COMPONENT(comp), compNode);
deleteClassComponents(Component.classInstance(comp));
end deleteComponent;

function deleteClassComponents
Expand Down Expand Up @@ -1711,10 +1709,6 @@ algorithm
case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE(), sections = sections)
algorithm
for c in cls_tree.components loop
if InstNode.isEmpty(c) then
continue;
end if;

comp := InstNode.component(c);
funcs := collectTypeFuncs(Component.getType(comp), funcs);
binding := Component.getBinding(comp);
Expand Down
56 changes: 25 additions & 31 deletions OMCompiler/Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -1675,38 +1675,36 @@ uniontype Function
Type ty;
Boolean dirty = false;
algorithm
if not InstNode.isEmpty(node) then
comp := InstNode.component(node);
binding := Component.getBinding(comp);
binding2 := Binding.mapExp(binding, mapFn);

if not referenceEq(binding, binding2) then
comp := Component.setBinding(binding2, comp);
dirty := true;
end if;
comp := InstNode.component(node);
binding := Component.getBinding(comp);
binding2 := Binding.mapExp(binding, mapFn);

() := match comp
case Component.TYPED_COMPONENT()
algorithm
ty := Type.mapDims(comp.ty, function Dimension.mapExp(func = mapFn));
if not referenceEq(binding, binding2) then
comp := Component.setBinding(binding2, comp);
dirty := true;
end if;

if not referenceEq(ty, comp.ty) then
comp.ty := ty;
dirty := true;
end if;
() := match comp
case Component.TYPED_COMPONENT()
algorithm
ty := Type.mapDims(comp.ty, function Dimension.mapExp(func = mapFn));

cls := InstNode.getClass(comp.classInst);
ClassTree.applyComponents(Class.classTree(cls),
function mapExpParameter(mapFn = mapFn));
then
();
if not referenceEq(ty, comp.ty) then
comp.ty := ty;
dirty := true;
end if;

else ();
end match;
cls := InstNode.getClass(comp.classInst);
ClassTree.applyComponents(Class.classTree(cls),
function mapExpParameter(mapFn = mapFn));
then
();

if dirty then
InstNode.updateComponent(comp, node);
end if;
else ();
end match;

if dirty then
InstNode.updateComponent(comp, node);
end if;
end mapExpParameter;

Expand Down Expand Up @@ -1736,10 +1734,6 @@ protected
for i in arrayLength(comps):-1:1 loop
n := comps[i];

if InstNode.isEmpty(n) then
continue;
end if;

// Sort the components based on their direction.
() := match paramDirection(n)
case Direction.INPUT algorithm inputs := n :: inputs; then ();
Expand Down
4 changes: 1 addition & 3 deletions OMCompiler/Compiler/NFFrontEnd/NFInst.mo
Expand Up @@ -3267,9 +3267,7 @@ algorithm
case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE())
algorithm
for c in cls_tree.components loop
if not InstNode.isEmpty(c) then
updateImplicitVariabilityComp(c, evalAllParams);
end if;
updateImplicitVariabilityComp(c, evalAllParams);
end for;

Sections.apply(cls.sections,
Expand Down
6 changes: 2 additions & 4 deletions OMCompiler/Compiler/NFFrontEnd/NFPackage.mo
Expand Up @@ -177,10 +177,8 @@ public
sections = sections)
algorithm
for c in comps loop
if not InstNode.isEmpty(c) then
constants := collectBindingConstants(
Component.getBinding(InstNode.component(c)), constants);
end if;
constants := collectBindingConstants(
Component.getBinding(InstNode.component(c)), constants);
end for;

() := match sections
Expand Down
4 changes: 0 additions & 4 deletions OMCompiler/Compiler/NFFrontEnd/NFRecord.mo
Expand Up @@ -161,10 +161,6 @@ protected
Component comp;
InstNode comp_node = InstNode.resolveInner(component);
algorithm
if InstNode.isEmpty(comp_node) then
return;
end if;

if InstNode.isProtected(comp_node) then
locals := comp_node :: locals;
return;
Expand Down
12 changes: 1 addition & 11 deletions OMCompiler/Compiler/NFFrontEnd/NFTyping.mo
Expand Up @@ -205,9 +205,7 @@ algorithm
case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE())
algorithm
for c in cls_tree.components loop
if not InstNode.isEmpty(c) then
typeComponent(c, origin);
end if;
typeComponent(c, origin);
end for;

() := match c.ty
Expand Down Expand Up @@ -842,10 +840,6 @@ protected
Variability comp_var, comp_eff_var, bind_var, bind_eff_var;
Component.Attributes attrs;
algorithm
if InstNode.isEmpty(component) then
return;
end if;

c := InstNode.component(node);

() := match c
Expand Down Expand Up @@ -2473,10 +2467,6 @@ function typeComponentSections
protected
Component comp;
algorithm
if InstNode.isEmpty(component) then
return;
end if;

comp := InstNode.component(component);

() := match comp
Expand Down

0 comments on commit fa23154

Please sign in to comment.