Add best-first search with the cost orders and algebras it searches by - #112
Merged
Conversation
The search rules of the package are uninformed. depth_first and breadth_first read the order of their stream off the shape of the derivation tree, and nothing lets a caller order a search by a cost on the search nodes instead. Random search is already informed, but its frontier is a heapq over reals written out inside sampling.py, with no general form behind it and nothing that states what a cost function has to be for the search to stay sound and complete. A new module cosy.search.costs, with sixteen of its names re-exported from the package. It carries three layers, separable on purpose. The cost order a cost function maps into, partial by default and strengthened to a positively ordered commutative monoid wherever costs are summed. The best-first frontier over it, whose pop returns a node that no node of the frontier lies strictly below, as a linear scan in general and as a binary heap where the order is total. And the additive cost algebras, which read a search node as the partial inhabitant it denotes and split its cost into the cost so far and the estimate of what its holes still add. best_first is the search rule the three build up to, run under uniform_cost, greedy or a_star. It takes no clause order, because the pop selects by cost alone, and it fixes the computation rule to the one the two uninformed rules use. The order stays partial throughout, and that is where the subtle mistakes live. Best-first search pops a minimal node and not a least one, several incomparable minima may exist at once, and the cost-bounded sets that carry completeness collect the nodes whose cost is not strictly above the bound, which over a partial order is weaker than "at most the bound". Soundness holds on every space. Completeness needs every cost-bounded set to be finite, and cost order needs a cost function that never falls along a branch. Both are properties of the cost function rather than of the search, so uniform_cost supplies them and greedy does not. The two cost domains reject a value that leaves their carrier, at the argument and at the result of an addition. A monoid is closed under its operation, so an overflowing sum is reported where it arises rather than by the next operation to receive it. The module docstring of sampling.py now names the two frontier classes it described in the abstract. Its own heap is the total-order fast path written out in place.
Contributor
There was a problem hiding this comment.
Benchmark CoSy
Details
| Benchmark suite | Current: 9cc2bfd | Previous: be71b5d | Ratio |
|---|---|---|---|
benchmarks/test_benchmark_maximal_elements.py::test_benchmark_maximal_elements |
10.549892760483873 iter/sec (stddev: 0.00016046166696687814) |
9.608281351562356 iter/sec (stddev: 0.010017085420616013) |
0.91 |
benchmarks/test_benchmark_maze.py::test_benchmark_maze |
4.469599573329848 iter/sec (stddev: 0.010452029992877749) |
3.9235166334572096 iter/sec (stddev: 0.018797551923491352) |
0.88 |
benchmarks/test_benchmark_maze_contains.py::test_benchmark_maze_contains |
4.248682767922877 iter/sec (stddev: 0.015905390729716647) |
3.5391214334611916 iter/sec (stddev: 0.025877608823890046) |
0.83 |
benchmarks/test_benchmark_maze_loopfree.py::test_benchmark_maze_loopfree |
4.506064942615535 iter/sec (stddev: 0.011333250950426203) |
3.8477221717914887 iter/sec (stddev: 0.02072136799063595) |
0.85 |
This comment was automatically generated by workflow using github-action-benchmark.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #112 +/- ##
===========================================
+ Coverage 91.70% 92.53% +0.83%
===========================================
Files 76 78 +2
Lines 8398 9367 +969
Branches 868 959 +91
===========================================
+ Hits 7701 8668 +967
Misses 623 623
- Partials 74 76 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem:
The search rules of the package are uninformed.
depth_firstandbreadth_firstread the order oftheir stream off the shape of the derivation tree, and nothing lets a caller order a search by a
cost on the search nodes instead. Random search is already an informed search, but its frontier is
a heap over reals written out inside
sampling.py, with no general form behind it and nothing thatstates what a cost function must satisfy for the search to remain sound and complete.
Changes:
cosy.search.costs, with sixteen of its names re-exported from the package. Itcarries three layers, separable on purpose.
incomparable costs, and strengthened to a positively ordered commutative monoid wherever costs
are summed.
Realsfor an order without addition,NonNegativeRealsandComponentwiseTuplesfor the domains that sum.
below.
LinearScanFrontierin general,HeapFrontierwhere the order is total, andbest_first_frontierpicks between them so that no caller has to remember which domains admit aheap.
split its cost into the cost so far and the estimate of what its holes still add.
best_firstis the search rule the three build up to, run underuniform_cost,greedyora_star. It takes no clause order, because the pop selects by cost alone, and it fixes thecomputation rule to the one the two uninformed rules use.
order needs a cost function that never falls along a branch. Both are properties of the cost
function rather than of the search, so
uniform_costsupplies them andgreedydoes not.assert_uniform_cost_completedecides the first of the two for a given symbol family.an addition. A monoid is closed under its operation, so an overflowing sum is reported where it
arises rather than by the next operation to receive it.
sampling.pynow names the two frontier classes it described in theabstract. Its own heap is the total-order fast path written out in place.