From dfb25dff32457185c5d2d358a88ba218fafec7a3 Mon Sep 17 00:00:00 2001 From: Pamela Wochner Date: Mon, 21 Oct 2024 14:22:54 +0200 Subject: [PATCH] Improve docstrings. --- src/stochastic_iterator.jl | 122 +++++++++++++++++++++++-------------- src/top_down_iterator.jl | 1 - 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/stochastic_iterator.jl b/src/stochastic_iterator.jl index cff69641..0fe464cc 100644 --- a/src/stochastic_iterator.jl +++ b/src/stochastic_iterator.jl @@ -3,52 +3,64 @@ using Random """ abstract type StochasticSearchIterator <: ProgramIterator - A unified abstract type for the algorithms Metropolis Hastings, Very Large Scale Neighbourhood and Simulated Annealing. - Each algorithm implements `neighbourhood`, `propose`, `accept` and `temperature` functions. Below the signatures of each function is shown. - - ## Signatures - --- - Returns a node location from the program that is the neighbourhood. It can also return other information using `dict` - - neighbourhood(iter::T, current_program::RuleNode) where T <: StochasticSearchIterator -> (loc::NodeLocation, dict::Dict) - --- - Proposes a list of programs using the location provided by `neighbourhood` and the `dict`. - - propose(iter::T, current_program::RuleNode, neighbourhood_node_loc::NodeLoc, dmap::AbstractVector{Int}, dict::Union{Nothing,Dict{String,Any}}) where T <: StochasticSearchIterator -> Iter[RuleNode] - ---- - - Based on the current program and possible cost and temperature it accepts the program or not. Usually we would always want to accept - better programs but we might get stuck if we do so. That is why some implementations of the `accept` function accept with a probability - costs that are worse. - `cost` means how different are the outcomes of the program compared to the correct outcomes. - The lower the `cost` the better the program performs on the examples. The `cost` is provided by the `cost_function` - - accept(::T, current_cost::Real, next_cost::Real, temperature::Real) where T <: StochasticSearchIterator -> Bool - ---- - Returns the new temperature based on the previous temperature. Higher the `temperature` means that the algorithm will explore more. - - temperature(::T, current_temperature::Real) where T <: StochasticSearchIterator -> Real - --- - Returns the cost of the current program. It receives a list of tuples `(expected, found)` and gives back a cost. - - cost_function(outcomes::Tuple{<:Number,<:Number}[]) -> Real - +A unified abstract type for the stochastic search algorithms Metropolis Hastings, Very Large Scale Neighbourhood and Simulated Annealing. +Iterators are customisable by overloading the followign functions: + - `neighbourhood` + - `propose` + - `temperature` + - `accept`. ---- # Fields - `examples::Vector{IOExample}` example used to check the program - - `cost_function::Function` + - `cost_function::Function`. Returns the cost of the current program. It receives a list of tuples for (expected, found) and gives back a cost. - `initial_temperature::Real` = 1 - `evaluation_function`::Function that evaluates the julia expressions An iterator over all possible expressions of a grammar up to max_depth with start symbol sym. Also inherits all stop criteria like `max_depth` from `ProgramIterator`. """ abstract type StochasticSearchIterator <: ProgramIterator end +""" + neighbourhood(iter::StochasticSearchIterator, current_program::RuleNode) + +Returns a node location from the neighbourhood of the current program. +""" +neighbourhood(iter::StochasticSearchIterator, current_program::RuleNode) = constructNeighbourhood(current_program, get_grammar(iter.solver)) + + +""" + propose(iter::StochasticSearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) + +Proposes a list of programs to fill in the location provided by `path` and the `dict`. +""" +propose(iter::StochasticSearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = random_fill_propose(iter.solver, path, dict) + +""" + temperature(::StochasticSearchIterator, current_temperature::Real) + +Returns the new temperature based on the current temperature. A higher temperature means that the algorithm will explore more. +""" +temperature(::StochasticSearchIterator, current_temperature::Real) = const_temperature(current_temperature) + +""" + accept(::StochasticSearchIterator, current_cost::Real, next_cost::Real, temperature::Real) + +Based on the current program and possible cost and temperature a program is accepted or not. Usually we would always want to accept +better programs but we might get stuck if we do so. That is why some implementations of the `accept` function accept with a probability +costs that are worse. +`cost` means how different are the outcomes of the program compared to the correct outcomes. +The lower the `cost` the better the program performs on the examples. The `cost` is provided by the `cost_function` +""" +accept(::StochasticSearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = probabilistic_accept(current_cost, next_cost, temperature) + struct IteratorState current_program::RuleNode current_temperature::Real dmap::AbstractVector{Int} # depth map of each rule end + + + Base.IteratorSize(::StochasticSearchIterator) = Base.SizeUnknown() Base.eltype(::StochasticSearchIterator) = RuleNode @@ -163,10 +175,17 @@ end calculate_cost(iter::T, program::Union{RuleNode, StateHole}) where T <: StochasticSearchIterator Wrapper around [`_calculate_cost`](@ref). +TODO: move somewhere else in code? Refactor?. """ calculate_cost(iter::T, program::Union{RuleNode, StateHole}) where T <: StochasticSearchIterator = _calculate_cost(program, iter.cost_function, iter.spec, get_grammar(iter.solver), iter.evaluation_function) -neighbourhood(iter::T, current_program::RuleNode) where T <: StochasticSearchIterator = constructNeighbourhood(current_program, get_grammar(iter.solver)) + +""" + AbstractMHIterator <: StochasticSearchIterator + +This is the supertype for all MH search iterators. It inherits all stop-criteria and from [`StochasticSearchIterator`](@ref). +""" +abstract type AbstractMHSearchIterator <: StochasticSearchIterator end Base.@doc """ MHSearchIterator(examples::AbstractArray{<:IOExample}, cost_function::Function, evaluation_function::Function=HerbInterpret.execute_on_input) @@ -184,20 +203,27 @@ The temperature value of the algorithm remains constant over time. cost_function::Function, initial_temperature::Real = 1, evaluation_function::Function = execute_on_input, -) <: StochasticSearchIterator +) <: AbstractMHSearchIterator -propose(iter::MHSearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = random_fill_propose(iter.solver, path, dict) +""" + AbstractVLSNSearchIterator <: StochasticSearchIterator -temperature(::MHSearchIterator, current_temperature::Real) = const_temperature(current_temperature) +This is the supertype for all VLSN search iterators. +TODO: more +""" +abstract type AbstractVLSNSearchIterator <: StochasticSearchIterator end -accept(::MHSearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = probabilistic_accept(current_cost, next_cost, temperature) +# TODO: add docstrings +propose(iter::AbstractVLSNSearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = enumerate_neighbours_propose(iter.vlsn_neighbourhood_depth)(iter.solver, path, dict) +temperature(::AbstractVLSNSearchIterator, current_temperature::Real) = const_temperature(current_temperature) +accept(::AbstractVLSNSearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = best_accept(current_cost, next_cost, temperature) Base.@doc """ VLSNSearchIterator(spec, cost_function, enumeration_depth = 2, evaluation_function::Function=HerbInterpret.execute_on_input) = StochasticSearchIterator( Returns an iterator that runs according to the Very Large Scale Neighbourhood Search algorithm. - `spec` : array of examples -- `cost_function` : cost function to evaluate the programs proposed +- `cost_function` : cost function to evaluate the proposed programs - `vlsn_neighbourhood_depth` : the enumeration depth to search for a best program at a time - `evaluation_function` : evaluation function that evaluates the program generated and produces an output The propose function consists of all possible programs of the given `enumeration_depth`. The accept function accepts the program @@ -210,14 +236,22 @@ The temperature value of the algorithm remains constant over time. vlsn_neighbourhood_depth::Int = 2, initial_temperature::Real = 1, evaluation_function::Function = execute_on_input -) <: StochasticSearchIterator +) <: AbstractVLSNSearchIterator -propose(iter::VLSNSearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = enumerate_neighbours_propose(iter.vlsn_neighbourhood_depth)(iter.solver, path, dict) +""" + AbstractSASearchIterator <: StochasticSearchIterator + +This is the supertype for all SA search iterators. +TODO: more +""" +abstract type AbstractSASearchIterator <: StochasticSearchIterator end -temperature(::VLSNSearchIterator, current_temperature::Real) = const_temperature(current_temperature) +# TODO: add docstrings +propose(iter::AbstractSASearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = random_fill_propose(iter.solver, path, dict) -accept(::VLSNSearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = best_accept(current_cost, next_cost, temperature) +temperature(iter::AbstractSASearchIterator, current_temperature::Real) = decreasing_temperature(iter.temperature_decreasing_factor)(current_temperature) +accept(::AbstractSASearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = probabilistic_accept_with_temperature(current_cost, next_cost, temperature) Base.@doc """ SASearchIterator(spec, cost_function, initial_temperature=1, temperature_decreasing_factor = 0.99, evaluation_function::Function=HerbInterpret.execute_on_input) @@ -237,12 +271,8 @@ but takes into account the tempeerature too. initial_temperature::Real = 1, temperature_decreasing_factor::Real = 0.99, evaluation_function::Function = execute_on_input -) <: StochasticSearchIterator - -propose(iter::SASearchIterator, path::Vector{Int}, dict::Union{Nothing,Dict{String,Any}}) = random_fill_propose(iter.solver, path, dict) +) <: AbstractSASearchIterator -temperature(iter::SASearchIterator, current_temperature::Real) = decreasing_temperature(iter.temperature_decreasing_factor)(current_temperature) -accept(::SASearchIterator, current_cost::Real, next_cost::Real, temperature::Real) = probabilistic_accept_with_temperature(current_cost, next_cost, temperature) diff --git a/src/top_down_iterator.jl b/src/top_down_iterator.jl index 92dae146..9194aa10 100644 --- a/src/top_down_iterator.jl +++ b/src/top_down_iterator.jl @@ -125,7 +125,6 @@ function priority_function( end return parent_value - 1; end -# TODO: concrete type Base.@doc """ @programiterator DFSIterator() <: AbstractDFSIterator