Skip to content

Commit 3eea6ab

Browse files
authored
Fix operations in UnorderedSet (#9470)
* Fix operations in UnorderedSet Applying a function to set elements requires a rehash and can produce duplicates if the function is not injective. * Skip applying the identity map
1 parent a7cbb77 commit 3eea6ab

File tree

2 files changed

+96
-17
lines changed

2 files changed

+96
-17
lines changed

OMCompiler/Compiler/Util/SBLinearMap.mo

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ public
108108
output Boolean empty = arrayEmpty(map.gain);
109109
end isEmpty;
110110

111+
function isIdentity
112+
input SBLinearMap map;
113+
output Boolean isIdentity;
114+
algorithm
115+
isIdentity := Array.all(map.gain, function realEq(x1 = 1.0)) and
116+
Array.all(map.offset, function realEq(x1 = 0.0));
117+
end isIdentity;
118+
111119
function isEqual
112120
input SBLinearMap map1;
113121
input SBLinearMap map2;
@@ -180,7 +188,9 @@ public
180188
input SBLinearMap map;
181189
output SBSet target = SBSet.copy(domain);
182190
algorithm
183-
UnorderedSet.map(target.asets, function applyAtomicSet(map = map));
191+
if not isIdentity(map) then
192+
UnorderedSet.apply(target.asets, function applyAtomicSet(map = map));
193+
end if;
184194
end apply;
185195

186196
function applyAtomicSet

OMCompiler/Compiler/Util/UnorderedSet.mo

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -278,22 +278,6 @@ public
278278
end for;
279279
end toArray;
280280

281-
function map
282-
"Maps all keys in the set."
283-
input UnorderedSet<T> set;
284-
input MapFn fn;
285-
partial function MapFn
286-
input output T key;
287-
end MapFn;
288-
protected
289-
array<list<T>> new_buckets = Mutable.access(set.buckets);
290-
algorithm
291-
for b in 1:arrayLength(new_buckets) loop
292-
new_buckets[b] := list(fn(k) for k in new_buckets[b]);
293-
end for;
294-
Mutable.update(set.buckets, new_buckets);
295-
end map;
296-
297281
function fold<FT>
298282
"Folds over the keys in the set."
299283
input UnorderedSet<T> set;
@@ -313,6 +297,91 @@ public
313297
end for;
314298
end fold;
315299

300+
/*
301+
function map<OT>
302+
"Applies a function to all keys in the given set and returns a new set
303+
with the new keys."
304+
input UnorderedSet<T> set;
305+
input MapFn fn;
306+
input OutHash hash;
307+
input OutKeyEq keyEq;
308+
output UnorderedSet<OT> outSet;
309+
310+
partial function MapFn
311+
input T key;
312+
output OT outKey;
313+
end MapFn;
314+
partial function OutHash
315+
input OT key;
316+
input Integer mod;
317+
output Integer hash;
318+
end OutHash;
319+
partial function OutKeyEq
320+
input OT key1;
321+
input OT key2;
322+
output Boolean equal;
323+
end OutKeyEq;
324+
algorithm
325+
outSet := new<OT>(hash, keyEq, Util.nextPrime(Mutable.access(set.size)));
326+
for b in Mutable.access(set.buckets) loop
327+
for k in b loop
328+
add(fn(k), outSet);
329+
end for;
330+
end for;
331+
end map;
332+
*/
333+
334+
function apply
335+
"Replaces all keys in the given set with the results of the given function
336+
when applied to all keys. Equivalent to a rehash."
337+
input UnorderedSet<T> set;
338+
input ApplyFn fn;
339+
340+
partial function ApplyFn
341+
input output T key;
342+
end ApplyFn;
343+
protected
344+
Hash hashfn = set.hashFn;
345+
KeyEq eqfn = set.eqFn;
346+
Integer bucket_count, hash, size = 0;
347+
array<list<T>> new_buckets;
348+
T newKey;
349+
list<T> bucket;
350+
Boolean duplicate;
351+
algorithm
352+
// Make a new bucket array.
353+
bucket_count := Util.nextPrime(Mutable.access(set.size));
354+
new_buckets := arrayCreate(bucket_count, {});
355+
356+
for b in Mutable.access(set.buckets) loop
357+
for k in b loop
358+
// Apply the function to the key
359+
newKey := fn(k);
360+
hash := hashfn(newKey, bucket_count);
361+
bucket := arrayGet(new_buckets, hash + 1);
362+
363+
// check if we have a duplicate
364+
duplicate := false;
365+
for nk in bucket loop
366+
if eqfn(nk, newKey) then
367+
duplicate := true;
368+
break;
369+
end if;
370+
end for;
371+
372+
// Add the result to the new bucket if it is not already there.
373+
if not duplicate then
374+
arrayUpdate(new_buckets, hash + 1, newKey :: bucket);
375+
size := size + 1;
376+
end if;
377+
end for;
378+
end for;
379+
380+
// Replace the old bucket array with the new one and update the size of the set.
381+
Mutable.update(set.buckets, new_buckets);
382+
Mutable.update(set.size, size);
383+
end apply;
384+
316385
function all
317386
"Returns true if the given function returns true for all elements in the set,
318387
otherwise false."

0 commit comments

Comments
 (0)