From 2e0ffc9fdda78852b091c9f078cc3ecaef5de5b6 Mon Sep 17 00:00:00 2001 From: David Llewellyn-Jones Date: Fri, 18 Oct 2024 19:09:39 +0100 Subject: [PATCH] Update the "more verbose" tutorial example There are two changes here, one of which may be a bit contentious. I really enjoyed working through this, but I was thrown by the final comments concerning 167. What's so different about 167 compared to 168? I found the program generator was quite happy to come up with a program for both. I thought it might be interesting therefore if the 167 example was something that the program generator was not able to solve. This, I think, makes it more interesting and also emphasises that the software is doing what the user would expect (i.e. not coming up with a solution that doesn't exist). This change therefore constrains the values to being even, so that the 167 result can't be obtained. The second, smaller change, is to use 'Number# instead of 'Real'. I was uncomfortable with the latter simply because, even in the original version, they are in fact all integers. I understand if you feel these changes are making things overly complicated. I just thought they'd make an interesting example. --- .../tutorials/getting_started_with_herb.jl | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/src/tutorials/getting_started_with_herb.jl b/docs/src/tutorials/getting_started_with_herb.jl index 8e841ae..aec38c2 100644 --- a/docs/src/tutorials/getting_started_with_herb.jl +++ b/docs/src/tutorials/getting_started_with_herb.jl @@ -18,20 +18,20 @@ Specifically, we will look at example-based search, where the goal is to find a # ╔═╡ 841f097d-a389-4dd2-9ad3-1a2292568634 md""" ### Setup -First, we start with the setup. We need to access to all the function in the Herb.jl framework. +First, we start with the setup. We need access to all the function in the Herb.jl framework. """ # ╔═╡ db7fe47b-ab3e-4705-b6ac-2733b9e81434 md""" ### Defining the program space -Next, we start by creating a grammar. We define a context-free grammar as a [`HerbGrammar.ContextSpecificGrammar`](@ref) without any constraints. A context-free grammar is just a simple set of production rules for defining combinations of terminal symbols (in our case real numbers). +Next, we start by creating a grammar. We define a context-free grammar as a [`HerbGrammar.ContextSpecificGrammar`](@ref) without any constraints. A context-free grammar is just a simple set of production rules for defining combinations of terminal symbols (in our case integers). -Contrary, we could define a context-sensitive grammar, when the production rules only hold in a certain context. However, for more information on this, please see our tutorial on [defining grammars](defining_grammars.md). +Alternatively we could define a context-sensitive grammar, when the production rules only hold in a certain context. For more information on this, please see our tutorial on [defining grammars](defining_grammars.md). For now, we specify a simple grammar (using the `@csgrammar` macro) for dealing with integers and explain all the rules individually: -1. First, we specify our interval `[0:9]` on real numbers and also constrain them to be integer. +1. First, we specify our number values and constrain them to being positive even integers. 2. Then, we can also use the variable `x` to hold an integer. 3. The third rule determines we can add two integers. 4. The fourth rule determines we can subtract an integer from another. @@ -42,11 +42,11 @@ If you run this cell, you can see all the rules rolled out. # ╔═╡ 763b378b-66f9-481e-a3da-ca37825eb255 g = HerbGrammar.@csgrammar begin - Real = |(0:9) - Real = x - Real = Real + Real - Real = Real - Real - Real = Real * Real + Number = 0|2|4|6|8 + Number = x + Number = Number + Number + Number = Number - Number + Number = Number * Number end # ╔═╡ 6d01dfe8-9048-4696-916c-b33fbc97268b @@ -69,7 +69,7 @@ In the cell below we automatically generate some examples for `x` assigning valu # ╔═╡ 8bf48b7a-0ff5-4015-81d3-ed2eeeceff1c # Create input-output examples -examples = [HerbSpecification.IOExample(Dict(:x => x), 3x + 5) for x ∈ 1:5] +examples = [HerbSpecification.IOExample(Dict(:x => x), 4x + 6) for x ∈ 1:5] # ╔═╡ 2baa7f33-c86d-40e2-9253-720ec19e4c43 md""" @@ -99,11 +99,11 @@ This can be done using a breadth-first search over the program/search space. This search is very basic; it makes use of an enumeration technique, where we enumerate programs one-by-one until we find a program that matches our examples. The search procedure has a built-in default evaluator to verify the candidate programs with the given input. The search procedure also has a built-in search procedure using breadth-first search. -So, we only need to give our grammar and the problem to our search procedure, along with a starting `Symbol`, in our case a `Real`. +So, we only need to give our grammar and the problem to our search procedure, along with a starting `Symbol`, in our case a `Number`. """ # ╔═╡ d553f37b-bc8a-4426-a98b-fb195ed994d9 -iterator_1 = BFSIterator(g, :Real) +iterator_1 = BFSIterator(g, :Number) # ╔═╡ e1910236-9783-4989-a014-c3f7ccdf33d3 synth(problem_1, iterator_1) @@ -119,7 +119,7 @@ md""" In the previous case, we used the built-ins of the search procedure. However, we can also give a custom enumerator to the search procedure and define a few more values. -We first define a new problem to test with, we are looking for the programs that can compute the value `167`. We immediately pass the examples to the problem and then set up the new search. +We first define a new problem to test with, we are looking for the programs that can compute the value `168`. We immediately pass the examples to the problem and then set up the new search. Search is done by passing the grammar, the problem and the starting point like before. We now also specify the enumeration function to be used, and now we use depth-first search. Then, we give the maximum depth of the programs we want to search for `(3)`, the maximum number of nodes in the Abstract Syntax Tree that exists during search `(10)`, and the maximum time in seconds allowed for the search. """ @@ -127,9 +127,11 @@ Search is done by passing the grammar, the problem and the starting point like b # ╔═╡ cdab3f55-37e4-4aee-bae1-14d3475cbdcd begin problem_2 = HerbSpecification.Problem("example2", [HerbSpecification.IOExample(Dict(:x => x), 168) for x ∈ 1:5]) - iterator_2 = HerbSearch.BFSIterator(g, :Real, max_depth=4, max_size=30) - expr_2 = HerbSearch.synth(problem_2, iterator_2) + iterator_2 = HerbSearch.BFSIterator(g, :Number, max_depth=4, max_size=30) + expr_2, flag = HerbSearch.synth(problem_2, iterator_2) print(expr_2) + program_2 = rulenode2expr(expr_2, g) + println(program_2) end # ╔═╡ 5ad86beb-eb25-4bae-b0c2-a33d1a38581a @@ -142,8 +144,10 @@ In any case, this concludes our first introduction to the `Herb.jl` program synt # ╔═╡ c06d09a5-138a-4821-8a60-074fa7ec026d begin problem_3 = HerbSpecification.Problem("example3", [HerbSpecification.IOExample(Dict(:x => x), 167) for x ∈ 1:5]) - expr_3 = HerbSearch.synth(problem_3, iterator_2) + expr_3, flag = HerbSearch.synth(problem_3, iterator_2) print(expr_3) + program_3 = rulenode2expr(expr_3, g) + println(program_3) end # ╔═╡ 00000000-0000-0000-0000-000000000001