Skip to content

Commit

Permalink
Merge pull request #24 from Herb-AI/dev
Browse files Browse the repository at this point in the history
Update `Grammar` -> `AbstractGrammar`
  • Loading branch information
THinnerichs authored Feb 29, 2024
2 parents bcbfd64 + 37396a8 commit 015059d
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 49 deletions.
8 changes: 4 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
name = "HerbConstraints"
uuid = "1fa96474-3206-4513-b4fa-23913f296dfc"
authors = ["Jaap de Jong <[email protected]>"]
version = "0.1.0"
version = "0.1.1"

[deps]
HerbGrammar = "4ef9e186-2fe5-4b24-8de7-9f7291f24af7"
HerbCore = "2b23ba43-8213-43cb-b5ea-38c12b45bd45"

[compat]
julia = "1.8"
HerbCore = "0.1.0"
HerbGrammar = "0.1.0"
HerbCore = "^0.2.0"
HerbGrammar = "^0.2.0"
julia = "^1.8"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# HerbConstraints.jl


[![Build Status](https://github.com/Herb-AI/HerbConstraints.jl/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/Herb-AI/HerbConstraints.jl/actions/workflows/CI.yml?query=branch%3Amaster)

This package contains the functionality to formulate, represent and use constraints within `Herb`.

Constraints are formulated as context-sensitive grammars. Further, they are divided into global and local constraints, that may be partially mapped to each other.

`HerbConstraints.jl` provides functionality to propagate constraints and match constraint patterns efficiently. Further, provides error handling through `matchfail` and `matchnode`.

[![Build Status](https://github.com/Herb-AI/HerbConstraints.jl/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/Herb-AI/HerbConstraints.jl/actions/workflows/CI.yml?query=branch%3Amaster)

4 changes: 2 additions & 2 deletions src/HerbConstraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Abstract type representing all propagator constraints.
Each propagator constraint has an implementation of a [`propagate`](@ref)-function that takes
- the [`PropagatorConstraint`](@ref)
- a [`Grammar`](@ref)
- a [`AbstractGrammar`](@ref)
- a [`GrammarContext`](@ref), which most importantly contains the tree and the location
in the tree where propagation should take place.
- The `domain` which the [`propagate`](@ref)-function prunes.
Expand All @@ -31,7 +31,7 @@ Each local constraint contains a `path` to a specific location in the tree.
Each local constraint has an implementation of a [`propagate`](@ref)-function that takes
- the [`LocalConstraint`](@ref)
- a [`Grammar`](@ref)
- a [`AbstractGrammar`](@ref)
- a [`GrammarContext`](@ref), which most importantly contains the tree and the location
in the tree where propagation should take place.
- The `domain` which the [`propagate`](@ref)-function prunes.
Expand Down
19 changes: 18 additions & 1 deletion src/localconstraints/local_condition.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
"""
LocalCondition <: LocalConstraint
Forbids any subtree that matches the pattern defined by `tree` and where the
[`RuleNode`](@ref) that is matched to the variable in the pattern violates the
predicate given by the `condition` function.
The `condition` function takes a `RuleNode` tree and should return a `Bool`.
This constraint is only enforced at the location defined by `path`.
Use a `Condition` constraint for enforcing this throughout the entire search space.
"""
mutable struct LocalCondition <: LocalConstraint
path::Vector{Int}
tree::AbstractMatchNode
condition::Function
end

"""
propagate(c::LocalCondition, ::AbstractGrammar, context::GrammarContext, domain::Vector{Int}, filled_hole::Union{HoleReference, Nothing})
Propagates the [`LocalCondition`](@ref) constraint.
"""
function propagate(
c::LocalCondition,
::Grammar,
::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand Down
2 changes: 1 addition & 1 deletion src/localconstraints/local_forbidden.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ the RuleNode at the given path match the pattern defined by the MatchNode.
"""
function propagate(
c::LocalForbidden,
::Grammar,
::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand Down
2 changes: 1 addition & 1 deletion src/localconstraints/local_one_of.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ It enforces that at least one of its given constraints hold.
"""
function propagate(
c::LocalOneOf,
g::Grammar,
g::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand Down
2 changes: 1 addition & 1 deletion src/localconstraints/local_ordered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ constraint.
"""
function propagate(
c::LocalOrdered,
::Grammar,
::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand Down
24 changes: 12 additions & 12 deletions src/matchnode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ contains_var(mn::MatchNode, var::Symbol) = any(contains_var(c, var) for c ∈ mn


"""
matchnode2expr(pattern::MatchNode, grammar::Grammar)
matchnode2expr(pattern::MatchNode, grammar::AbstractGrammar)
Converts a MatchNode tree into a Julia expression.
This is primarily useful for pretty-printing a pattern. Returns the corresponding expression.
"""
function matchnode2expr(pattern::MatchNode, grammar::Grammar)
function matchnode2expr(pattern::MatchNode, grammar::AbstractGrammar)
root = deepcopy(grammar.rules[pattern.rule_ind])
if !grammar.isterminal[pattern.rule_ind] # not terminal
root,_ = _matchnode2expr(root, pattern, grammar)
Expand All @@ -92,21 +92,21 @@ function matchnode2expr(pattern::MatchNode, grammar::Grammar)
end

"""
matchnode2expr(pattern::MatchVar, grammar::Grammar)
matchnode2expr(pattern::MatchVar, grammar::AbstractGrammar)
Converts a MatchVar into an expression by returning the variable directly.
This is primarily useful for pretty-printing a pattern.
"""
function matchnode2expr(pattern::MatchVar, ::Grammar)
function matchnode2expr(pattern::MatchVar, ::AbstractGrammar)
return pattern.var_name
end

"""
_matchnode2expr(expr::Expr, pattern::MatchNode, grammar::Grammar, j=0)
_matchnode2expr(expr::Expr, pattern::MatchNode, grammar::AbstractGrammar, j=0)
Internal function for [`matchnode2expr`](@ref), recursively iterating over a matched pattern and converting it to an expression. This is primarily useful for pretty-printing a pattern. Returns the corresponding expression and the current child index.
"""
function _matchnode2expr(expr::Expr, pattern::MatchNode, grammar::Grammar, j=0)
function _matchnode2expr(expr::Expr, pattern::MatchNode, grammar::AbstractGrammar, j=0)
for (k,arg) enumerate(expr.args)
if isa(arg, Expr)
expr.args[k],j = _matchnode2expr(arg, pattern, grammar, j)
Expand All @@ -127,11 +127,11 @@ end


"""
_matchnode2expr(expr::Expr, pattern::MatchVar, grammar::Grammar, j=0)
_matchnode2expr(expr::Expr, pattern::MatchVar, grammar::AbstractGrammar, j=0)
Internal function for [`matchnode2expr`](@ref), recursively iterating over a matched variable and converting it to an expression. This is primarily useful for pretty-printing a pattern. Returns the corresponding expression and the current child index.
"""
function _matchnode2expr(expr::Expr, pattern::MatchVar, grammar::Grammar, j=0)
function _matchnode2expr(expr::Expr, pattern::MatchVar, grammar::AbstractGrammar, j=0)
for (k,arg) enumerate(expr.args)
if isa(arg, Expr)
expr.args[k],j = _matchnode2expr(arg, pattern, grammar, j)
Expand All @@ -148,11 +148,11 @@ end


"""
_matchnode2expr(typ::Symbol, pattern::MatchNode, grammar::Grammar, j=0)
_matchnode2expr(typ::Symbol, pattern::MatchNode, grammar::AbstractGrammar, j=0)
Internal function for [`matchnode2expr`](@ref), returning the matched translated symbol. This is primarily useful for pretty-printing a pattern. Returns the corresponding expression, i.e. the variable name and the current child index.
"""
function _matchnode2expr(typ::Symbol, pattern::MatchNode, grammar::Grammar, j=0)
function _matchnode2expr(typ::Symbol, pattern::MatchNode, grammar::AbstractGrammar, j=0)
retval = typ
if haskey(grammar.bytype, typ)
child = pattern.children[1]
Expand All @@ -170,11 +170,11 @@ end


"""
_matchnode2expr(typ::Symbol, pattern::MatchVar, grammar::Grammar, j=0)
_matchnode2expr(typ::Symbol, pattern::MatchVar, grammar::AbstractGrammar, j=0)
Internal function for [`matchnode2expr`](@ref). This is primarily useful for pretty-printing a pattern. Returns the corresponding expression, i.e. the variable name and the current child index.
"""
function _matchnode2expr(typ::Symbol, pattern::MatchVar, grammar::Grammar, j=0)
function _matchnode2expr(typ::Symbol, pattern::MatchVar, grammar::AbstractGrammar, j=0)
return pattern.var_name, j
end

Expand Down
6 changes: 3 additions & 3 deletions src/propagatorconstraints/comesafter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ Creates a [`ComesAfter`](@ref) constraint with only a single `predecessor`.
ComesAfter(rule::Int, predecessor::Int) = ComesAfter(rule, [predecessor])

"""
propagate(c::ComesAfter, ::Grammar, context::GrammarContext, domain::Vector{Int})::Tuple{Vector{Int}, Vector{LocalConstraint}}
propagate(c::ComesAfter, ::AbstractGrammar, context::GrammarContext, domain::Vector{Int})::Tuple{Vector{Int}, Vector{LocalConstraint}}
Propagates the [`ComesAfter`](@ref) [`PropagatorConstraint`](@ref).
Rules in the domain that would violate the [`ComesAfter`](@ref) constraint are removed.
"""

function propagate(
c::ComesAfter,
::Grammar,
::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand All @@ -69,7 +69,7 @@ end
"""
Checks if the given tree abides the constraint.
"""
function check_tree(c::ComesAfter, g::Grammar, tree::AbstractRuleNode)::Bool
function check_tree(c::ComesAfter, g::AbstractGrammar, tree::AbstractRuleNode)::Bool
@warn "ComesAfter.check_tree not implemented!"

return true
Expand Down
34 changes: 31 additions & 3 deletions src/propagatorconstraints/condition.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
"""
Condition <: PropagatorConstraint
This [`PropagatorConstraint`](@ref) forbids any subtree that matches the pattern defined by `tree`
and where the [`RuleNode`](@ref) that is matched to the variable in the pattern violates the predicate given by
the `condition` function.
The `condition` function takes a `RuleNode` tree and should return a `Bool`.
!!! warning
The [`Condition`](@ref) constraint makes use of [`LocalConstraint`](@ref)s to make sure that constraints
are also enforced in the future when the context of a [`Hole`](@ref) changes.
Therefore, [`Condition`](@ref) can only be used in implementations that keep track of the
[`LocalConstraint`](@ref)s and propagate them at the right moments.
"""
struct Condition <: PropagatorConstraint
tree::AbstractMatchNode
condition::Function
end


"""
propagate(c::Condition, g::AbstractGrammar, context::GrammarContext, domain::Vector{Int})::Tuple{Vector{Int}, Vector{LocalConstraint}}
Propagates the [`Condition`](@ref) constraint.
Rules that violate the [`Condition`](@ref) constraint are removed from the domain.
!!! warning
The [`Condition`](@ref) constraint makes use of [`LocalConstraint`](@ref)s to make sure that constraints
are also enforced in the future when the context of a [`Hole`](@ref) changes.
Therefore, [`Condition`](@ref) can only be used in implementations that keep track of the
[`LocalConstraint`](@ref)s and propagate them at the right moments.
"""

function propagate(
c::Condition,
g::Grammar,
g::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand All @@ -27,7 +55,7 @@ end
"""
Checks if the given tree abides the constraint.
"""
function check_tree(c::Condition, g::Grammar, tree::RuleNode)::Bool
function check_tree(c::Condition, g::AbstractGrammar, tree::RuleNode)::Bool
vars = Dict{Symbol, AbstractRuleNode}()

# Return false if the node fits the pattern, but not the condition
Expand All @@ -38,6 +66,6 @@ function check_tree(c::Condition, g::Grammar, tree::RuleNode)::Bool
return all(check_tree(c, g, child) for child tree.children)
end

function check_tree(::Condition, ::Grammar, ::Hole)::Bool
function check_tree(::Condition, ::AbstractGrammar, ::Hole)::Bool
return false
end
12 changes: 6 additions & 6 deletions src/propagatorconstraints/forbidden.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
This [`PropagatorConstraint`] forbids any subtree that matches the pattern given by `tree` to be generated.
A pattern is a tree of [`AbstractMatchNode`](@ref)s.
Such a node can either be a [`MatchNode`](@ref), which contains a rule index corresponding to the
rule index in the [`Grammar`](@ref) and the appropriate number of children, similar to [`RuleNode`](@ref)s.
rule index in the [`AbstractGrammar`](@ref) and the appropriate number of children, similar to [`RuleNode`](@ref)s.
It can also contain a [`MatchVar`](@ref), which contains a single identifier symbol.
A [`MatchVar`](@ref) can match any subtree, but if there are multiple instances of the same
variable in the pattern, the matched subtrees must be identical.
Expand All @@ -31,7 +31,7 @@ end


"""
propagate(c::Forbidden, g::Grammar, context::GrammarContext, domain::Vector{Int})::Tuple{Vector{Int}, Vector{LocalConstraint}}
propagate(c::Forbidden, g::AbstractGrammar, context::GrammarContext, domain::Vector{Int})::Tuple{Vector{Int}, Vector{LocalConstraint}}
Propagates the [`Forbidden`](@ref) constraint.
It removes the rules from the `domain` that would complete the forbidden tree.
Expand All @@ -44,7 +44,7 @@ It removes the rules from the `domain` that would complete the forbidden tree.
"""
function propagate(
c::Forbidden,
g::Grammar,
g::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand All @@ -62,19 +62,19 @@ function propagate(
end

"""
check_tree(c::Forbidden, g::Grammar, tree::RuleNode)::Bool
check_tree(c::Forbidden, g::AbstractGrammar, tree::RuleNode)::Bool
Checks if the given [`AbstractRuleNode`](@ref) tree abides the [`Forbidden`](@ref) constraint.
"""
function check_tree(c::Forbidden, g::Grammar, tree::RuleNode)::Bool
function check_tree(c::Forbidden, g::AbstractGrammar, tree::RuleNode)::Bool
vars = Dict{Symbol, AbstractRuleNode}()
if _pattern_match(tree, c.tree, vars) nothing
return false
end
return all(check_tree(c, g, child) for child tree.children)
end

function check_tree(c::Forbidden, ::Grammar, tree::Hole)::Bool
function check_tree(c::Forbidden, ::AbstractGrammar, tree::Hole)::Bool
vars = Dict{Symbol, AbstractRuleNode}()
return _pattern_match(tree, c.tree, vars) !== nothing
end
4 changes: 2 additions & 2 deletions src/propagatorconstraints/forbidden_path.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ It removes the elements from the domain that would complete the forbidden sequen
"""
function propagate(
c::ForbiddenPath,
::Grammar,
::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand All @@ -48,7 +48,7 @@ end
"""
Checks if the given tree abides the constraint.
"""
function check_tree(c::ForbiddenPath, g::Grammar, tree::AbstractRuleNode)::Bool
function check_tree(c::ForbiddenPath, g::AbstractGrammar, tree::AbstractRuleNode)::Bool
@warn "ForbiddenPath.check_tree not implemented!"

return true
Expand Down
4 changes: 2 additions & 2 deletions src/propagatorconstraints/one_of.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It enforces that at least one of its given constraints hold.
"""
function propagate(
c::OneOf,
g::Grammar,
g::AbstractGrammar,
context::GrammarContext,
domain::Vector{Int},
filled_hole::Union{HoleReference, Nothing}
Expand All @@ -32,6 +32,6 @@ end
"""
Checks if the given tree abides the constraint.
"""
function check_tree(c::OneOf, g::Grammar, tree::AbstractRuleNode)::Bool
function check_tree(c::OneOf, g::AbstractGrammar, tree::AbstractRuleNode)::Bool
return any(check_tree(cons, g, tree) for cons in c.constraints)
end
Loading

2 comments on commit 015059d

@THinnerichs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

Release note:

  • Update abstract type Grammar -> AbstractGrammar
  • update to new versions of HerbCore and HerbGrammar

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/101992

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.1 -m "<description of version>" 015059da02ac7f3ebb649cf87bb0f20cfb923093
git push origin v0.1.1

Please sign in to comment.