[m-rev.] for review: exploit sortedness in bag.m
Julien Fischer
jfischer at opturion.com
Sat Mar 9 21:19:51 AEDT 2024
On Sat, 9 Mar 2024, Zoltan Somogyi wrote:
> Act on some old XXXs in bag.m.
>
> library/bag.m:
> An old diff added several XXXs to this module about exploiting
> the sortedness of set inputs. This diff replaces one of those XXXs
> with code that does exploit that sortedness, and rewrites the others
> to document the reason why doing so in those cases is probably not
> a good idea.
>
> Add some dividers around function/predicate definition pairs
> that both implement the same operation, to make it easier to distinguish
> them from the previous and next such pairs, whose names are often
> very similar.
>
> diff --git a/library/bag.m b/library/bag.m
> index 5fb6306cb..41a596e9b 100644
> --- a/library/bag.m
> +++ b/library/bag.m
> @@ -474,12 +492,22 @@ det_insert_duplicates(N, Item, !Bag) :-
> error($pred, "number of items is negative")
> ).
>
> +%---------------------%
> +
> insert_set(!.Bag, Xs) = !:Bag :-
> bag.insert_set(Xs, !Bag).
>
> insert_set(Set, !Bag) :-
> set.to_sorted_list(Set, List),
> - % XXX We should exploit the sortedness of List.
> + % XXX We could try to exploit the sortedness of List, but
> + %
> + % - it would make a difference only if the size of Set
> + % is comparable to the number of keys in Bag, and
> + %
> + % - using a test to restrict the special casing to just
> + % the invocations for which it would help rather than hurt
> + % will impose its own cost as well, which would need
> + % to be paid on *all* invocations.
> bag.insert_list(List, !Bag).
I think you can omit the "XXX" since there's nothing that needs to be
addressed there, just documentation of an implementation choice.
...
> @@ -525,19 +561,33 @@ det_remove_list(Xs, !Bag) :-
> unexpected($pred, "some item not in bag")
> ).
>
> +%---------------------%
> +
> remove_set(Set, !Bag) :-
> set.to_sorted_list(Set, Xs),
> - % XXX We should exploit the sortedness of Xs.
> + % XXX We could try to exploit the sortedness of List, but
> + %
> + % - it would make a difference only if the size of Set
> + % is comparable to the number of keys in Bag, and
> + %
> + % - using a test to restrict the special casing to just
> + % the invocations for which it would help rather than hurt
> + % will impose its own cost as well, which would need
> + % to be paid on *all* invocations.
> bag.remove_list(Xs, !Bag).
Ditto.
...
> @@ -574,22 +628,42 @@ from_list(Xs, Bag) :-
> bag.init(Bag0),
> bag.insert_list(Xs, Bag0, Bag).
>
> +%---------------------%
> +
> from_sorted_list(Xs) = Bag :-
> bag.from_sorted_list(Xs, Bag).
>
> from_sorted_list(Xs, Bag) :-
> - bag.init(Bag0),
> - % XXX We should exploit the sortedness of Xs.
> - bag.insert_list(Xs, Bag0, Bag).
> + % Instead of adding each X in Xs one-by-one to an initially empty map,
> + % we construct the map in its final form directly.
> + %
> + % The approach we use here allocates only two memory cells per item
> + % that does not end up in the final result: the pair and cons cells.
s/does/do/
> + % For any list over about half a dozen items, this is fewer cells than
> + % would be used by intermediate forms of the map with the other approach.
> + % And for any list shorter than about half a dozedn items, the memory
s/dozedn/dozen/
> + % needed, and the time taken by allocations, would both be too small
> + % to matter either way.
> + acc_rev_items(Xs, [], RevXsOnes),
> + map.from_rev_sorted_assoc_list(RevXsOnes, Map),
> + Bag = bag(Map).
That looks fine otherwise.
Julien.
More information about the reviews
mailing list