mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
library/psqueue.m:
Fix a bug: the adjust predicate was documented to fail if asked to adjust
the priority of a nonexistent key, but it succeeded anyway.
Fix a bug: the function that computed the size of a psqueue did not count
the priority/key pair in the winner structure.
Make the at_most predicate significantly more efficient, by eliminating
an expensive conversion to the min view. Most of the contents of the min
view was not needed. In Haskell (the language used in the paper that
this module is derived from), computing stuff that won't be looked at
is cheap due to lazyness; in Mercury, it can be expensive.
Make the at_most predicate significantly more efficient in another respect
as well, by using cords to avoid re-re-re-appending the same elements.
Make most other predicates more efficient by eliminating the redundant
checking for empty queues. For example, when you convert a nonempty queue
to the tournament view, you shouldn't need to check whether the result
is a tournament with no players; it will not be. This change required
two main changes in data structures. The first is to separate out
the concepts of psqueues that may be empty from those which may not.
The second is updating the tournament view to eliminate the possibility
of no players, and handling empty psqueues *without* converting them
to the tournament view.
Document the meanings of the module's data structures, both original
and updated, including their invariants (at least, the invariants
I can see).
Delete the type for min views, since after the performance fix to at_most,
it is no longer needed.
Delete the type for tree views, since it is isomorphic to the actual
data structure, and conversions to it just waste time.
Delete the t_ prefix from the names of types.
Change the documentation of predicates to use full sentences, not just
sentence fragments.
Do not include the predicates intended only for unit tests in the
publicly documented part of the interface.
Use the P, K order of type variables CONSISTENTLY. Change the order
of fields representing priority/key pairs in structures likewise.
Use consistent naming schemes for variables: PSQx for psqueues, LTreex
for ltrees, etc. Use xPrime instead of x0 for variables bound in the
conditions of if-then-elses. Use Maybe as a prefix on the names of
variables of maybe types.
Avoid the use of generic variable names such as "Res"; use names that
reflect the value being returned instead.
Avoid the use of numeric suffixes on variables when these do NOT denote
progression over time; use A and B, or L and R, suffixes instead.
Give some function symbols and predicates more meaningful names.
Internal operations do not need to be available as both functions
and predicates; pick whichever seems more appropriate, and remove
the other. Remove some other unused functions, such as construct_leaf.
Factor out some common code, e.g. for updating minimums and maximums.
Remove redundant "is det" declarations from functions.
Fix the type specializations. Specializing a predicate is useless
unless its caller either always calls it with values of the specialized
type, or is itself specialized the same way. This module needs the latter,
so add type specializations to all predicates between the exported
predicates and the primitives that can directly benefit from the
specializations.
tests/hard_coded/psqueue_test.{m,exp}:
Make this test case significantly harder. The old version did not
pick up the two bugs referred to above, but the new version does.
323 lines
9.4 KiB
Plaintext
323 lines
9.4 KiB
Plaintext
empty test: ok
|
|
nonempty test: ok
|
|
empty test after remove: ok
|
|
|
|
extended paper example test:
|
|
size before insert is 0
|
|
inserting prio 1, key Lennart2, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Lennart2",
|
|
loser_leaf
|
|
)
|
|
size after insert is 1
|
|
|
|
size before insert is 1
|
|
inserting prio 8, key Warren, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Lennart2"
|
|
loser_leaf
|
|
)
|
|
)
|
|
size after insert is 2
|
|
|
|
size before insert is 2
|
|
inserting prio 2, key Erik, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 2, prio 8, key "Warren"
|
|
loser_node(size 1, prio 2, key "Erik"
|
|
loser_leaf
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_leaf
|
|
)
|
|
)
|
|
size after insert is 3
|
|
|
|
size before insert is 3
|
|
inserting prio 7, key Richard, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 3, prio 7, key "Richard"
|
|
loser_node(size 1, prio 2, key "Erik"
|
|
loser_leaf
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Richard"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
size after insert is 4
|
|
|
|
size before insert is 4
|
|
inserting prio 5, key Simon, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 4, prio 5, key "Simon"
|
|
loser_node(size 1, prio 2, key "Erik"
|
|
loser_leaf
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 2, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 5
|
|
|
|
size before insert is 5
|
|
inserting prio 4, key Charles, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 5, prio 5, key "Simon"
|
|
loser_node(size 2, prio 2, key "Erik"
|
|
loser_node(size 1, prio 4, key "Charles"
|
|
loser_leaf
|
|
split key "Charles"
|
|
loser_leaf
|
|
)
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 2, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 6
|
|
|
|
size before insert is 6
|
|
inserting prio 6, key Mary, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 6, prio 5, key "Simon"
|
|
loser_node(size 2, prio 2, key "Erik"
|
|
loser_node(size 1, prio 4, key "Charles"
|
|
loser_leaf
|
|
split key "Charles"
|
|
loser_leaf
|
|
)
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 3, prio 6, key "Mary"
|
|
loser_node(size 1, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Mary"
|
|
loser_leaf
|
|
)
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 7
|
|
|
|
size before insert is 7
|
|
inserting prio 3, key Phil, giving
|
|
winner(prio 1, key "Lennart2", maxkey "Warren",
|
|
loser_node(size 7, prio 3, key "Phil"
|
|
loser_node(size 2, prio 2, key "Erik"
|
|
loser_node(size 1, prio 4, key "Charles"
|
|
loser_leaf
|
|
split key "Charles"
|
|
loser_leaf
|
|
)
|
|
split key "Erik"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 4, prio 5, key "Simon"
|
|
loser_node(size 2, prio 6, key "Mary"
|
|
loser_leaf
|
|
split key "Mary"
|
|
loser_node(size 1, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Phil"
|
|
loser_leaf
|
|
)
|
|
)
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 8
|
|
|
|
size before insert is 8
|
|
inserting prio 1, key Lennart, giving
|
|
winner(prio 1, key "Lennart", maxkey "Warren",
|
|
loser_node(size 8, prio 3, key "Phil"
|
|
loser_node(size 3, prio 2, key "Erik"
|
|
loser_node(size 1, prio 4, key "Charles"
|
|
loser_leaf
|
|
split key "Charles"
|
|
loser_leaf
|
|
)
|
|
split key "Erik"
|
|
loser_node(size 1, prio 1, key "Lennart2"
|
|
loser_leaf
|
|
split key "Lennart"
|
|
loser_leaf
|
|
)
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 4, prio 5, key "Simon"
|
|
loser_node(size 2, prio 6, key "Mary"
|
|
loser_leaf
|
|
split key "Mary"
|
|
loser_node(size 1, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Phil"
|
|
loser_leaf
|
|
)
|
|
)
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 9
|
|
|
|
size before insert is 9
|
|
inserting prio 2, key Erik2, giving
|
|
winner(prio 1, key "Lennart", maxkey "Warren",
|
|
loser_node(size 9, prio 3, key "Phil"
|
|
loser_node(size 4, prio 2, key "Erik"
|
|
loser_node(size 1, prio 4, key "Charles"
|
|
loser_leaf
|
|
split key "Charles"
|
|
loser_leaf
|
|
)
|
|
split key "Erik"
|
|
loser_node(size 2, prio 1, key "Lennart2"
|
|
loser_node(size 1, prio 2, key "Erik2"
|
|
loser_leaf
|
|
split key "Erik2"
|
|
loser_leaf
|
|
)
|
|
split key "Lennart"
|
|
loser_leaf
|
|
)
|
|
)
|
|
split key "Lennart2"
|
|
loser_node(size 4, prio 5, key "Simon"
|
|
loser_node(size 2, prio 6, key "Mary"
|
|
loser_leaf
|
|
split key "Mary"
|
|
loser_node(size 1, prio 7, key "Richard"
|
|
loser_leaf
|
|
split key "Phil"
|
|
loser_leaf
|
|
)
|
|
)
|
|
split key "Richard"
|
|
loser_node(size 1, prio 8, key "Warren"
|
|
loser_leaf
|
|
split key "Simon"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
size after insert is 10
|
|
|
|
|
|
at_most tests
|
|
at_most 0: []
|
|
at_most 1: [1 - "Lennart", 1 - "Lennart2"]
|
|
at_most 2: [2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2"]
|
|
at_most 3: [2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 3 - "Phil"]
|
|
at_most 4: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 3 - "Phil"]
|
|
at_most 5: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 3 - "Phil", 5 - "Simon"]
|
|
at_most 6: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 6 - "Mary", 3 - "Phil", 5 - "Simon"]
|
|
at_most 7: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 6 - "Mary", 3 - "Phil", 7 - "Richard", 5 - "Simon"]
|
|
at_most 8: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 6 - "Mary", 3 - "Phil", 7 - "Richard", 5 - "Simon", 8 - "Warren"]
|
|
at_most 9: [4 - "Charles", 2 - "Erik", 2 - "Erik2", 1 - "Lennart", 1 - "Lennart2", 6 - "Mary", 3 - "Phil", 7 - "Richard", 5 - "Simon", 8 - "Warren"]
|
|
|
|
to_ord_assoc_list test:
|
|
[1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
|
|
delete tests
|
|
delete key Lennart2: prio 1, left [1 - "Lennart", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Warren: prio 8, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard"]
|
|
delete key Erik: prio 2, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Richard: prio 7, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 8 - "Warren"]
|
|
delete key Simon: prio 5, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Charles: prio 4, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Mary: prio 6, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 7 - "Richard", 8 - "Warren"]
|
|
delete key Phil: prio 3, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Lennart: prio 1, left [1 - "Lennart2", 2 - "Erik", 2 - "Erik2", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key Erik2: prio 2, left [1 - "Lennart", 1 - "Lennart2", 2 - "Erik", 3 - "Phil", 4 - "Charles", 5 - "Simon", 6 - "Mary", 7 - "Richard", 8 - "Warren"]
|
|
delete key NotThere: failed
|
|
|
|
from_assoc_list test:
|
|
via from_assoc_list and via inserts assoc lists agree:
|
|
[0 - "M", 1 - "L", 2 - "B", 3 - "N", 4 - "H"]
|
|
via from_assoc_list and via inserts psqueues agree:
|
|
winner(prio 0, key "M", maxkey "N",
|
|
loser_node(size 4, prio 2, key "B"
|
|
loser_node(size 1, prio 4, key "H"
|
|
loser_leaf
|
|
split key "B"
|
|
loser_leaf
|
|
)
|
|
split key "H"
|
|
loser_node(size 2, prio 1, key "L"
|
|
loser_leaf
|
|
split key "L"
|
|
loser_node(size 1, prio 3, key "N"
|
|
loser_leaf
|
|
split key "M"
|
|
loser_leaf
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
adjust tests on
|
|
[0 - "M", 1 - "L", 2 - "B", 3 - "N", 4 - "H"]
|
|
adjusting priority of H to 0 succeeded
|
|
[0 - "H", 0 - "M", 1 - "L", 2 - "B", 3 - "N"]
|
|
adjusting priority of L to 8 succeeded
|
|
[0 - "M", 2 - "B", 3 - "N", 4 - "H", 8 - "L"]
|
|
adjusting priority of B to 2 succeeded
|
|
[0 - "M", 1 - "L", 2 - "B", 3 - "N", 4 - "H"]
|
|
adjusting priority of M to 2 succeeded
|
|
[1 - "L", 2 - "B", 2 - "M", 3 - "N", 4 - "H"]
|
|
adjusting priority of N to 1 succeeded
|
|
[0 - "M", 1 - "L", 1 - "N", 2 - "B", 4 - "H"]
|
|
adjusting priority of X to 7 failed
|