diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..453925c --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1 @@ +style = "sciml" \ No newline at end of file diff --git a/.dev/Project.toml b/.dev/Project.toml new file mode 100644 index 0000000..2922960 --- /dev/null +++ b/.dev/Project.toml @@ -0,0 +1,3 @@ +[deps] +Git = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" diff --git a/.dev/herb_format.jl b/.dev/herb_format.jl new file mode 100644 index 0000000..d3e5bc3 --- /dev/null +++ b/.dev/herb_format.jl @@ -0,0 +1,70 @@ +""" +Formatting script inspired by that of the `Flux.jl` package, which +can be found at: +https://github.com/FluxML/Flux.jl/blob/caa1ceef9cf59bd817b7bf5c94d0ffbec5a0f32c/dev/flux_format.jl +""" + +using Pkg +Pkg.activate(@__DIR__) +Pkg.instantiate() + +using JuliaFormatter + +help = """ +Usage: herb_format [flags] [FILE/PATH]... +Formats the given julia files using the Herb formatting options. +If paths are given instead, it will format all *.jl files under +the paths. If nothing is given, all changed julia files are formatted. + -v, --verbose + Print the name of the files being formatted with relevant details. + -h, --help + Print this help message. + --check + Check if the files are formatted without changing them. +""" + +options = Dict{Symbol, Bool}() +indices_to_remove = [] # used to delete options once processed + +for (index, arg) in enumerate(ARGS) + if arg[1] != '-' + continue + end + val = true + if arg in ["-v", "--verbose"] + opt = :verbose + push!(indices_to_remove, index) + elseif arg in ["-h", "--help"] + opt = :help + push!(indices_to_remove, index) + elseif arg == "--check" + opt = :overwrite + val = false + write(stdout, "Checking files.\n") + push!(indices_to_remove, index) + else + error("Option $arg is not supported.") + end + options[opt] = val +end + +# remove options from args +deleteat!(ARGS, indices_to_remove) + +# print help message if asked +if haskey(options, :help) + write(stdout, help) + exit(0) +end + +# otherwise format files +if isempty(ARGS) + filenames = readlines(`git ls-files "*.jl"`) +else + filenames = ARGS +end + +write(stdout, "Formatting in progress.\n") +# format returns true if the files were already formatted +# and false if they were not (had to be formatted) +exit(format(filenames; options...) ? 0 : 1) diff --git a/.dev/setup.jl b/.dev/setup.jl new file mode 100644 index 0000000..44fa7b2 --- /dev/null +++ b/.dev/setup.jl @@ -0,0 +1,20 @@ +""" +Dev environment setup script inspired by that of the `Flux.jl` package, which +can be found at: +https://github.com/FluxML/Flux.jl/blob/caa1ceef9cf59bd817b7bf5c94d0ffbec5a0f32c/dev/setup.jl +""" + +# instantiate the environment +using Pkg +Pkg.activate(@__DIR__) +Pkg.instantiate() + +# setup the custom git hook +using Git + +# set the local hooks path +const git = Git.git() +run(`$git config --local core.hooksPath .githooks/`) + +# set file permission for hook +Base.Filesystem.chmod(".githooks", 0o777; recursive = true) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..b7b564b --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Migrate code style to SciML +4a4aaf91ac34c1c0eda650be5a5031432594773a \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..776d941 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Get the list of files that are about to be committed and filter out only the .jl files +files=$(git diff --cached --name-only --diff-filter=ACM | grep "\.jl$") + +# If no files are found, exit +if [ -z "$files" ]; then + exit 0 +fi + +# Run the herb formatter on the list of files +julia --startup-file=no -O1 --color=yes .dev/herb_format.jl --check $files + +# If the formatter exited with an error, abort the commit +if [ $? -ne 0 ]; then + echo "Error: formatter must be run on the files before committing." + echo "Please run julia .dev/herb_format.jl YOUR_CHANGED_FILES.jl" + exit 1 +fi \ No newline at end of file diff --git a/.github/workflows/JuliaFormatter.yml b/.github/workflows/JuliaFormatter.yml new file mode 100644 index 0000000..84f4ece --- /dev/null +++ b/.github/workflows/JuliaFormatter.yml @@ -0,0 +1,53 @@ +name: Formatting Check + +on: + push: + branches: + - master + tags: '*' + pull_request: + +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} +jobs: + format: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1' + os: + - ubuntu-latest + arch: + - x64 + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + julia_file_change: + - added|modified: '**.jl' + list-files: 'shell' + + - uses: julia-actions/setup-julia@latest + if: steps.filter.outputs.julia_file_change == 'true' + with: + version: ${{ matrix.version }} + + - uses: julia-actions/cache@v1 + + - name: Apply JuliaFormatter + if: steps.filter.outputs.julia_file_change == 'true' + run: | + julia --color=yes .dev/herb_format.jl --verbose ${{ steps.filter.outputs.julia_file_change_files }} + - name: Check formatting diff + if: steps.filter.outputs.julia_file_change == 'true' + run: | + git diff --color=always --exit-code \ No newline at end of file diff --git a/.github/workflows/check_docs.yml b/.github/workflows/check_docs.yml new file mode 100644 index 0000000..2cd9454 --- /dev/null +++ b/.github/workflows/check_docs.yml @@ -0,0 +1,54 @@ +name: Check Docs + +on: + push: + branches: + - master + tags: '*' + pull_request: + +jobs: + documentation: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Julia + uses: julia-actions/setup-julia@v1 + with: + version: '1' # Use the latest stable Julia version + - name: Install dependencies + run: | + julia --project=docs -e ' + using Pkg; + Pkg.develop(PackageSpec(path=pwd())); + Pkg.instantiate(); + Pkg.add("Documenter"); + ' + - name: Try building documentation and run doctests + run: | + julia --project=docs -e ' + using Documenter, HerbConstraints; + content = """ + ```@meta + CurrentModule = HerbConstraints + DocTestSetup = quote + using HerbConstraints + end + ``` + ```@autodocs + Modules = [HerbConstraints] + ``` + """ + mkpath("src/") + open("src/index.md", "w") do file + write(file, content) + end + makedocs( + sitename="HerbConstraints.jl", + modules=[HerbConstraints], + format=Documenter.HTML(), + doctest=true, + warnonly=[:missing_docs], + pages=["index.md"] + ); + ' \ No newline at end of file diff --git a/src/HerbConstraints.jl b/src/HerbConstraints.jl index 43061f2..711cb53 100644 --- a/src/HerbConstraints.jl +++ b/src/HerbConstraints.jl @@ -29,7 +29,6 @@ Inside the [`propagate!`](@ref) function, the constraint can use the following s """ abstract type AbstractLocalConstraint <: AbstractConstraint end - """ function get_priority(::AbstractLocalConstraint) @@ -78,77 +77,75 @@ include("grammarconstraints/forbidden_sequence.jl") include("grammarconstraints/unique.jl") export - AbstractGrammarConstraint, - AbstractLocalConstraint, - - DomainRuleNode, - VarNode, - pattern_match, - check_tree, - - #grammar constraints - Forbidden, - Ordered, - Contains, - ContainsSubtree, - ForbiddenSequence, - Unique, - - #local constraints - LocalForbidden, - LocalOrdered, - LocalContains, - LocalContainsSubtree, - LocalForbiddenSequence, - LocalUnique, - - #public solver functions - GenericSolver, - Solver, - SolverState, - new_state!, - save_state!, - load_state!, - isfeasible, - get_state, - get_tree, - get_grammar, - get_starting_symbol, - get_state, - get_node_at_location, - get_hole_at_location, - get_max_depth, - get_max_size, - get_tree_size, - - #tree manipulations - remove!, - remove_all_but!, - substitute!, - remove_node!, - - #domainutils - is_subdomain, - partition, - are_disjoint, - get_intersection, - - #solverstatistics - track!, - - #functions related to stateful objects - restore!, - StateInt, - get_value, - set_value!, - increment!, - decrement!, - - #uniform solver - UniformSolver, - - #state fixed shaped hole - StateHole, - freeze_state + AbstractGrammarConstraint, + AbstractLocalConstraint, DomainRuleNode, + VarNode, + pattern_match, + check_tree, + +#grammar constraints + Forbidden, + Ordered, + Contains, + ContainsSubtree, + ForbiddenSequence, + Unique, + +#local constraints + LocalForbidden, + LocalOrdered, + LocalContains, + LocalContainsSubtree, + LocalForbiddenSequence, + LocalUnique, + +#public solver functions + GenericSolver, + Solver, + SolverState, + new_state!, + save_state!, + load_state!, + isfeasible, + get_state, + get_tree, + get_grammar, + get_starting_symbol, + get_state, + get_node_at_location, + get_hole_at_location, + get_max_depth, + get_max_size, + get_tree_size, + +#tree manipulations + remove!, + remove_all_but!, + substitute!, + remove_node!, + +#domainutils + is_subdomain, + partition, + are_disjoint, + get_intersection, + +#solverstatistics + track!, + +#functions related to stateful objects + restore!, + StateInt, + get_value, + set_value!, + increment!, + decrement!, + +#uniform solver + UniformSolver, + +#state fixed shaped hole + StateHole, + freeze_state end # module HerbConstraints diff --git a/src/csg_annotated/csg_annotated.jl b/src/csg_annotated/csg_annotated.jl index 33f6b4f..b5bf0e7 100644 --- a/src/csg_annotated/csg_annotated.jl +++ b/src/csg_annotated/csg_annotated.jl @@ -44,19 +44,21 @@ macro csgrammar_annotated(expression) # parse rules, get constraints from annotations rules = Any[] types = Symbol[] - bytype = Dict{Symbol,Vector{Int}}() + bytype = Dict{Symbol, Vector{Int}}() constraints = Vector{AbstractConstraint}() rule_index = 1 for (e, label) in zip(expression.args, labels) # only consider if e is of type ... = ... - if !(e isa Expr && e.head == :(=)) continue end - + if !(e isa Expr && e.head == :(=)) + continue + end + # get the left and right hand side of a rule lhs = e.args[1] rhs = e.args[2] - + # parse annotations if present if rhs isa Expr && rhs.head == :(:=) # get new annotations as a list @@ -68,7 +70,8 @@ macro csgrammar_annotated(expression) end # convert annotations, append to constraints - append!(constraints, annotation2constraint(a, rule_index, labels) for a ∈ annotations) + append!(constraints, + annotation2constraint(a, rule_index, labels) for a in annotations) # discard annotation rhs = rhs.args[1] @@ -78,25 +81,27 @@ macro csgrammar_annotated(expression) new_rules = Any[] parse_rule!(new_rules, rhs) - @assert (length(new_rules) == 1 || label == "") "Cannot give rule name $(label) to multiple rules!" + @assert (length(new_rules) == 1||label == "") "Cannot give rule name $(label) to multiple rules!" # add new rules to data - for new_rule ∈ new_rules + for new_rule in new_rules push!(rules, new_rule) push!(types, lhs) bytype[lhs] = push!(get(bytype, lhs, Int[]), rule_index) - + rule_index += 1 end end # determine parameters alltypes = collect(keys(bytype)) - is_terminal = [isterminal(rule, alltypes) for rule ∈ rules] - is_eval = [iseval(rule) for rule ∈ rules] - childtypes = [get_childtypes(rule, alltypes) for rule ∈ rules] - bychildtypes = [BitVector([childtypes[i1] == childtypes[i2] for i2 ∈ 1:length(rules)]) for i1 ∈ 1:length(rules)] - domains = Dict(type => BitArray(r ∈ bytype[type] for r ∈ 1:length(rules)) for type ∈ alltypes) + is_terminal = [isterminal(rule, alltypes) for rule in rules] + is_eval = [iseval(rule) for rule in rules] + childtypes = [get_childtypes(rule, alltypes) for rule in rules] + bychildtypes = [BitVector([childtypes[i1] == childtypes[i2] for i2 in 1:length(rules)]) + for i1 in 1:length(rules)] + domains = Dict(type => BitArray(r ∈ bytype[type] for r in 1:length(rules)) + for type in alltypes) return ContextSensitiveGrammar( rules, @@ -112,14 +117,15 @@ macro csgrammar_annotated(expression) ) end - # gets the labels from an expression function _get_labels!(expression::Expr)::Vector{String} labels = Vector{String}() for e in expression.args # only consider if e is of type ... = ... - if !(e isa Expr && e.head == :(=)) continue end + if !(e isa Expr && e.head == :(=)) + continue + end lhs = e.args[1] @@ -140,7 +146,6 @@ function _get_labels!(expression::Expr)::Vector{String} return labels end - """ Converts an annotation to a constraint. commutative: creates an Ordered constraint @@ -148,7 +153,8 @@ transitive: creates an (incorrect) Forbidden constraint forbidden_path(path::Vector{Union{Symbol, Int}}): creates a ForbiddenPath constraint with the original rule included ... || ...: creates a OneOf constraint (also works with ... || ... || ... et cetera, though not very performant) """ -function annotation2constraint(annotation::Any, rule_index::Int, labels::Vector{String})::AbstractConstraint +function annotation2constraint( + annotation::Any, rule_index::Int, labels::Vector{String})::AbstractConstraint if annotation isa Expr # function-like annotations if annotation.head == :call @@ -157,7 +163,8 @@ function annotation2constraint(annotation::Any, rule_index::Int, labels::Vector{ if func_name == :forbidden_path string_args = eval(func_args[1]) - index_args = [arg isa Symbol ? _get_rule_index(labels, string(arg)) : arg for arg in string_args] + index_args = [arg isa Symbol ? _get_rule_index(labels, string(arg)) : arg + for arg in string_args] return ForbiddenPath( [rule_index; index_args] @@ -168,7 +175,8 @@ function annotation2constraint(annotation::Any, rule_index::Int, labels::Vector{ # disjunctive annotations if annotation.head == :|| return OneOf( - @show [annotation2constraint(a, rule_index, labels) for a in annotation.args] + @show [annotation2constraint(a, rule_index, labels) + for a in annotation.args] ) end end @@ -183,7 +191,8 @@ function annotation2constraint(annotation::Any, rule_index::Int, labels::Vector{ if annotation == :transitive return Forbidden( - MatchNode(rule_index, [MatchVar(:x), MatchNode(rule_index, [MatchVar(:y), MatchVar(:z)])]) + MatchNode(rule_index, + [MatchVar(:x), MatchNode(rule_index, [MatchVar(:y), MatchVar(:z)])]) ) end @@ -191,6 +200,6 @@ function annotation2constraint(annotation::Any, rule_index::Int, labels::Vector{ throw(ArgumentError("Annotation $(annotation) at rule $(rule_index) not found!")) end - # helper function for label lookup -_get_rule_index(labels::Vector{String}, label::String)::Int = findfirst(isequal(label), labels) +_get_rule_index(labels::Vector{String}, label::String)::Int = findfirst( + isequal(label), labels) diff --git a/src/domainrulenode.jl b/src/domainrulenode.jl index 46ea6c9..57b0210 100644 --- a/src/domainrulenode.jl +++ b/src/domainrulenode.jl @@ -13,15 +13,18 @@ struct DomainRuleNode <: AbstractRuleNode children::Vector{AbstractRuleNode} end -function DomainRuleNode(grammar::AbstractGrammar, rules::Vector{Int}, children::Vector{<:AbstractRuleNode}) +function DomainRuleNode( + grammar::AbstractGrammar, rules::Vector{Int}, children::Vector{<:AbstractRuleNode}) domain = falses(length(grammar.rules)) - for r ∈ rules + for r in rules domain[r] = true end return DomainRuleNode(domain, children) end -DomainRuleNode(grammar::AbstractGrammar, rules::Vector{Int}) = DomainRuleNode(grammar, rules, Vector{AbstractRuleNode}()) +function DomainRuleNode(grammar::AbstractGrammar, rules::Vector{Int}) + DomainRuleNode(grammar, rules, Vector{AbstractRuleNode}()) +end #DomainRuleNode(get_domain(grammar, sym), []) DomainRuleNode(domain::BitVector) = DomainRuleNode(domain, []) diff --git a/src/grammarconstraints/contains.jl b/src/grammarconstraints/contains.jl index 0ae6056..5d58934 100644 --- a/src/grammarconstraints/contains.jl +++ b/src/grammarconstraints/contains.jl @@ -22,5 +22,5 @@ function check_tree(c::Contains, tree::AbstractRuleNode)::Bool if get_rule(tree) == c.rule return true end - return any(check_tree(c, child) for child ∈ get_children(tree)) + return any(check_tree(c, child) for child in get_children(tree)) end diff --git a/src/grammarconstraints/contains_subtree.jl b/src/grammarconstraints/contains_subtree.jl index dfdcb41..0586452 100644 --- a/src/grammarconstraints/contains_subtree.jl +++ b/src/grammarconstraints/contains_subtree.jl @@ -27,5 +27,5 @@ function check_tree(c::ContainsSubtree, tree::AbstractRuleNode)::Bool if pattern_match(c.tree, tree) isa PatternMatchSuccess return true end - return any(check_tree(c, child) for child ∈ get_children(tree)) + return any(check_tree(c, child) for child in get_children(tree)) end diff --git a/src/grammarconstraints/forbidden.jl b/src/grammarconstraints/forbidden.jl index 9692389..4195886 100644 --- a/src/grammarconstraints/forbidden.jl +++ b/src/grammarconstraints/forbidden.jl @@ -27,8 +27,12 @@ function on_new_node(solver::Solver, c::Forbidden, path::Vector{Int}) #minor optimization: prevent the first hardfail (https://github.com/orgs/Herb-AI/projects/6/views/1?pane=issue&itemId=55570518) if c.tree isa RuleNode @match get_node_at_location(solver, path) begin - hole::AbstractHole => if !hole.domain[c.tree.ind] return end - node::RuleNode => if node.ind != c.tree.ind return end + hole::AbstractHole => if !hole.domain[c.tree.ind] + return + end + node::RuleNode => if node.ind != c.tree.ind + return + end end end post!(solver, LocalForbidden(path, c.tree)) @@ -41,10 +45,10 @@ Checks if the given [`AbstractRuleNode`](@ref) tree abides the [`Forbidden`](@re """ function check_tree(c::Forbidden, tree::AbstractRuleNode)::Bool @match pattern_match(tree, c.tree) begin - ::PatternMatchHardFail => () - ::PatternMatchSoftFail => () - ::PatternMatchSuccess => return false - ::PatternMatchSuccessWhenHoleAssignedTo => () + ::PatternMatchHardFail => () + ::PatternMatchSoftFail => () + ::PatternMatchSuccess => return false + ::PatternMatchSuccessWhenHoleAssignedTo => () end - return all(check_tree(c, child) for child ∈ tree.children) + return all(check_tree(c, child) for child in tree.children) end diff --git a/src/grammarconstraints/forbidden_sequence.jl b/src/grammarconstraints/forbidden_sequence.jl index e407985..10c947c 100644 --- a/src/grammarconstraints/forbidden_sequence.jl +++ b/src/grammarconstraints/forbidden_sequence.jl @@ -24,13 +24,19 @@ struct ForbiddenSequence <: AbstractGrammarConstraint ignore_if::Vector{Int} end -ForbiddenSequence(sequence::Vector{Int}; ignore_if=Vector{Int}()) = ForbiddenSequence(sequence, ignore_if) +function ForbiddenSequence(sequence::Vector{Int}; ignore_if = Vector{Int}()) + ForbiddenSequence(sequence, ignore_if) +end function on_new_node(solver::Solver, c::ForbiddenSequence, path::Vector{Int}) #minor optimization: prevent the first hardfail (https://github.com/orgs/Herb-AI/projects/6/views/1?pane=issue&itemId=55570518) @match get_node_at_location(solver, path) begin - hole::AbstractHole => if !hole.domain[c.sequence[end]] return end - node::RuleNode => if node.ind != c.sequence[end] return end + hole::AbstractHole => if !hole.domain[c.sequence[end]] + return + end + node::RuleNode => if node.ind != c.sequence[end] + return + end end post!(solver, LocalForbiddenSequence(path, c.sequence, c.ignore_if)) end @@ -40,18 +46,19 @@ end Checks if the given [`AbstractRuleNode`](@ref) tree abides the [`ForbiddenSequence`](@ref) constraint. """ -function check_tree(c::ForbiddenSequence, tree::AbstractRuleNode; sequence_started=false)::Bool +function check_tree( + c::ForbiddenSequence, tree::AbstractRuleNode; sequence_started = false)::Bool @assert isfilled(tree) "check_tree does not support checking trees that contain holes. $(tree) is a hole." # attempt to start the sequence on the any node in the tree if !sequence_started - for child ∈ tree.children - if !check_tree(c, child, sequence_started=false) + for child in tree.children + if !check_tree(c, child, sequence_started = false) return false end end end - + # add the current node to the current sequence if possible if (get_rule(tree) == c.sequence[1]) remaining_sequence = c.sequence[2:end] @@ -64,17 +71,17 @@ function check_tree(c::ForbiddenSequence, tree::AbstractRuleNode; sequence_start if isempty(remaining_sequence) return false end - + if sequence_started # the sequence contains one of the `ignore_if` rules, and therefore is satisfied if get_rule(tree) ∈ c.ignore_if return true end - + # continue the current sequence smaller_constraint = ForbiddenSequence(remaining_sequence, c.ignore_if) - for child ∈ tree.children - if !check_tree(smaller_constraint, child, sequence_started=true) + for child in tree.children + if !check_tree(smaller_constraint, child, sequence_started = true) return false end end diff --git a/src/grammarconstraints/ordered.jl b/src/grammarconstraints/ordered.jl index e1a0103..a9bc78e 100644 --- a/src/grammarconstraints/ordered.jl +++ b/src/grammarconstraints/ordered.jl @@ -33,8 +33,12 @@ function on_new_node(solver::Solver, c::Ordered, path::Vector{Int}) #minor optimization: prevent the first hardfail (https://github.com/orgs/Herb-AI/projects/6/views/1?pane=issue&itemId=55570518) if c.tree isa RuleNode @match get_node_at_location(solver, path) begin - hole::AbstractHole => if !hole.domain[c.tree.ind] return end - node::RuleNode => if node.ind != c.tree.ind return end + hole::AbstractHole => if !hole.domain[c.tree.ind] + return + end + node::RuleNode => if node.ind != c.tree.ind + return + end end end post!(solver, LocalOrdered(path, c.tree, c.order)) @@ -49,11 +53,11 @@ function check_tree(c::Ordered, tree::AbstractRuleNode)::Bool vars = Dict{Symbol, AbstractRuleNode}() if pattern_match(tree, c.tree, vars) isa PatternMatchSuccess # Check variable ordering - for (var₁, var₂) ∈ zip(c.order[1:end-1], c.order[2:end]) + for (var₁, var₂) in zip(c.order[1:(end - 1)], c.order[2:end]) if vars[var₁] > vars[var₂] return false end end end - return all(check_tree(c, child) for child ∈ tree.children) + return all(check_tree(c, child) for child in tree.children) end diff --git a/src/grammarconstraints/unique.jl b/src/grammarconstraints/unique.jl index f4a6859..9062a84 100644 --- a/src/grammarconstraints/unique.jl +++ b/src/grammarconstraints/unique.jl @@ -7,7 +7,6 @@ struct Unique <: AbstractGrammarConstraint rule::Int end - function on_new_node(solver::Solver, c::Unique, path::Vector{Int}) if length(path) == 0 #only post a local constraint at the root @@ -15,7 +14,6 @@ function on_new_node(solver::Solver, c::Unique, path::Vector{Int}) end end - """ function _count_occurrences(rule::Int, node::AbstractRuleNode)::Int @@ -24,13 +22,12 @@ Recursively counts the number of occurrences of the `rule` in the `node`. function _count_occurrences(node::AbstractRuleNode, rule::Int)::Int @assert isfilled(node) count = (get_rule(node) == rule) ? 1 : 0 - for child ∈ get_children(node) + for child in get_children(node) count += _count_occurrences(child, rule) end return count end - """ function check_tree(c::Unique, tree::AbstractRuleNode)::Bool diff --git a/src/lessthanorequal.jl b/src/lessthanorequal.jl index 0596f74..f4ce36b 100644 --- a/src/lessthanorequal.jl +++ b/src/lessthanorequal.jl @@ -8,7 +8,6 @@ A result of the `less_than_or_equal` function. Can be one of 3 cases: """ abstract type LessThanOrEqualResult end - """ abstract type LessThanOrEqualSuccess <: LessThanOrEqualResult @@ -20,7 +19,6 @@ The strictness of a LessThanOrEqualSuccess is specified by 1 of 2 concrete cases """ abstract type LessThanOrEqualSuccess <: LessThanOrEqualResult end - """ struct LessThanOrEqualSuccessEquality <: LessThanOrEqualSuccess end @@ -28,7 +26,6 @@ abstract type LessThanOrEqualSuccess <: LessThanOrEqualResult end """ struct LessThanOrEqualSuccessLessThan <: LessThanOrEqualSuccess end - """ struct LessThanOrEqualSuccessEquality <: LessThanOrEqualSuccess end @@ -36,7 +33,6 @@ struct LessThanOrEqualSuccessLessThan <: LessThanOrEqualSuccess end """ struct LessThanOrEqualSuccessEquality <: LessThanOrEqualSuccess end - """ struct LessThanOrEqualSuccessWithHoles <: LessThanOrEqualSuccess end @@ -45,7 +41,6 @@ Because of the holes involved, it is not possible to specify '<' or '=='. """ struct LessThanOrEqualSuccessWithHoles <: LessThanOrEqualSuccess end - """ struct LessThanOrEqualHardFail <: LessThanOrEqualResult end @@ -53,7 +48,6 @@ struct LessThanOrEqualSuccessWithHoles <: LessThanOrEqualSuccess end """ struct LessThanOrEqualHardFail <: LessThanOrEqualResult end - """ struct LessThanOrEqualSoftFail <: LessThanOrEqualResult @@ -69,7 +63,6 @@ end LessThanOrEqualSoftFail(hole) = LessThanOrEqualSoftFail(hole, nothing) - """ function make_less_than_or_equal!(h1::Union{RuleNode, AbstractHole}, h2::Union{RuleNode, AbstractHole})::LessThanOrEqualResult @@ -79,9 +72,9 @@ Ensures that n1<=n2 by removing impossible values from holes. Returns one of the - [`LessThanOrEqualSoftFail`](@ref). When no further deductions can be made, but [n1<=n2] and [n1>n2] are still possible. """ function make_less_than_or_equal!( - solver::Solver, - hole1::Union{RuleNode, AbstractHole}, - hole2::Union{RuleNode, AbstractHole} + solver::Solver, + hole1::Union{RuleNode, AbstractHole}, + hole2::Union{RuleNode, AbstractHole} )::LessThanOrEqualResult make_less_than_or_equal!(solver, hole1, hole2, Vector{Tuple{AbstractHole, Int}}()) end @@ -92,10 +85,10 @@ end Helper function that keeps track of the guards """ function make_less_than_or_equal!( - solver::Solver, - hole1::Union{RuleNode, AbstractHole}, - hole2::Union{RuleNode, AbstractHole}, - guards::Vector{Tuple{AbstractHole, Int}} + solver::Solver, + hole1::Union{RuleNode, AbstractHole}, + hole2::Union{RuleNode, AbstractHole}, + guards::Vector{Tuple{AbstractHole, Int}} )::LessThanOrEqualResult @assert isfeasible(solver) @match (isfilled(hole1), isfilled(hole2)) begin @@ -136,7 +129,8 @@ function make_less_than_or_equal!( return LessThanOrEqualSuccessLessThan() end # tiebreak on the children - return make_less_than_or_equal!(solver, hole1.children, hole2.children, guards) + return make_less_than_or_equal!( + solver, hole1.children, hole2.children, guards) else return LessThanOrEqualSoftFail(hole2) end @@ -169,7 +163,8 @@ function make_less_than_or_equal!( return LessThanOrEqualSuccessLessThan() end # tiebreak on the children - return make_less_than_or_equal!(solver, hole1.children, hole2.children, guards) + return make_less_than_or_equal!( + solver, hole1.children, hole2.children, guards) else return LessThanOrEqualSoftFail(hole1) end @@ -213,7 +208,8 @@ function make_less_than_or_equal!( # {2, 3} <= {3, 4}, try to tiebreak on the children push!(guards, (hole1, 0)) push!(guards, (hole2, 0)) - return make_less_than_or_equal!(solver, hole1.children, hole2.children, guards) + return make_less_than_or_equal!( + solver, hole1.children, hole2.children, guards) elseif left_highest_ind < right_lowest_ind # {2, 3} < {7, 8}, success return LessThanOrEqualSuccessLessThan() @@ -234,19 +230,19 @@ end Helper function that tiebreaks on children. """ function make_less_than_or_equal!( - solver::Solver, - nodes1::Vector{AbstractRuleNode}, - nodes2::Vector{AbstractRuleNode}, - guards::Vector{Tuple{AbstractHole, Int}} + solver::Solver, + nodes1::Vector{AbstractRuleNode}, + nodes2::Vector{AbstractRuleNode}, + guards::Vector{Tuple{AbstractHole, Int}} )::LessThanOrEqualResult - for (node1, node2) ∈ zip(nodes1, nodes2) + for (node1, node2) in zip(nodes1, nodes2) result = make_less_than_or_equal!(solver, node1, node2, guards) @match result begin - ::LessThanOrEqualSuccessWithHoles => (); - ::LessThanOrEqualSuccessEquality => (); - ::LessThanOrEqualSuccessLessThan => return result; - ::LessThanOrEqualSoftFail => return result; - ::LessThanOrEqualHardFail => begin + ::LessThanOrEqualSuccessWithHoles => () + ::LessThanOrEqualSuccessEquality => () + ::LessThanOrEqualSuccessLessThan => return result + ::LessThanOrEqualSoftFail => return result + ::LessThanOrEqualHardFail => begin if length(guards) == 0 return result elseif length(guards) == 1 @@ -261,5 +257,6 @@ function make_less_than_or_equal!( end end end - return isnothing(guards) ? LessThanOrEqualSuccessEquality() : LessThanOrEqualSuccessWithHoles() + return isnothing(guards) ? LessThanOrEqualSuccessEquality() : + LessThanOrEqualSuccessWithHoles() end diff --git a/src/localconstraints/local_contains.jl b/src/localconstraints/local_contains.jl index 1eaeb6d..aef2b59 100644 --- a/src/localconstraints/local_contains.jl +++ b/src/localconstraints/local_contains.jl @@ -5,7 +5,7 @@ LocalContains Enforces that a given `rule` appears at or below the given `path` at least once. """ struct LocalContains <: AbstractLocalConstraint - path::Vector{Int} + path::Vector{Int} rule::Int end @@ -20,11 +20,11 @@ function propagate!(solver::Solver, c::LocalContains) node = get_node_at_location(solver, c.path) track!(solver, "LocalContains propagation") @match _contains(node, c.rule) begin - true => begin + true => begin track!(solver, "LocalContains satisfied") deactivate!(solver, c) end - false => begin + false => begin track!(solver, "LocalContains inconsistency") set_infeasible!(solver) end @@ -63,7 +63,8 @@ function _contains(node::AbstractRuleNode, rule::Int)::Union{Vector{AbstractHole return _contains(node, rule, Vector{AbstractHole}()) end -function _contains(node::AbstractRuleNode, rule::Int, holes::Vector{AbstractHole})::Union{Vector{AbstractHole}, Bool} +function _contains(node::AbstractRuleNode, rule::Int, + holes::Vector{AbstractHole})::Union{Vector{AbstractHole}, Bool} if !isuniform(node) # the rule might appear underneath this non-uniform hole push!(holes, node) @@ -81,8 +82,9 @@ function _contains(node::AbstractRuleNode, rule::Int, holes::Vector{AbstractHole return _contains(get_children(node), rule, holes) end -function _contains(children::Vector{AbstractRuleNode}, rule::Int, holes::Vector{AbstractHole})::Union{Vector{AbstractHole}, Bool} - for child ∈ children +function _contains(children::Vector{AbstractRuleNode}, rule::Int, + holes::Vector{AbstractHole})::Union{Vector{AbstractHole}, Bool} + for child in children if _contains(child, rule, holes) == true return true end diff --git a/src/localconstraints/local_contains_subtree.jl b/src/localconstraints/local_contains_subtree.jl index ea2e6a1..20b7deb 100644 --- a/src/localconstraints/local_contains_subtree.jl +++ b/src/localconstraints/local_contains_subtree.jl @@ -9,7 +9,7 @@ Enforces that a given `tree` appears at or below the given `path` at least once. The `indices` and `candidates` fields should not be set by the user. """ mutable struct LocalContainsSubtree <: AbstractLocalConstraint - path::Vector{Int} + path::Vector{Int} tree::AbstractRuleNode candidates::Union{Vector{AbstractRuleNode}, Nothing} indices::Union{StateSparseSet, Nothing} @@ -24,7 +24,6 @@ function LocalContainsSubtree(path::Vector{Int}, tree::AbstractRuleNode) LocalContainsSubtree(path, tree, Vector{AbstractRuleNode}(), nothing) end - """ function propagate!(::GenericSolver, ::LocalContainsSubtree) @@ -36,7 +35,6 @@ function propagate!(::GenericSolver, ::LocalContainsSubtree) throw(ArgumentError("LocalContainsSubtree cannot be propagated by the GenericSolver")) end - """ function propagate!(solver::UniformSolver, c::LocalContainsSubtree) @@ -49,15 +47,16 @@ function propagate!(solver::UniformSolver, c::LocalContainsSubtree) if isnothing(c.candidates) # Initial propagation: pattern match all nodes, only store the candidates for re-propagation c.candidates = Vector{AbstractRuleNode}() - for node ∈ get_nodes(solver) + for node in get_nodes(solver) @match pattern_match(c.tree, node) begin ::PatternMatchHardFail => () ::PatternMatchSuccess => begin track!(solver, "LocalContainsSubtree satisfied (initial propagation)") - deactivate!(solver, c); + deactivate!(solver, c) return end - ::PatternMatchSoftFail || ::PatternMatchSuccessWhenHoleAssignedTo => push!(c.candidates, node) + ::PatternMatchSoftFail || ::PatternMatchSuccessWhenHoleAssignedTo => push!( + c.candidates, node) end end n = length(c.candidates) @@ -69,16 +68,16 @@ function propagate!(solver::UniformSolver, c::LocalContainsSubtree) @match make_equal!(solver, c.candidates[1], c.tree) begin ::MakeEqualHardFail => begin @assert false "pattern_match failed to detect a hardfail" - end - ::MakeEqualSuccess => begin + end + ::MakeEqualSuccess => begin track!(solver, "LocalContainsSubtree deduction (initial)") - deactivate!(solver, c); + deactivate!(solver, c) return - end + end ::MakeEqualSoftFail => begin track!(solver, "LocalContainsSubtree softfail (1 candidate) (initial)") return - end + end end else track!(solver, "LocalContainsSubtree softfail (>=2 candidates) (initial)") @@ -89,13 +88,13 @@ function propagate!(solver::UniformSolver, c::LocalContainsSubtree) # Re-propagation if !isnothing(c.indices) && (size(c.indices) >= 2) # Update the candidates by pattern matching them again - for i ∈ c.indices + for i in c.indices match = pattern_match(c.candidates[i], c.tree) @match match begin ::PatternMatchHardFail => remove!(c.indices, i) ::PatternMatchSuccess => begin track!(solver, "LocalContainsSubtree satisfied") - deactivate!(solver, c); + deactivate!(solver, c) return end ::PatternMatchSoftFail || ::PatternMatchSuccessWhenHoleAssignedTo => () @@ -111,16 +110,16 @@ function propagate!(solver::UniformSolver, c::LocalContainsSubtree) track!(solver, "LocalContainsSubtree inconsistency") set_infeasible!(solver) return - end - ::MakeEqualSuccess => begin + end + ::MakeEqualSuccess => begin track!(solver, "LocalContainsSubtree deduction") - deactivate!(solver, c); + deactivate!(solver, c) return - end + end ::MakeEqualSoftFail => begin track!(solver, "LocalContainsSubtree softfail (1 candidate)") return - end + end end elseif n == 0 track!(solver, "LocalContainsSubtree inconsistency") diff --git a/src/localconstraints/local_forbidden.jl b/src/localconstraints/local_forbidden.jl index fc72475..ae137e9 100644 --- a/src/localconstraints/local_forbidden.jl +++ b/src/localconstraints/local_forbidden.jl @@ -22,17 +22,17 @@ function propagate!(solver::Solver, c::LocalForbidden) node = get_node_at_location(solver, c.path) track!(solver, "LocalForbidden propagation") @match pattern_match(node, c.tree) begin - ::PatternMatchHardFail => begin + ::PatternMatchHardFail => begin # A match fail means that the constraint is already satisfied. # This constraint does not have to be re-propagated. deactivate!(solver, c) track!(solver, "LocalForbidden hardfail") - end; - match::PatternMatchSoftFail => begin + end + match::PatternMatchSoftFail => begin # The constraint needs to be re-propagated track!(solver, "LocalForbidden softfail") end - ::PatternMatchSuccess => begin + ::PatternMatchSuccess => begin # The forbidden tree is exactly matched. This means the state is infeasible. track!(solver, "LocalForbidden inconsistency") set_infeasible!(solver) #throw(InconsistencyException()) diff --git a/src/localconstraints/local_forbidden_sequence.jl b/src/localconstraints/local_forbidden_sequence.jl index d02456a..1ac2702 100644 --- a/src/localconstraints/local_forbidden_sequence.jl +++ b/src/localconstraints/local_forbidden_sequence.jl @@ -15,8 +15,10 @@ end Return true iff the manipulation happened at or above the constraint path. """ -function shouldschedule(::Solver, constraint::LocalForbiddenSequence, path::Vector{Int})::Bool - return (length(constraint.path) >= length(path)) && (path== constraint.path[1:length(path)] ) +function shouldschedule( + ::Solver, constraint::LocalForbiddenSequence, path::Vector{Int})::Bool + return (length(constraint.path) >= length(path)) && + (path == constraint.path[1:length(path)]) end """ @@ -30,7 +32,7 @@ function propagate!(solver::Solver, c::LocalForbiddenSequence) # Smallest match forbidden_assignments = Vector{Tuple{Int, Any}}() i = length(c.sequence) - for (path_idx, node) ∈ Iterators.reverse(enumerate(nodes)) + for (path_idx, node) in Iterators.reverse(enumerate(nodes)) forbidden_rule = c.sequence[i] if (node isa RuleNode) || (node isa StateHole && isfilled(node)) rule = get_rule(node) @@ -46,9 +48,9 @@ function propagate!(solver::Solver, c::LocalForbiddenSequence) push!(forbidden_assignments, (path_idx, forbidden_rule)) i -= 1 else - for r ∈ c.ignore_if + for r in c.ignore_if if node.domain[r] - rules = [r for r ∈ findall(node.domain) if r ∉ c.ignore_if] + rules = [r for r in findall(node.domain) if r ∉ c.ignore_if] if !isempty(rules) push!(forbidden_assignments, (path_idx, rules)) break @@ -83,14 +85,14 @@ function propagate!(solver::Solver, c::LocalForbiddenSequence) if path_idx > length(c.path) deactivate!(solver, c) end - remove!(solver, c.path[1:path_idx-1], rule) + remove!(solver, c.path[1:(path_idx - 1)], rule) return end # Smallest match with a maximum of 1 hole (Optional, slightly stronger inference without making all possible matches) i = length(c.sequence) forbidden_assignment = nothing - for (path_idx, node) ∈ Iterators.reverse(enumerate(nodes)) + for (path_idx, node) in Iterators.reverse(enumerate(nodes)) forbidden_rule = c.sequence[i] if (node isa RuleNode) || (node isa StateHole && isfilled(node)) rule = get_rule(node) @@ -101,7 +103,7 @@ function propagate!(solver::Solver, c::LocalForbiddenSequence) i -= 1 end else - for r ∈ c.ignore_if + for r in c.ignore_if if node.domain[r] #softfail (ignore if) return @@ -129,19 +131,19 @@ function propagate!(solver::Solver, c::LocalForbiddenSequence) if path_idx > length(c.path) deactivate!(solver, c) end - remove!(solver, c.path[1:path_idx-1], rule) + remove!(solver, c.path[1:(path_idx - 1)], rule) end - """ function get_nodes_on_path(root::AbstractRuleNode, path::Vector{Int})::Vector{AbstractRuleNode} Gets a list of nodes on the `path`, starting (and including) the `root`. """ -function get_nodes_on_path(node::AbstractRuleNode, path::Vector{Int})::Vector{AbstractRuleNode} +function get_nodes_on_path( + node::AbstractRuleNode, path::Vector{Int})::Vector{AbstractRuleNode} nodes = Vector{AbstractRuleNode}() push!(nodes, node) - for i ∈ path + for i in path node = node.children[i] push!(nodes, node) end diff --git a/src/localconstraints/local_ordered.jl b/src/localconstraints/local_ordered.jl index 2570947..ee93b60 100644 --- a/src/localconstraints/local_ordered.jl +++ b/src/localconstraints/local_ordered.jl @@ -23,21 +23,21 @@ function propagate!(solver::Solver, c::LocalOrdered) track!(solver, "LocalOrdered propagation") vars = Dict{Symbol, AbstractRuleNode}() @match pattern_match(node, c.tree, vars) begin - ::PatternMatchHardFail => begin + ::PatternMatchHardFail => begin # A match fail means that the constraint is already satisfied. # This constraint does not have to be re-propagated. deactivate!(solver, c) track!(solver, "LocalOrdered match hardfail") - end; - ::PatternMatchSoftFail || ::PatternMatchSuccessWhenHoleAssignedTo => begin + end + ::PatternMatchSoftFail || ::PatternMatchSuccessWhenHoleAssignedTo => begin # The constraint will re-propagated on any tree manipulation. track!(solver, "LocalOrdered match softfail") () end - ::PatternMatchSuccess => begin + ::PatternMatchSuccess => begin # The forbidden tree is exactly matched. - should_deactivate = true - for (name1, name2) ∈ zip(c.order[1:end-1], c.order[2:end]) + should_deactivate = true + for (name1, name2) in zip(c.order[1:(end - 1)], c.order[2:end]) # Removing rules is handled inside make_less_than_or_equal! @match make_less_than_or_equal!(solver, vars[name1], vars[name2]) begin ::LessThanOrEqualHardFail => begin diff --git a/src/localconstraints/local_unique.jl b/src/localconstraints/local_unique.jl index 84e21f1..8ac9f96 100644 --- a/src/localconstraints/local_unique.jl +++ b/src/localconstraints/local_unique.jl @@ -6,7 +6,7 @@ Enforces that a given `rule` appears at or below the given `path` at most once. In case of the UniformSolver, cache the list of `holes`, since no new holes can appear. """ struct LocalUnique <: AbstractLocalConstraint - path::Vector{Int} + path::Vector{Int} rule::Int holes::Vector{AbstractHole} end @@ -34,11 +34,11 @@ function propagate!(solver::Solver, c::LocalUnique) set_infeasible!(solver) track!(solver, "LocalUnique inconsistency") elseif count == 1 - if all(isuniform(hole) for hole ∈ c.holes) + if all(isuniform(hole) for hole in c.holes) track!(solver, "LocalUnique deactivate") deactivate!(solver, c) - end - for hole ∈ c.holes + end + for hole in c.holes deductions = 0 if (hole.domain[c.rule] == true) && !isfilled(hole) path = get_path(solver, hole) @@ -61,7 +61,8 @@ All holes that potentially can hold the target rule are stored in the `holes` ve Stops counting if the rule occurs more than once. Counting beyond 2 is not needed for LocalUnique. """ -function _count_occurrences!(node::AbstractRuleNode, rule::Int, holes::Vector{AbstractHole})::Int +function _count_occurrences!( + node::AbstractRuleNode, rule::Int, holes::Vector{AbstractHole})::Int count = 0 if isfilled(node) # if the rulenode is the second occurence of the rule, hardfail @@ -77,7 +78,7 @@ function _count_occurrences!(node::AbstractRuleNode, rule::Int, holes::Vector{Ab push!(holes, node) end end - for child ∈ get_children(node) + for child in get_children(node) count += _count_occurrences!(child, rule, holes) if count > 1 return count @@ -97,7 +98,7 @@ Counts the occurences of the `rule` in the cached list of `holes`. """ function _count_occurrences(holes::Vector{AbstractHole}, rule::Int) count = 0 - for hole ∈ holes + for hole in holes if isfilled(hole) && get_rule(hole) == rule count += 1 if count >= 2 diff --git a/src/makeequal.jl b/src/makeequal.jl index bdcd43d..c1e5c0e 100644 --- a/src/makeequal.jl +++ b/src/makeequal.jl @@ -39,18 +39,18 @@ struct MakeEqualSoftFail <: MakeEqualResult end Tree manipulation that enforces `node1` == `node2` if unambiguous. """ function make_equal!( - solver::Solver, - hole1::Union{RuleNode, AbstractHole}, - hole2::Union{RuleNode, AbstractHole, DomainRuleNode} + solver::Solver, + hole1::Union{RuleNode, AbstractHole}, + hole2::Union{RuleNode, AbstractHole, DomainRuleNode} )::MakeEqualResult make_equal!(solver, hole1, hole2, Dict{Symbol, AbstractRuleNode}()) end function make_equal!( - solver::Solver, - hole1::Union{RuleNode, AbstractHole}, - hole2::Union{RuleNode, AbstractHole}, - vars::Dict{Symbol, AbstractRuleNode} + solver::Solver, + hole1::Union{RuleNode, AbstractHole}, + hole2::Union{RuleNode, AbstractHole}, + vars::Dict{Symbol, AbstractRuleNode} )::MakeEqualResult @assert isfeasible(solver) @match (isfilled(hole1), isfilled(hole2)) begin @@ -101,11 +101,11 @@ function make_equal!( end softfailed = false - for (child1, child2) ∈ zip(get_children(hole1), get_children(hole2)) + for (child1, child2) in zip(get_children(hole1), get_children(hole2)) result = make_equal!(solver, child1, child2, vars) @match result begin - ::MakeEqualSuccess => (); - ::MakeEqualHardFail => return result; + ::MakeEqualSuccess => () + ::MakeEqualHardFail => return result ::MakeEqualSoftFail => begin softfailed = true end @@ -115,12 +115,12 @@ function make_equal!( end function make_equal!( - solver::Solver, - node::Union{RuleNode, AbstractHole}, - var::VarNode, - vars::Dict{Symbol, AbstractRuleNode} + solver::Solver, + node::Union{RuleNode, AbstractHole}, + var::VarNode, + vars::Dict{Symbol, AbstractRuleNode} )::MakeEqualResult - if var.name ∈ keys(vars) + if var.name ∈ keys(vars) return make_equal!(solver, node, vars[var.name], vars) end vars[var.name] = node @@ -128,12 +128,12 @@ function make_equal!( end function make_equal!( - solver::Solver, - node::Union{RuleNode, AbstractHole}, - domainrulenode::DomainRuleNode, - vars::Dict{Symbol, AbstractRuleNode} + solver::Solver, + node::Union{RuleNode, AbstractHole}, + domainrulenode::DomainRuleNode, + vars::Dict{Symbol, AbstractRuleNode} )::MakeEqualResult - softfailed = false + softfailed = false if isfilled(node) #(RuleNode, DomainRuleNode) if !domainrulenode.domain[get_rule(node)] @@ -154,11 +154,11 @@ function make_equal!( end end - for (child1, child2) ∈ zip(get_children(node), get_children(domainrulenode)) + for (child1, child2) in zip(get_children(node), get_children(domainrulenode)) result = make_equal!(solver, child1, child2, vars) @match result begin - ::MakeEqualSuccess => (); - ::MakeEqualHardFail => return result; + ::MakeEqualSuccess => () + ::MakeEqualHardFail => return result ::MakeEqualSoftFail => begin softfailed = true end diff --git a/src/patternmatch.jl b/src/patternmatch.jl index 7e643b3..522a700 100644 --- a/src/patternmatch.jl +++ b/src/patternmatch.jl @@ -56,7 +56,8 @@ end Generic fallback function for commutativity. Swaps arguments 1 and 2, then dispatches to a more specific signature. If this gets stuck in an infinite loop, the implementation of an AbstractRuleNode type pair is missing. """ -function pattern_match(mn::AbstractRuleNode, rn::AbstractRuleNode, vars::Dict{Symbol, AbstractRuleNode}) +function pattern_match( + mn::AbstractRuleNode, rn::AbstractRuleNode, vars::Dict{Symbol, AbstractRuleNode}) pattern_match(rn, mn, vars) end @@ -66,7 +67,8 @@ end Pairwise tries to match two ordered lists of [AbstractRuleNode](@ref)s. Typically, this function is used to pattern match the children two AbstractRuleNodes. """ -function pattern_match(rns::Vector{AbstractRuleNode}, mns::Vector{AbstractRuleNode}, vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult +function pattern_match(rns::Vector{AbstractRuleNode}, mns::Vector{AbstractRuleNode}, + vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult # Currently, invalid arities are not supported. # Suppose rule 3 = "S -> -S" # Consider two equivalent constraints: @@ -79,19 +81,19 @@ function pattern_match(rns::Vector{AbstractRuleNode}, mns::Vector{AbstractRuleNo # if (length(rns) == 0 || length(mns) == 0) # return PatternMatchSuccess() # end - @assert length(rns) == length(mns) "Unable to pattern match rulenodes with different arities" + @assert length(rns)==length(mns) "Unable to pattern match rulenodes with different arities" match_result = PatternMatchSuccess() - for (n1, n2) ∈ zip(rns, mns) + for (n1, n2) in zip(rns, mns) child_match_result = pattern_match(n1, n2, vars) @match child_match_result begin - ::PatternMatchHardFail => return child_match_result; - ::PatternMatchSoftFail => (match_result = child_match_result); #continue searching for a hardfail - ::PatternMatchSuccess => (); #continue searching for a hardfail + ::PatternMatchHardFail => return child_match_result + ::PatternMatchSoftFail => (match_result = child_match_result) #continue searching for a hardfail + ::PatternMatchSuccess => () #continue searching for a hardfail ::PatternMatchSuccessWhenHoleAssignedTo => begin if !(match_result isa PatternMatchSuccess) return PatternMatchSoftFail(child_match_result.hole) end - match_result = child_match_result; + match_result = child_match_result end end end @@ -103,8 +105,9 @@ end Comparing any [`AbstractRuleNode`](@ref) with a named [`VarNode`](@ref) """ -function pattern_match(rn::AbstractRuleNode, var::VarNode, vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult - if var.name ∈ keys(vars) +function pattern_match(rn::AbstractRuleNode, var::VarNode, + vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult + if var.name ∈ keys(vars) return pattern_match(rn, vars[var.name]) end vars[var.name] = rn @@ -116,7 +119,8 @@ end Comparing any [`AbstractRuleNode`](@ref) with a [`DomainRuleNode`](@ref) """ -function pattern_match(node::AbstractRuleNode, domainrulenode::DomainRuleNode, vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult +function pattern_match(node::AbstractRuleNode, domainrulenode::DomainRuleNode, + vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult if isfilled(node) #(RuleNode, DomainRuleNode) if !domainrulenode.domain[get_rule(node)] @@ -132,10 +136,11 @@ function pattern_match(node::AbstractRuleNode, domainrulenode::DomainRuleNode, v #a large hole is involved return PatternMatchSoftFail(node) end - children_match_result = pattern_match(get_children(node), get_children(domainrulenode), vars) + children_match_result = pattern_match( + get_children(node), get_children(domainrulenode), vars) @match children_match_result begin - ::PatternMatchHardFail => return children_match_result; - ::PatternMatchSoftFail => return children_match_result; + ::PatternMatchHardFail => return children_match_result + ::PatternMatchSoftFail => return children_match_result ::PatternMatchSuccess => begin if is_subdomain(node.domain, domainrulenode.domain) return children_match_result @@ -147,13 +152,13 @@ function pattern_match(node::AbstractRuleNode, domainrulenode::DomainRuleNode, v return PatternMatchSuccessWhenHoleAssignedTo(node, intersection[1]) #exactly this value end return PatternMatchSuccessWhenHoleAssignedTo(node, intersection) #one of multiple values - end + end ::PatternMatchSuccessWhenHoleAssignedTo => begin if is_subdomain(node.domain, domainrulenode.domain) return children_match_result end return PatternMatchSoftFail(children_match_result.hole) - end + end end end end @@ -166,7 +171,9 @@ It is important to note that some `AbstractHole`s are already filled and should This is why this function is dispatched on `(isfilled(h1), isfilled(h2))`. The '(RuleNode, AbstractHole)' case could still include two nodes of type `AbstractHole`, but one of them should be treated as a rulenode. """ -function pattern_match(h1::Union{RuleNode, AbstractHole}, h2::Union{RuleNode, AbstractHole}, vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult +function pattern_match( + h1::Union{RuleNode, AbstractHole}, h2::Union{RuleNode, AbstractHole}, + vars::Dict{Symbol, AbstractRuleNode})::PatternMatchResult @match (isfilled(h1), isfilled(h2)) begin #(RuleNode, RuleNode) (true, true) => begin @@ -182,12 +189,14 @@ function pattern_match(h1::Union{RuleNode, AbstractHole}, h2::Union{RuleNode, Ab return PatternMatchHardFail() end if isuniform(h2) - children_match_result = pattern_match(get_children(h1), get_children(h2), vars) + children_match_result = pattern_match( + get_children(h1), get_children(h2), vars) @match children_match_result begin - ::PatternMatchHardFail => return children_match_result; - ::PatternMatchSoftFail => return children_match_result; - ::PatternMatchSuccess => return PatternMatchSuccessWhenHoleAssignedTo(h2, get_rule(h1)); - ::PatternMatchSuccessWhenHoleAssignedTo => return PatternMatchSoftFail(children_match_result.hole); + ::PatternMatchHardFail => return children_match_result + ::PatternMatchSoftFail => return children_match_result + ::PatternMatchSuccess => return PatternMatchSuccessWhenHoleAssignedTo( + h2, get_rule(h1)) + ::PatternMatchSuccessWhenHoleAssignedTo => return PatternMatchSoftFail(children_match_result.hole) end end if !h2.domain[get_rule(h1)] @@ -209,12 +218,13 @@ function pattern_match(h1::Union{RuleNode, AbstractHole}, h2::Union{RuleNode, Ab return PatternMatchHardFail() end if isuniform(h1) && isuniform(h2) - children_match_result = pattern_match(get_children(h1), get_children(h2), vars) + children_match_result = pattern_match( + get_children(h1), get_children(h2), vars) @match children_match_result begin - ::PatternMatchHardFail => return children_match_result; - ::PatternMatchSoftFail => return children_match_result; - ::PatternMatchSuccess => return PatternMatchSoftFail(h1); - ::PatternMatchSuccessWhenHoleAssignedTo => return PatternMatchSoftFail(children_match_result.hole); + ::PatternMatchHardFail => return children_match_result + ::PatternMatchSoftFail => return children_match_result + ::PatternMatchSuccess => return PatternMatchSoftFail(h1) + ::PatternMatchSuccessWhenHoleAssignedTo => return PatternMatchSoftFail(children_match_result.hole) end end return PatternMatchSoftFail(isuniform(h1) ? h2 : h1) diff --git a/src/solver/domainutils.jl b/src/solver/domainutils.jl index 3e14aac..326fed7 100644 --- a/src/solver/domainutils.jl +++ b/src/solver/domainutils.jl @@ -8,7 +8,7 @@ function is_subdomain(subdomain::BitVector, domain::BitVector) return all(.!subdomain .| domain) end function is_subdomain(subdomain::StateSparseSet, domain::BitVector) - for v ∈ subdomain + for v in subdomain if !domain[v] return false end @@ -29,9 +29,9 @@ function is_subdomain(specific_tree::AbstractRuleNode, general_tree::AbstractRul return false end end - + #(RuleNode, AbstractHole), the rule must be inside the domain of the general_tree - (true, false) => begin + (true, false) => begin if !general_tree.domain[get_rule(specific_tree)] return false end @@ -41,7 +41,7 @@ function is_subdomain(specific_tree::AbstractRuleNode, general_tree::AbstractRul (false, true) => return false #(AbstractHole, AbstractHole), dispatch to the is_subdomain for domains - (false, false) => begin + (false, false) => begin if !is_subdomain(specific_tree.domain, general_tree.domain) return false end @@ -58,7 +58,8 @@ function is_subdomain(specific_tree::AbstractRuleNode, general_tree::AbstractRul @assert isuniform(general_tree) @assert isuniform(specific_tree) "The specific_tree cannot be a non-uniform Hole at this point." @assert length(get_children(specific_tree)) == length(get_children(general_tree)) - for (specific_child, general_child) ∈ zip(get_children(specific_tree), get_children(general_tree)) + for (specific_child, general_child) in zip( + get_children(specific_tree), get_children(general_tree)) if !is_subdomain(specific_child, general_child) return false end @@ -96,7 +97,7 @@ function are_disjoint(domain1::BitVector, domain2::BitVector)::Bool end are_disjoint(bitvector::BitVector, sss::StateSparseSet)::Bool = are_disjoint(sss, bitvector) function are_disjoint(sss::StateSparseSet, bitvector::BitVector) - for v ∈ sss + for v in sss if bitvector[v] return false end @@ -112,13 +113,14 @@ Returns all the values that are in both `domain1` and `domain2` function get_intersection(domain1::BitVector, domain2::BitVector)::Vector{Int} return findall(domain1 .& domain2) end -function get_intersection(sss::Union{BitVector, StateSparseSet}, domain2::Union{BitVector, StateSparseSet})::Vector{Int} - if !(sss isa StateSparseSet) +function get_intersection(sss::Union{BitVector, StateSparseSet}, + domain2::Union{BitVector, StateSparseSet})::Vector{Int} + if !(sss isa StateSparseSet) sss, domain2 = domain2, sss @assert sss isa StateSparseSet end intersection = Vector{Int}() - for v ∈ sss + for v in sss if domain2[v] push!(intersection, v) end diff --git a/src/solver/generic_solver/generic_solver.jl b/src/solver/generic_solver/generic_solver.jl index baf2d9c..31ff490 100644 --- a/src/solver/generic_solver/generic_solver.jl +++ b/src/solver/generic_solver/generic_solver.jl @@ -24,34 +24,35 @@ mutable struct GenericSolver <: Solver max_depth::Int end - """ GenericSolver(grammar::AbstractGrammar, sym::Symbol) Constructs a new solver, with an initial state using starting symbol `sym` """ -function GenericSolver(grammar::AbstractGrammar, sym::Symbol; with_statistics=false, use_uniformsolver=true, max_size = typemax(Int), max_depth = typemax(Int)) +function GenericSolver(grammar::AbstractGrammar, sym::Symbol; with_statistics = false, + use_uniformsolver = true, max_size = typemax(Int), max_depth = typemax(Int)) init_node = Hole(get_domain(grammar, sym)) - GenericSolver(grammar, init_node, with_statistics=with_statistics, use_uniformsolver=use_uniformsolver, max_size = max_size, max_depth = max_depth) + GenericSolver(grammar, init_node, with_statistics = with_statistics, + use_uniformsolver = use_uniformsolver, max_size = max_size, max_depth = max_depth) end - """ GenericSolver(grammar::AbstractGrammar, init_node::AbstractRuleNode) Constructs a new solver, with an initial state of the provided [`AbstractRuleNode`](@ref). """ -function GenericSolver(grammar::AbstractGrammar, init_node::AbstractRuleNode; with_statistics=false, use_uniformsolver=true, max_size = typemax(Int), max_depth = typemax(Int)) +function GenericSolver( + grammar::AbstractGrammar, init_node::AbstractRuleNode; with_statistics = false, + use_uniformsolver = true, max_size = typemax(Int), max_depth = typemax(Int)) stats = with_statistics ? SolverStatistics() : nothing - solver = GenericSolver(grammar, nothing, PriorityQueue{AbstractLocalConstraint, Int}(), stats, use_uniformsolver, false, max_size, max_depth) + solver = GenericSolver(grammar, nothing, PriorityQueue{AbstractLocalConstraint, Int}(), + stats, use_uniformsolver, false, max_size, max_depth) new_state!(solver, init_node) return solver end - get_name(::GenericSolver) = "GenericSolver" - """ deactivate!(solver::GenericSolver, constraint::AbstractLocalConstraint) @@ -95,7 +96,6 @@ function deactivate!(solver::GenericSolver, constraint::AbstractLocalConstraint) delete!(get_state(solver).active_constraints, constraint) end - """ post!(solver::GenericSolver, constraint::AbstractLocalConstraint) @@ -104,7 +104,9 @@ By default, the constraint will be scheduled for its initial propagation. Constraints can overload this method to add themselves to notify lists or triggers. """ function post!(solver::GenericSolver, constraint::AbstractLocalConstraint) - if !isfeasible(solver) return end + if !isfeasible(solver) + return + end track!(solver, "post! $(typeof(constraint))") # add to the list of active constraints push!(get_state(solver).active_constraints, constraint) @@ -115,7 +117,6 @@ function post!(solver::GenericSolver, constraint::AbstractLocalConstraint) solver.fix_point_running = temp end - """ new_state!(solver::GenericSolver, tree::AbstractRuleNode) @@ -129,7 +130,7 @@ function new_state!(solver::GenericSolver, tree::AbstractRuleNode) if (node isa AbstractHole) simplify_hole!(solver, path) end - for (i, childnode) ∈ enumerate(get_children(node)) + for (i, childnode) in enumerate(get_children(node)) _dfs_simplify(childnode, push!(copy(path), i)) end end @@ -139,7 +140,6 @@ function new_state!(solver::GenericSolver, tree::AbstractRuleNode) fix_point!(solver) end - """ save_state!(solver::GenericSolver) @@ -150,7 +150,6 @@ function save_state!(solver::GenericSolver)::SolverState return copy(get_state(solver)) end - """ load_state!(solver::GenericSolver, state::SolverState) @@ -161,7 +160,6 @@ function load_state!(solver::GenericSolver, state::SolverState) solver.state = state end - """ function get_tree_size(solver::GenericSolver)::Int @@ -171,7 +169,6 @@ function get_tree_size(solver::GenericSolver)::Int return length(get_tree(solver)) end - """ function get_tree(solver::GenericSolver)::AbstractRuleNode @@ -181,7 +178,6 @@ function get_tree(solver::GenericSolver)::AbstractRuleNode return solver.state.tree end - """ function get_grammar(solver::GenericSolver)::AbstractGrammar @@ -198,12 +194,11 @@ Get the symbol from the solver. """ function get_starting_symbol(solver::GenericSolver)::Symbol root = get_tree(solver) - rule = isfilled(root) ? get_rule(root) : findfirst(root.domain) + rule = isfilled(root) ? get_rule(root) : findfirst(root.domain) grammar = get_grammar(solver) return grammar.types[rule] end - """ function get_state(solver::GenericSolver)::SolverState @@ -213,7 +208,6 @@ function get_state(solver::GenericSolver)::SolverState return solver.state end - """ function get_max_depth(solver::GenericSolver)::SolverState @@ -223,7 +217,6 @@ function get_max_depth(solver::GenericSolver) return solver.max_depth end - """ function get_max_depth(solver::GenericSolver)::SolverState @@ -233,7 +226,6 @@ function get_max_size(solver::GenericSolver) return solver.max_size end - """ set_infeasible!(solver::GenericSolver) @@ -257,7 +249,6 @@ function isfeasible(solver::GenericSolver) return get_state(solver).isfeasible end - """ get_path(solver::GenericSolver, node::AbstractRuleNode) @@ -272,7 +263,8 @@ end Get the node at path `location`. """ -function HerbCore.get_node_at_location(solver::GenericSolver, location::Vector{Int})::AbstractRuleNode +function HerbCore.get_node_at_location( + solver::GenericSolver, location::Vector{Int})::AbstractRuleNode # dispatches the function on type `AbstractRuleNode` (defined in rulenode_operator.jl in HerbGrammar.jl) node = get_node_at_location(get_tree(solver), location) @assert !isnothing(node) "No node exists at location $location in the current state of the solver" @@ -290,23 +282,23 @@ function get_hole_at_location(solver::GenericSolver, location::Vector{Int})::Abs return hole end - """ notify_tree_manipulation(solver::GenericSolver, event_path::Vector{Int}) Notify subscribed constraints that a tree manipulation has occured at the `event_path` by scheduling them for propagation """ function notify_tree_manipulation(solver::GenericSolver, event_path::Vector{Int}) - if !isfeasible(solver) return end + if !isfeasible(solver) + return + end active_constraints = get_state(solver).active_constraints - for c ∈ active_constraints + for c in active_constraints if shouldschedule(solver, c, event_path) schedule!(solver, c) end end end - """ notify_new_node(solver::GenericSolver, event_path::Vector{Int}) @@ -315,13 +307,14 @@ Notify all constraints that a new node has appeared at the `event_path` by calli This does not notify the solver about nodes below the `event_path`. In that case, call [`notify_new_nodes`](@ref) instead. """ function notify_new_node(solver::GenericSolver, event_path::Vector{Int}) - if !isfeasible(solver) return end - for c ∈ get_grammar(solver).constraints + if !isfeasible(solver) + return + end + for c in get_grammar(solver).constraints on_new_node(solver, c, event_path) end end - """ notify_new_nodes(solver::GenericSolver, node::AbstractRuleNode, path::Vector{Int}) @@ -329,7 +322,7 @@ Notify all grammar constraints about the new `node` and its (grand)children """ function notify_new_nodes(solver::GenericSolver, node::AbstractRuleNode, path::Vector{Int}) notify_new_node(solver, path) - for (i, childnode) ∈ enumerate(get_children(node)) + for (i, childnode) in enumerate(get_children(node)) notify_new_nodes(solver, childnode, push!(copy(path), i)) end end diff --git a/src/solver/generic_solver/state.jl b/src/solver/generic_solver/state.jl index eb463c9..f032fc3 100644 --- a/src/solver/generic_solver/state.jl +++ b/src/solver/generic_solver/state.jl @@ -17,11 +17,12 @@ mutable struct SolverState isfeasible::Bool end -SolverState(tree::AbstractRuleNode) = SolverState(tree, Set{AbstractLocalConstraint}(), true) +function SolverState(tree::AbstractRuleNode) + SolverState(tree, Set{AbstractLocalConstraint}(), true) +end -function Base.copy(state::SolverState) +function Base.copy(state::SolverState) tree = deepcopy(state.tree) active_constraints = copy(state.active_constraints) # constraints are stateless, so the constraints can be shallow copied SolverState(tree, active_constraints, state.isfeasible) end - diff --git a/src/solver/generic_solver/treemanipulations.jl b/src/solver/generic_solver/treemanipulations.jl index c93eb17..f4bfd96 100644 --- a/src/solver/generic_solver/treemanipulations.jl +++ b/src/solver/generic_solver/treemanipulations.jl @@ -25,7 +25,7 @@ It is assumed the path points to a hole, otherwise an exception will be thrown. function remove!(solver::GenericSolver, path::Vector{Int}, rules::Vector{Int}) hole = get_hole_at_location(solver, path) domain_updated = false - for rule_index ∈ rules + for rule_index in rules if hole.domain[rule_index] domain_updated = true hole.domain[rule_index] = false @@ -47,7 +47,9 @@ It is assumed new_domain ⊆ domain. For example: [1, 0, 1, 0] ⊆ [1, 0, 1, 1] """ function remove_all_but!(solver::GenericSolver, path::Vector{Int}, new_domain::BitVector) hole = get_hole_at_location(solver, path) - if hole.domain == new_domain @warn "'remove_all_but' was called with trivial arguments" return end + if hole.domain == new_domain + @warn "'remove_all_but' was called with trivial arguments" return + end @assert is_subdomain(new_domain, hole.domain) "($new_domain) ⊈ ($(hole.domain)) The remaining rules are required to be a subdomain of the hole to remove from" hole.domain = new_domain simplify_hole!(solver, path) @@ -71,7 +73,7 @@ function remove_above!(solver::GenericSolver, path::Vector{Int}, rule_index::Int # The tree manipulation won't have any effect, ignore the tree manipulation return end - for r ∈ rule_index+1:length(hole.domain) + for r in (rule_index + 1):length(hole.domain) hole.domain[r] = false end simplify_hole!(solver, path) @@ -95,7 +97,7 @@ function remove_below!(solver::GenericSolver, path::Vector{Int}, rule_index::Int # The tree manipulation won't have any effect, ignore the tree manipulation return end - for r ∈ 1:rule_index-1 + for r in 1:(rule_index - 1) hole.domain[r] = false end simplify_hole!(solver, path) @@ -113,7 +115,8 @@ It is assumed rule_index ∈ hole.domain. !!! warning: If the `hole` is known to be in the current tree, the hole can be passed directly. The caller has to make sure that the hole instance is actually present at the provided `path`. """ -function remove_all_but!(solver::GenericSolver, path::Vector{Int}, rule_index::Int; hole::Union{Hole, Nothing}=nothing) +function remove_all_but!(solver::GenericSolver, path::Vector{Int}, + rule_index::Int; hole::Union{Hole, Nothing} = nothing) if isnothing(hole) hole = get_hole_at_location(solver, path) end @@ -121,7 +124,7 @@ function remove_all_but!(solver::GenericSolver, path::Vector{Int}, rule_index::I if isuniform(hole) # no new children appear underneath new_node = RuleNode(rule_index, get_children(hole)) - substitute!(solver, path, new_node, is_domain_increasing=false) + substitute!(solver, path, new_node, is_domain_increasing = false) else # reduce the domain of the non-uniform hole and let `simplify_hole!` take care of instantiating the children correctly # throw("WARNING: attempted to fill a non-uniform hole (untested behavior).") @@ -130,7 +133,7 @@ function remove_all_but!(solver::GenericSolver, path::Vector{Int}, rule_index::I # If this is also the case for a newly added constraint, make sure to add an `if isuniform(hole) end` check to your propagator. # Before you delete this error, make sure that the caller, typically a `propagate!` function, is actually working as intended. # If you are sure that filling in a non-uniform hole is fine, this error can safely be deleted." - for r ∈ 1:length(hole.domain) + for r in 1:length(hole.domain) hole.domain[r] = false end hole.domain[rule_index] = true @@ -138,7 +141,6 @@ function remove_all_but!(solver::GenericSolver, path::Vector{Int}, rule_index::I end end - """ substitute!(solver::GenericSolver, path::Vector{Int}, new_node::AbstractRuleNode; is_domain_increasing::Union{Nothing, Bool}=nothing) @@ -148,7 +150,8 @@ Domain increasing substitutions are substitutions that cannot be achieved by rep Example of an domain increasing event: `hole[{3, 4, 5}] -> hole[{1, 2}]`. Example of an domain decreasing event: `hole[{3, 4, 5}] -> rulenode(4, [hole[{1, 2}], rulenode(1)])`. """ -function substitute!(solver::GenericSolver, path::Vector{Int}, new_node::AbstractRuleNode; is_domain_increasing::Union{Nothing, Bool}=nothing) +function substitute!(solver::GenericSolver, path::Vector{Int}, new_node::AbstractRuleNode; + is_domain_increasing::Union{Nothing, Bool} = nothing) if isempty(path) #replace the root old_node = solver.state.tree @@ -156,19 +159,20 @@ function substitute!(solver::GenericSolver, path::Vector{Int}, new_node::Abstrac else #replace a node in the middle of the tree parent = get_tree(solver) - for i ∈ path[1:end-1] + for i in path[1:(end - 1)] parent = parent.children[i] end old_node = parent.children[path[end]] parent.children[path[end]] = new_node end - - if (get_tree_size(solver) > get_max_size(solver)) || (length(path)+depth(new_node) > get_max_depth(solver)) + + if (get_tree_size(solver) > get_max_size(solver)) || + (length(path) + depth(new_node) > get_max_depth(solver)) #if the tree is too large, mark it as infeasible set_infeasible!(solver) return end - + if isnothing(is_domain_increasing) #automatically decide if the event is domain increasing track!(solver, "substitute! checks is_domain_increasing") @@ -192,7 +196,6 @@ function substitute!(solver::GenericSolver, path::Vector{Int}, new_node::Abstrac end end - """ function remove_node!(solver::GenericSolver, path::Vector{Int}) @@ -205,10 +208,9 @@ function remove_node!(solver::GenericSolver, path::Vector{Int}) grammar = get_grammar(solver) type = grammar.types[get_rule(node)] domain = copy(grammar.domains[type]) #must be copied, otherwise we are mutating the grammar - substitute!(solver, path, Hole(domain), is_domain_increasing=true) + substitute!(solver, path, Hole(domain), is_domain_increasing = true) end - """ simplify_hole!(solver::GenericSolver, path::Vector{Int}) @@ -216,7 +218,9 @@ Takes a [Hole](@ref) and tries to simplify it to a [UniformHole](@ref) or [RuleN If the domain of the hole is empty, the state will be marked as infeasible """ function simplify_hole!(solver::GenericSolver, path::Vector{Int}) - if !isfeasible(solver) return end + if !isfeasible(solver) + return + end hole = get_hole_at_location(solver, path) grammar = get_grammar(solver) new_node = nothing @@ -241,8 +245,8 @@ function simplify_hole!(solver::GenericSolver, path::Vector{Int}) #the hole will be simplified and replaced with a `new_node` if !isnothing(new_node) - substitute!(solver, path, new_node, is_domain_increasing=false) - for i ∈ 1:length(new_node.children) + substitute!(solver, path, new_node, is_domain_increasing = false) + for i in 1:length(new_node.children) # try to simplify the new children child_path = push!(copy(path), i) if (new_node.children[i] isa AbstractHole) diff --git a/src/solver/solver.jl b/src/solver/solver.jl index 7d511c6..e1007d3 100644 --- a/src/solver/solver.jl +++ b/src/solver/solver.jl @@ -20,14 +20,15 @@ Each solver should implement at least: """ abstract type Solver end - """ fix_point!(solver::Solver) Propagate constraints in the current state until no further dedecutions can be made """ function fix_point!(solver::Solver) - if solver.fix_point_running return end + if solver.fix_point_running + return + end solver.fix_point_running = true while !isempty(solver.schedule) if !isfeasible(solver) @@ -36,13 +37,12 @@ function fix_point!(solver::Solver) empty!(solver.schedule) break end - constraint = dequeue!(solver.schedule) + constraint = dequeue!(solver.schedule) propagate!(solver, constraint) end solver.fix_point_running = false end - """ schedule(solver::GenericSolver, constraint::AbstractLocalConstraint) @@ -56,7 +56,6 @@ function schedule!(solver::Solver, constraint::AbstractLocalConstraint) end end - """ shouldschedule(solver::Solver, constraint::AbstractLocalConstraint, path::Vector{Int})::Bool @@ -65,7 +64,8 @@ Returns true if the `constraint` should be scheduled for propagation. Default behavior: return true iff the manipulation happened at or below the constraint path. """ -function shouldschedule(::Solver, constraint::AbstractLocalConstraint, path::Vector{Int})::Bool - return (length(path) >= length(constraint.path)) && (path[1:length(constraint.path)] == constraint.path) +function shouldschedule( + ::Solver, constraint::AbstractLocalConstraint, path::Vector{Int})::Bool + return (length(path) >= length(constraint.path)) && + (path[1:length(constraint.path)] == constraint.path) end - diff --git a/src/solver/solverstatistics.jl b/src/solver/solverstatistics.jl index 5857205..4ec110b 100644 --- a/src/solver/solverstatistics.jl +++ b/src/solver/solverstatistics.jl @@ -26,8 +26,8 @@ function Base.show(io::IO, statistics::SolverStatistics) print(io, "SolverStatistics: \n") if length(keys(statistics.dict)) > 0 max_key_length = maximum(length.(keys(statistics.dict))) - for key ∈ sort(collect(keys(statistics.dict))) #keys(statistics.dict) - spaces = "." ^ (max_key_length - length(key)) + for key in sort(collect(keys(statistics.dict))) #keys(statistics.dict) + spaces = "."^(max_key_length - length(key)) print(io, "$key $spaces $(statistics.dict[key])\n") end else diff --git a/src/solver/uniform_solver/state_hole.jl b/src/solver/uniform_solver/state_hole.jl index 3d40690..1e069fe 100644 --- a/src/solver/uniform_solver/state_hole.jl +++ b/src/solver/uniform_solver/state_hole.jl @@ -6,44 +6,39 @@ - `children`: The children of this hole in the expression tree. """ mutable struct StateHole <: AbstractUniformHole - domain::StateSparseSet - children::Vector{AbstractRuleNode} + domain::StateSparseSet + children::Vector{AbstractRuleNode} end - """ Converts a [`UniformHole`](@ref) to a [`StateHole`](@ref) """ function StateHole(sm::StateManager, hole::UniformHole) - sss_domain = StateSparseSet(sm, hole.domain) - children = [StateHole(sm, child) for child ∈ hole.children] - return StateHole(sss_domain, children) + sss_domain = StateSparseSet(sm, hole.domain) + children = [StateHole(sm, child) for child in hole.children] + return StateHole(sss_domain, children) end - """ Converts a [`RuleNode`](@ref) to a [`StateHole`](@ref) """ function StateHole(sm::StateManager, rulenode::RuleNode) - children = [StateHole(sm, child) for child ∈ rulenode.children] - return RuleNode(rulenode.ind, children) + children = [StateHole(sm, child) for child in rulenode.children] + return RuleNode(rulenode.ind, children) end - HerbCore.isuniform(::StateHole) = true - """ get_rule(hole::StateHole)::Int Assuming the hole has domain size 1, get the rule it is currently assigned to. """ function HerbCore.get_rule(hole::StateHole)::Int - @assert isfilled(hole) "$(hole) has not been filled yet, unable to get the rule" - return findfirst(hole.domain) + @assert isfilled(hole) "$(hole) has not been filled yet, unable to get the rule" + return findfirst(hole.domain) end - """ isfilled(hole::StateHole)::Bool @@ -51,58 +46,55 @@ Holes with domain size 1 are fixed to a rule. Returns whether the hole has domain size 1. (holes with an empty domain are not considered to be fixed) """ function HerbCore.isfilled(hole::StateHole)::Bool - return size(hole.domain) == 1 + return size(hole.domain) == 1 end - """ contains_hole(hole::StateHole)::Bool Returns true if the `hole` or any of its (grand)children are not filled. """ function HerbCore.contains_hole(hole::StateHole)::Bool - if !isfilled(hole) - return true - end - return any(contains_hole(c) for c ∈ hole.children) + if !isfilled(hole) + return true + end + return any(contains_hole(c) for c in hole.children) end - -function Base.show(io::IO, node::StateHole; separator=",", last_child::Bool=false) - print(io, "statehole[$(node.domain)]") - if !isempty(node.children) - print(io, "{") - for (i,c) in enumerate(node.children) - show(io, c, separator=separator, last_child=(i == length(node.children))) - end - print(io, "}") - elseif !last_child - print(io, separator) - end +function Base.show(io::IO, node::StateHole; separator = ",", last_child::Bool = false) + print(io, "statehole[$(node.domain)]") + if !isempty(node.children) + print(io, "{") + for (i, c) in enumerate(node.children) + show(io, c, separator = separator, last_child = (i == length(node.children))) + end + print(io, "}") + elseif !last_child + print(io, separator) + end end HerbCore.get_children(hole::StateHole) = hole.children - function Base.:(==)(A::StateHole, B::StateHole) - isfilled(A) && isfilled(B) && - (get_rule(A) == get_rule(B)) && - (length(A.children) == length(B.children)) && - all(isequal(a, b) for (a, b) in zip(A.children, B.children)) + isfilled(A) && isfilled(B) && + (get_rule(A) == get_rule(B)) && + (length(A.children) == length(B.children)) && + all(isequal(a, b) for (a, b) in zip(A.children, B.children)) end function Base.:(==)(A::RuleNode, B::StateHole) - isfilled(B) && - (get_rule(A) == get_rule(B)) && - (length(A.children) == length(B.children)) && - all(isequal(a, b) for (a, b) in zip(A.children, B.children)) + isfilled(B) && + (get_rule(A) == get_rule(B)) && + (length(A.children) == length(B.children)) && + all(isequal(a, b) for (a, b) in zip(A.children, B.children)) end function Base.:(==)(A::StateHole, B::RuleNode) - isfilled(A) && - (get_rule(A) == get_rule(B)) && - (length(A.children) == length(B.children)) && - all(isequal(a, b) for (a, b) in zip(A.children, B.children)) + isfilled(A) && + (get_rule(A) == get_rule(B)) && + (length(A.children) == length(B.children)) && + all(isequal(a, b) for (a, b) in zip(A.children, B.children)) end """ @@ -112,9 +104,9 @@ Converts a [`StateHole`])(@ref) to a [`RuleNode`]@(ref). The hole and its children are assumed to be filled. """ function freeze_state(hole::StateHole)::RuleNode - return RuleNode(get_rule(hole), [freeze_state(c) for c in hole.children]) + return RuleNode(get_rule(hole), [freeze_state(c) for c in hole.children]) end function freeze_state(node::RuleNode)::RuleNode - return RuleNode(node.ind, [freeze_state(c) for c in node.children]) + return RuleNode(node.ind, [freeze_state(c) for c in node.children]) end diff --git a/src/solver/uniform_solver/state_manager.jl b/src/solver/uniform_solver/state_manager.jl index 8e7ba83..8f5bf09 100644 --- a/src/solver/uniform_solver/state_manager.jl +++ b/src/solver/uniform_solver/state_manager.jl @@ -24,10 +24,9 @@ mutable struct StateInt end function StateInt(sm, val) - return StateInt(sm, val, sm.current_state_id-1) + return StateInt(sm, val, sm.current_state_id - 1) end - """ Get the value of the stateful integer """ @@ -35,7 +34,6 @@ function get_value(int::StateInt) return int.val end - """ Set the value of the integer to the given `val` """ @@ -46,7 +44,6 @@ function set_value!(int::StateInt, val::Int) end end - """ Increase the value of the integer by 1 """ @@ -55,7 +52,6 @@ function increment!(int::StateInt) int.val += 1 end - """ Decrease the value of the integer by 1 """ @@ -64,7 +60,6 @@ function decrement!(int::StateInt) int.val -= 1 end - """ Backup entry for the given [`StateInt`](@ref) """ @@ -73,7 +68,6 @@ struct StateIntBackup original_val::Int end - """ Should be called whenever the state of a `StateInt` is modified. Creates a `StateIntBackup` for the given `StateInt`. @@ -96,7 +90,6 @@ function backup!(int::StateInt) end end - """ Restores the `StateInt` stored in the `StateIntBackup` to its original value """ @@ -128,7 +121,6 @@ function StateManager() return StateManager(prior_backups, current_backups, current_state_id) end - """ Make a backup of the current state. Return to this state by calling `restore!`. """ @@ -138,7 +130,6 @@ function save_state!(sm::StateManager) sm.current_state_id += 1 end - """ Reverts all the backups since the last `save_state!`. """ diff --git a/src/solver/uniform_solver/state_sparse_set.jl b/src/solver/uniform_solver/state_sparse_set.jl index 1400d20..9de6096 100644 --- a/src/solver/uniform_solver/state_sparse_set.jl +++ b/src/solver/uniform_solver/state_sparse_set.jl @@ -34,13 +34,12 @@ function StateSparseSet(sm::StateManager, domain::BitVector) min = StateInt(sm, 1) max = StateInt(sm, n) set = StateSparseSet(values, indices, size, min, max, n) - for v ∈ findall(.!domain) + for v in findall(.!domain) remove!(set, v) end return set end - """ Pretty print the `StateSparseSet`. """ @@ -48,7 +47,7 @@ function Base.show(io::IO, set::StateSparseSet) print(io, "{") size = get_value(set.size) if size > 0 - for i ∈ 1:size-1 + for i in 1:(size - 1) print(io, set.values[i]) print(io, ", ") end @@ -105,7 +104,6 @@ function Base.getindex(set::StateSparseSet, val::Int) return val ∈ set end - """ Returns the maximum value in the set. This function name is used instead of `min` to allow code reuse for domains of type `BitVector` and `StateSparseSet`. @@ -132,24 +130,24 @@ function Base.in(val::Int, set::StateSparseSet) return set.indices[val] <= get_value(set.size) end - Base.eltype(::StateSparseSet) = Int - function Base.iterate(set::StateSparseSet) index = 1 - if index > get_value(set.size) return nothing end + if index > get_value(set.size) + return nothing + end return set.values[index], index end - function Base.iterate(set::StateSparseSet, index::Int) index += 1 - if index > get_value(set.size) return nothing end + if index > get_value(set.size) + return nothing + end return set.values[index], index end - """ remove!(set::StateSparseSet, val::Int) @@ -157,15 +155,14 @@ Removes value `val` from StateSparseSet `set`. Returns true if `val` was in `set """ function remove!(set::StateSparseSet, val::Int)::Bool if val ∉ set - return false; + return false end - _exchange_positions!(set, val, set.values[get_value(set.size)]); - decrement!(set.size); - _update_bounds_val_removed!(set, val); - return true; + _exchange_positions!(set, val, set.values[get_value(set.size)]) + decrement!(set.size) + _update_bounds_val_removed!(set, val) + return true end - """ remove_all_but!(set::StateSparseSet, val::Int)::Bool @@ -188,7 +185,6 @@ function remove_all_but!(set::StateSparseSet, val::Int)::Bool return true end - """ Remove all the values less than `val` from the `set` """ @@ -198,7 +194,7 @@ function remove_below!(set::StateSparseSet, val::Int)::Bool elseif get_value(set.max) < val Base.empty!(set) else - for v ∈ get_value(set.min):val-1 + for v in get_value(set.min):(val - 1) remove!(set, v) end end @@ -214,7 +210,7 @@ function remove_above!(set::StateSparseSet, val::Int)::Bool elseif get_value(set.min) > val Base.empty!(set) else - for v ∈ val+1:get_value(set.max) + for v in (val + 1):get_value(set.max) remove!(set, v) end end @@ -252,7 +248,7 @@ The maximum value of the set will be updated to the actual maximum of the set. function _update_max_val_removed!(set::StateSparseSet, val::Int) max = get_value(set.max) if !isempty(set) && max == val - for v ∈ max-1:-1:1 + for v in (max - 1):-1:1 if v ∈ set set_value!(set.max, v) return @@ -268,7 +264,7 @@ The minimum value of the set will be updated to the actual minimum of the set. function _update_min_val_removed!(set::StateSparseSet, val::Int) min = get_value(set.min) if !isempty(set) && min == val - for v ∈ min+1:set.n + for v in (min + 1):(set.n) if v ∈ set set_value!(set.min, v) return @@ -277,14 +273,13 @@ function _update_min_val_removed!(set::StateSparseSet, val::Int) end end - """ are_disjoint(set1::StateSparseSet, set2::StateSparseSet) Returns true if there is no overlap in values between `set1` and `set2` """ function are_disjoint(set1::StateSparseSet, set2::StateSparseSet) - for v ∈ set1 + for v in set1 if v ∈ set2 return false end diff --git a/src/solver/uniform_solver/state_stack.jl b/src/solver/uniform_solver/state_stack.jl index d54343c..ba8f535 100644 --- a/src/solver/uniform_solver/state_stack.jl +++ b/src/solver/uniform_solver/state_stack.jl @@ -12,7 +12,7 @@ end Create an empty StateStack supporting elements of type T """ -function StateStack{T}(sm::AbstractStateManager) where T +function StateStack{T}(sm::AbstractStateManager) where {T} return StateStack{T}(Vector{T}(), StateInt(sm, 0)) end @@ -21,7 +21,7 @@ end Create a StateStack for the provided `vec` """ -function StateStack{T}(sm::AbstractStateManager, vec::Vector{T}) where T +function StateStack{T}(sm::AbstractStateManager, vec::Vector{T}) where {T} return StateStack{T}(vec, StateInt(sm, length(vec))) end @@ -64,6 +64,6 @@ end Checks whether the `value` is in the `stack`. """ -function Base.in(stack::StateStack{T}, value::T)::Bool where T +function Base.in(stack::StateStack{T}, value::T)::Bool where {T} return value ∈ stack.vec[1:size(stack)] end diff --git a/src/solver/uniform_solver/uniform_solver.jl b/src/solver/uniform_solver/uniform_solver.jl index 64c0665..02a9570 100644 --- a/src/solver/uniform_solver/uniform_solver.jl +++ b/src/solver/uniform_solver/uniform_solver.jl @@ -15,11 +15,11 @@ mutable struct UniformSolver <: Solver statistics::Union{SolverStatistics, Nothing} end - """ UniformSolver(grammar::AbstractGrammar, fixed_shaped_tree::AbstractRuleNode) """ -function UniformSolver(grammar::AbstractGrammar, fixed_shaped_tree::AbstractRuleNode; with_statistics=false) +function UniformSolver(grammar::AbstractGrammar, + fixed_shaped_tree::AbstractRuleNode; with_statistics = false) @assert !contains_nonuniform_hole(fixed_shaped_tree) "$(fixed_shaped_tree) contains non-uniform holes" sm = StateManager() tree = StateHole(sm, fixed_shaped_tree) @@ -34,16 +34,15 @@ function UniformSolver(grammar::AbstractGrammar, fixed_shaped_tree::AbstractRule ::Bool => with_statistics ? SolverStatistics() : nothing ::Nothing => nothing end - solver = UniformSolver(grammar, sm, tree, path_to_node, node_to_path, isactive, canceledconstraints, true, schedule, fix_point_running, statistics) + solver = UniformSolver(grammar, sm, tree, path_to_node, node_to_path, isactive, + canceledconstraints, true, schedule, fix_point_running, statistics) notify_new_nodes(solver, tree, Vector{Int}()) fix_point!(solver) return solver end - get_name(::UniformSolver) = "UniformSolver" - """ notify_new_nodes(solver::UniformSolver, node::AbstractRuleNode, path::Vector{Int}) @@ -52,15 +51,14 @@ Notify all grammar constraints about the new `node` and its (grand)children function notify_new_nodes(solver::UniformSolver, node::AbstractRuleNode, path::Vector{Int}) solver.path_to_node[path] = node solver.node_to_path[node] = path - for (i, childnode) ∈ enumerate(get_children(node)) + for (i, childnode) in enumerate(get_children(node)) notify_new_nodes(solver, childnode, push!(copy(path), i)) end - for c ∈ get_grammar(solver).constraints + for c in get_grammar(solver).constraints on_new_node(solver, c, path) end end - """ get_path(solver::UniformSolver, node::AbstractRuleNode) @@ -70,7 +68,6 @@ function HerbCore.get_path(solver::UniformSolver, node::AbstractRuleNode)::Vecto return solver.node_to_path[node] end - """ get_node_at_location(solver::UniformSolver, path::Vector{Int}) @@ -80,7 +77,6 @@ function HerbCore.get_node_at_location(solver::UniformSolver, path::Vector{Int}) return solver.path_to_node[path] end - """ get_hole_at_location(solver::UniformSolver, path::Vector{Int}) @@ -92,7 +88,6 @@ function get_hole_at_location(solver::UniformSolver, path::Vector{Int}) return hole end - """ get_nodes(solver) @@ -102,7 +97,6 @@ function get_nodes(solver) return keys(solver.node_to_path) end - """ function get_grammar(solver::UniformSolver)::AbstractGrammar @@ -112,7 +106,6 @@ function get_grammar(solver::UniformSolver)::AbstractGrammar return solver.grammar end - """ function get_tree(solver::UniformSolver)::AbstractRuleNode @@ -122,7 +115,6 @@ function get_tree(solver::UniformSolver)::AbstractRuleNode return solver.tree end - """ deactivate!(solver::UniformSolver, constraint::AbstractLocalConstraint) @@ -146,7 +138,6 @@ function deactivate!(solver::UniformSolver, constraint::AbstractLocalConstraint) push!(solver.canceledconstraints, constraint) end - """ post!(solver::UniformSolver, constraint::AbstractLocalConstraint) @@ -154,7 +145,9 @@ Post a new local constraint. Converts the constraint to a state constraint and schedules it for propagation. """ function post!(solver::UniformSolver, constraint::AbstractLocalConstraint) - if !isfeasible(solver) return end + if !isfeasible(solver) + return + end # initial propagation of the new constraint temp = solver.fix_point_running solver.fix_point_running = true @@ -168,22 +161,23 @@ function post!(solver::UniformSolver, constraint::AbstractLocalConstraint) end #if the was not deactivated after initial propagation, it can be added to the list of constraints if (constraint ∈ keys(solver.isactive)) - @assert solver.isactive[constraint] == 0 "Attempted to post a constraint that is already active: $(constraint). Please verify that the grammar does not contain duplicate constraints." + @assert solver.isactive[constraint]==0 "Attempted to post a constraint that is already active: $(constraint). Please verify that the grammar does not contain duplicate constraints." else solver.isactive[constraint] = StateInt(solver.sm, 0) #initializing the state int as 0 will deactivate it on backtrack end set_value!(solver.isactive[constraint], 1) end - """ notify_tree_manipulation(solver::UniformSolver, event_path::Vector{Int}) Notify subscribed constraints that a tree manipulation has occured at the `event_path` by scheduling them for propagation """ function notify_tree_manipulation(solver::UniformSolver, event_path::Vector{Int}) - if !isfeasible(solver) return end - for (constraint, isactive) ∈ solver.isactive + if !isfeasible(solver) + return + end + for (constraint, isactive) in solver.isactive if get_value(isactive) == 1 if shouldschedule(solver, constraint, event_path) schedule!(solver, constraint) @@ -192,7 +186,6 @@ function notify_tree_manipulation(solver::UniformSolver, event_path::Vector{Int} end end - """ isfeasible(solver::UniformSolver) @@ -202,7 +195,6 @@ function isfeasible(solver::UniformSolver) return solver.isfeasible end - """ set_infeasible!(solver::Solver) @@ -212,7 +204,6 @@ function set_infeasible!(solver::UniformSolver) solver.isfeasible = false end - """ Save the current state of the solver, can restored using `restore!` """ @@ -222,7 +213,6 @@ function save_state!(solver::UniformSolver) save_state!(solver.sm) end - """ Restore state of the solver until the last `save_state!` """ @@ -231,4 +221,3 @@ function restore!(solver::UniformSolver) restore!(solver.sm) solver.isfeasible = true end - diff --git a/src/solver/uniform_solver/uniform_treemanipulations.jl b/src/solver/uniform_solver/uniform_treemanipulations.jl index ef840d1..060101b 100644 --- a/src/solver/uniform_solver/uniform_treemanipulations.jl +++ b/src/solver/uniform_solver/uniform_treemanipulations.jl @@ -26,7 +26,7 @@ function remove!(solver::UniformSolver, path::Vector{Int}, rules::Vector{Int}) #remove the rule_index from the state sparse set of the hole hole = get_hole_at_location(solver, path) domain_updated = false - for rule_index ∈ rules + for rule_index in rules if remove!(hole.domain, rule_index) domain_updated = true end diff --git a/src/varnode.jl b/src/varnode.jl index 87dbb98..7787203 100644 --- a/src/varnode.jl +++ b/src/varnode.jl @@ -16,7 +16,7 @@ struct VarNode <: AbstractRuleNode name::Symbol end -function Base.show(io::IO, node::VarNode; separator=",", last_child::Bool=true) +function Base.show(io::IO, node::VarNode; separator = ",", last_child::Bool = true) print(io, node.name) if !last_child print(io, separator) @@ -30,5 +30,6 @@ HerbCore.isuniform(::VarNode) = false Checks if an [`AbstractRuleNode`](@ref) tree contains a [`VarNode`](@ref) with the given `name`. """ -contains_varnode(rn::AbstractRuleNode, name::Symbol) = any(contains_varnode(c, name) for c ∈ rn.children) +contains_varnode(rn::AbstractRuleNode, name::Symbol) = any(contains_varnode(c, name) +for c in rn.children) contains_varnode(vn::VarNode, name::Symbol) = vn.name == name diff --git a/test/runtests.jl b/test/runtests.jl index 0bd7341..97c3114 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using HerbCore +using HerbCore using HerbConstraints using Test diff --git a/test/test_contains_subtree.jl b/test/test_contains_subtree.jl index 64beb19..0e04262 100644 --- a/test/test_contains_subtree.jl +++ b/test/test_contains_subtree.jl @@ -1,7 +1,6 @@ @testset verbose=false "ContainsSubtree" begin - function has_active_constraints(solver::UniformSolver)::Bool - for c ∈ keys(solver.isactive) + for c in keys(solver.isactive) if get_value(solver.isactive[c]) == 1 return true end @@ -9,12 +8,12 @@ return false end - @testset "check_tree$with_varnode" for with_varnode ∈ ["", " (with VarNode)"] + @testset "check_tree$with_varnode" for with_varnode in ["", " (with VarNode)"] contains_subtree = ContainsSubtree( RuleNode(3, [ - RuleNode(1), - isempty(with_varnode) ? RuleNode(2) : VarNode(:a) - ]) + RuleNode(1), + isempty(with_varnode) ? RuleNode(2) : VarNode(:a) + ]) ) tree_true = RuleNode(3, [ @@ -40,32 +39,34 @@ @testset "check_tree, 2 VarNodes" begin contains_subtree = ContainsSubtree( RuleNode(3, [ - VarNode(:a), - VarNode(:a) - ]) + VarNode(:a), + VarNode(:a) + ]) ) - tree_true = RuleNode(3, [ - RuleNode(3, [ - RuleNode(1), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(1), - RuleNode(2) - ]), - ]) + tree_true = RuleNode(3, + [ + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]) + ]) - tree_false = RuleNode(3, [ - RuleNode(3, [ - RuleNode(1), - RuleNode(2) - ]), - RuleNode(4, [ - RuleNode(1), - RuleNode(2) - ]), - ]) + tree_false = RuleNode(3, + [ + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]), + RuleNode(4, [ + RuleNode(1), + RuleNode(2) + ]) + ]) @test check_tree(contains_subtree, tree_true) == true @test check_tree(contains_subtree, tree_false) == false @@ -87,13 +88,15 @@ @testset "0 candidates" begin # 3{1, :a} is never contained in the tree - tree = UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(2), - RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) + tree = UniformHole(BitVector((0, 0, 1, 1)), + [ + RuleNode(2), + RuleNode(4, + [ + UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) ]) - ]) solver = UniformSolver(grammar, tree) @test !isfeasible(solver) @@ -102,13 +105,15 @@ @testset "1 candidate" begin # 3{1, :a} can only appear at the root - tree = UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(1), - RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) + tree = UniformHole(BitVector((0, 0, 1, 1)), + [ + RuleNode(1), + RuleNode(4, + [ + UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) ]) - ]) solver = UniformSolver(grammar, tree) tree = get_tree(solver) @@ -122,13 +127,15 @@ @testset "2 candidates" begin # 3{1, :a} can appear at path=[] and path=[2]. - tree = UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(1), - RuleNode(3, [ - UniformHole(BitVector((1, 1, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) + tree = UniformHole(BitVector((0, 0, 1, 1)), + [ + RuleNode(1), + RuleNode(3, + [ + UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) ]) - ]) #initial propagation: softfail, all holes remain unfilled solver = UniformSolver(grammar, tree) @@ -165,10 +172,11 @@ # the first hole can be filled with a 3 # filling the other two holes is ambiguous - tree = UniformHole(BitVector((0, 0, 1, 1)), [ - UniformHole(BitVector((1, 1, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) - ]) + tree = UniformHole(BitVector((0, 0, 1, 1)), + [ + UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) solver = UniformSolver(grammar, tree) tree = get_tree(solver) @@ -188,16 +196,15 @@ # - 4{4{1, 1}, 4{1, 1}} INVALID # no deductions can be made at this point. - tree = UniformHole(BitVector((0, 0, 1, 1)), [ - UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(1), - RuleNode(1) - ]) - RuleNode(4, [ - RuleNode(1), - RuleNode(1) - ]) - ]) + tree = UniformHole(BitVector((0, 0, 1, 1)), + [UniformHole(BitVector((0, 0, 1, 1)), [ + RuleNode(1), + RuleNode(1) + ]) + RuleNode(4, [ + RuleNode(1), + RuleNode(1) + ])]) solver = UniformSolver(grammar, tree) tree = get_tree(solver) @@ -215,45 +222,41 @@ "SoftFail large domain", BitVector((0, 0, 0, 1, 1, 1)), # domain_root BitVector((0, 0, 0, 1, 1, 1)), # domain_root_target - BitVector((1, 1, 1, 0, 0, 0)), # domain_leaf - BitVector((1, 1, 1, 0, 0, 0)), # domain_leaf_target + BitVector((1, 1, 1, 0, 0, 0)) # domain_leaf_target ), ( "SoftFail small domain", BitVector((0, 0, 0, 1, 1, 0)), # domain_root BitVector((0, 0, 0, 1, 1, 0)), # domain_root_target - BitVector((1, 1, 0, 0, 0, 0)), # domain_leaf - BitVector((1, 1, 0, 0, 0, 0)), # domain_leaf_target + BitVector((1, 1, 0, 0, 0, 0)) # domain_leaf_target ), ( "Deduction in Root", BitVector((0, 0, 0, 1, 0, 1)), # domain_root BitVector((0, 0, 0, 1, 0, 0)), # domain_root_target - BitVector((1, 1, 0, 0, 0, 0)), # domain_leaf - BitVector((1, 1, 0, 0, 0, 0)), # domain_leaf_target + BitVector((1, 1, 0, 0, 0, 0)) # domain_leaf_target ), ( "Deduction in Leaf", BitVector((0, 0, 0, 1, 1, 0)), # domain_root BitVector((0, 0, 0, 1, 1, 0)), # domain_root_target - BitVector((0, 1, 1, 0, 0, 0)), # domain_leaf - BitVector((0, 1, 0, 0, 0, 0)), # domain_leaf_target + BitVector((0, 1, 0, 0, 0, 0)) # domain_leaf_target ), ( "Deduction in Root and Leaf", BitVector((0, 0, 0, 1, 0, 1)), # domain_root BitVector((0, 0, 0, 1, 0, 0)), # domain_root_target - BitVector((0, 1, 1, 0, 0, 0)), # domain_leaf - BitVector((0, 1, 0, 0, 0, 0)), # domain_leaf_target + BitVector((0, 1, 0, 0, 0, 0)) # domain_leaf_target ) ] - @testset "$name" for (name, domain_root, domain_root_target, domain_leaf, domain_leaf_target) ∈ tests + @testset "$name" for ( + name, domain_root, domain_root_target, domain_leaf, domain_leaf_target) in tests grammar = @csgrammar begin S = 1 S = 2 @@ -262,12 +265,14 @@ S = 5, S S = 6, S end - + # must contain at least rule 4 or 5 in the root. # must contain at least rule 1 or 2 in the leaf. - addconstraint!(grammar, ContainsSubtree(DomainRuleNode(grammar, [4, 5], [ - DomainRuleNode(grammar, [1, 2]) - ]))) + addconstraint!(grammar, + ContainsSubtree(DomainRuleNode( + grammar, [4, 5], [ + DomainRuleNode(grammar, [1, 2]) + ]))) tree = UniformHole(domain_root, [ UniformHole(domain_leaf, []) @@ -275,7 +280,7 @@ solver = UniformSolver(grammar, tree) tree = get_tree(solver) - for rule ∈ 1:6 + for rule in 1:6 @test domain_root_target[rule] == tree.domain[rule] @test domain_leaf_target[rule] == tree.children[1].domain[rule] end @@ -291,7 +296,8 @@ addconstraint!(grammar, ContainsSubtree(DomainRuleNode(grammar, [1, 2]))) @test !isfeasible(UniformSolver(grammar, RuleNode(3))) - @test !isfeasible(UniformSolver(grammar, UniformHole(BitVector((0, 0, 1, 1)), []))) + @test !isfeasible(UniformSolver( + grammar, UniformHole(BitVector((0, 0, 1, 1)), []))) end end end diff --git a/test/test_domain_utils.jl b/test/test_domain_utils.jl index f8aa7fc..998e6fd 100644 --- a/test/test_domain_utils.jl +++ b/test/test_domain_utils.jl @@ -1,6 +1,5 @@ using HerbGrammar @testset verbose=false "Domain Utils" begin - @testset "is_subdomain (BitVector and StateSparseSet)" begin #The domain represents a set of rules. In this case the domain represents the set {1, 3, 4, 5, 8}. #is_subdomain checks if the two provided domains form a subset relation. @@ -16,65 +15,92 @@ using HerbGrammar @test is_subdomain(BitVector((1, 1, 1, 1, 1, 1, 1, 1)), domain) == false #(StateSparseSet, BitVector) - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((0, 0, 0, 0, 0, 0, 0, 0))), domain) == true - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((0, 0, 0, 1, 0, 0, 0, 0))), domain) == true - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((1, 0, 0, 1, 0, 0, 0, 0))), domain) == true - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((1, 0, 1, 1, 1, 0, 0, 1))), domain) == true - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((0, 1, 0, 0, 0, 0, 0, 0))), domain) == false - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((0, 1, 1, 0, 1, 0, 0, 1))), domain) == false - @test is_subdomain(HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((1, 1, 1, 1, 1, 1, 1, 1))), domain) == false + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((0, 0, 0, 0, 0, 0, 0, 0))), + domain) == true + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((0, 0, 0, 1, 0, 0, 0, 0))), + domain) == true + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((1, 0, 0, 1, 0, 0, 0, 0))), + domain) == true + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((1, 0, 1, 1, 1, 0, 0, 1))), + domain) == true + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((0, 1, 0, 0, 0, 0, 0, 0))), + domain) == false + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((0, 1, 1, 0, 1, 0, 0, 1))), + domain) == false + @test is_subdomain( + HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((1, 1, 1, 1, 1, 1, 1, 1))), + domain) == false end @testset "is_subdomain true (AbstractRuleNode)" begin #is_subdomain for rulenodes checks if a specific tree can be obtained by repeatedly filling in holes from the general_tree @test is_subdomain(RuleNode(1), Hole(BitVector((1, 1, 1)))) - @test is_subdomain(UniformHole(BitVector((1, 1, 0)), []), Hole(BitVector((1, 1, 1)))) - @test is_subdomain(UniformHole(BitVector((1, 1, 1)), []), Hole(BitVector((1, 1, 1)))) + @test is_subdomain( + UniformHole(BitVector((1, 1, 0)), []), Hole(BitVector((1, 1, 1)))) + @test is_subdomain( + UniformHole(BitVector((1, 1, 1)), []), Hole(BitVector((1, 1, 1)))) @test is_subdomain(Hole(BitVector((1, 1, 1))), Hole(BitVector((1, 1, 1)))) - specific_tree = RuleNode(3, [ - UniformHole(BitVector((1, 1, 0)), []), - RuleNode(3, [ + specific_tree = RuleNode(3, + [ + UniformHole(BitVector((1, 1, 0)), []), + RuleNode(3, [ + Hole(BitVector((1, 1, 1))), + RuleNode(1) + ]) + ]) + general_tree = UniformHole( + BitVector((0, 1, 1)), [ Hole(BitVector((1, 1, 1))), - RuleNode(1) + Hole(BitVector((1, 0, 1))) ]) - ]) - general_tree = UniformHole(BitVector((0, 1, 1)), [ - Hole(BitVector((1, 1, 1))), - Hole(BitVector((1, 0, 1))) - ]) @test is_subdomain(specific_tree, general_tree) end @testset "is_subdomain false (AbstractRuleNode)" begin @test is_subdomain(RuleNode(1), Hole(BitVector((0, 1, 1)))) == false - @test is_subdomain(UniformHole(BitVector((1, 1, 0)), []), Hole(BitVector((0, 1, 1)))) == false - @test is_subdomain(UniformHole(BitVector((1, 1, 1)), []), Hole(BitVector((0, 1, 1)))) == false + @test is_subdomain( + UniformHole(BitVector((1, 1, 0)), []), Hole(BitVector((0, 1, 1)))) == false + @test is_subdomain( + UniformHole(BitVector((1, 1, 1)), []), Hole(BitVector((0, 1, 1)))) == false @test is_subdomain(Hole(BitVector((1, 1, 1))), Hole(BitVector((0, 1, 1)))) == false - specific_tree = RuleNode(3, [ - UniformHole(BitVector((1, 1, 0)), []), - RuleNode(2, [ # The specific_tree has a RuleNode(2) at the second child + specific_tree = RuleNode(3, + [ + UniformHole(BitVector((1, 1, 0)), []), + RuleNode(2, [ # The specific_tree has a RuleNode(2) at the second child + Hole(BitVector((1, 1, 1))), + RuleNode(1) + ]) + ]) + general_tree = UniformHole( + BitVector((0, 1, 1)), [ Hole(BitVector((1, 1, 1))), - RuleNode(1) + Hole(BitVector((1, 0, 1))) # RuleNode(2) is not part of this domain ]) - ]) - general_tree = UniformHole(BitVector((0, 1, 1)), [ - Hole(BitVector((1, 1, 1))), - Hole(BitVector((1, 0, 1))) # RuleNode(2) is not part of this domain - ]) @test is_subdomain(specific_tree, general_tree) == false end @testset "is_subdomain false (AbstractRuleNode, no holes)" begin #the specific_tree is larger than the general_tree - specific_tree = RuleNode(8, [ - RuleNode(5) - RuleNode(7, [ - RuleNode(4), - RuleNode(5) - ]) - ]) + specific_tree = RuleNode(8, [RuleNode(5) + RuleNode(7, [ + RuleNode(4), + RuleNode(5) + ])]) general_tree = RuleNode(9) @test is_subdomain(specific_tree, general_tree) == false end @@ -124,11 +150,14 @@ using HerbGrammar @testset "get_intersection" begin #(BitVector, BitVector) - @test get_intersection(BitVector((1, 1, 1, 1)), BitVector((1, 1, 1, 1))) == [1, 2, 3, 4] - @test get_intersection(BitVector((1, 0, 0, 0)), BitVector((0, 1, 1, 1))) == Vector{Int}() + @test get_intersection(BitVector((1, 1, 1, 1)), BitVector((1, 1, 1, 1))) == + [1, 2, 3, 4] + @test get_intersection(BitVector((1, 0, 0, 0)), BitVector((0, 1, 1, 1))) == + Vector{Int}() @test get_intersection(BitVector((1, 1, 1, 0)), BitVector((0, 0, 1, 1))) == [3] @test get_intersection(BitVector((1, 1, 1, 1)), BitVector((0, 0, 0, 1))) == [4] - @test get_intersection(BitVector((1, 1, 1, 1)), BitVector((0, 0, 0, 0))) == Vector{Int}() + @test get_intersection(BitVector((1, 1, 1, 1)), BitVector((0, 0, 0, 0))) == + Vector{Int}() #(BitVector, StateSparseSet). same cases, but now one of the domains is implemented with a StateSparseSet sss = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), 4) diff --git a/test/test_forbidden.jl b/test/test_forbidden.jl index 62306e7..c0507d8 100644 --- a/test/test_forbidden.jl +++ b/test/test_forbidden.jl @@ -21,16 +21,17 @@ RuleNode(2), RuleNode(2) ]) - tree_large_true = RuleNode(3, [ - RuleNode(4, [ - RuleNode(2), - RuleNode(3, [ + tree_large_true = RuleNode(3, + [ + RuleNode(4, [ RuleNode(2), - RuleNode(2) - ]) - ]), - RuleNode(2) - ]) + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) + ]), + RuleNode(2) + ]) @test check_tree(forbidden, tree11) == false @test check_tree(forbidden, tree12) == true @test check_tree(forbidden, tree21) == true @@ -43,19 +44,21 @@ RuleNode(2), RuleNode(2) ]) - tree_large_false = RuleNode(3, [ - RuleNode(4, [ - RuleNode(3, [ - RuleNode(2), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - RuleNode(2) - ]) - ]), - RuleNode(2) - ]) + tree_large_false = RuleNode(3, + [ + RuleNode(4, + [ + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) + ]), + RuleNode(2) + ]) @test check_tree(forbidden, tree22) == false @test check_tree(forbidden, tree_large_false) == false end diff --git a/test/test_forbidden_sequence.jl b/test/test_forbidden_sequence.jl index b77ca24..7dc20e0 100644 --- a/test/test_forbidden_sequence.jl +++ b/test/test_forbidden_sequence.jl @@ -4,39 +4,39 @@ # holes can be represented by tuples of indices if length(sequence) == 1 if sequence[1] isa Tuple - domain = BitVector((r ∈ sequence[1] for r ∈ 1:9)) + domain = BitVector((r ∈ sequence[1] for r in 1:9)) return Hole(domain) end return RuleNode(sequence[1]) end children = [dummy_tree(sequence[2:end])] if sequence[1] isa Tuple - domain = BitVector((r ∈ sequence[1] for r ∈ 1:9)) + domain = BitVector((r ∈ sequence[1] for r in 1:9)) return UniformHole(domain, children) end return RuleNode(sequence[1], children) end - + function dummy_solver(sequence, constraint)::Solver grammar = @csgrammar begin S = (S, 1) | (S, 2) | (S, 3) | (S, 4) | (S, 5) | (S, 6) | (S, 7) | (S, 8) S = 9 end # only 1 grammar is ever instantiated (at compile time), so we need to clear the grammar - empty!(grammar.constraints) + empty!(grammar.constraints) addconstraint!(grammar, constraint) return GenericSolver(grammar, dummy_tree(sequence)) end - + function get_sequence(solver, n) #converts a tree into a sequence of Int (representing a rule) and Tuple{Int} (representing a domain of rules) sequence = [] node = get_tree(solver) - for _ ∈ 1:n + for _ in 1:n if isfilled(node) push!(sequence, get_rule(node)) else - push!(sequence, Tuple(rule for rule ∈ 1:9 if node.domain[rule])) + push!(sequence, Tuple(rule for rule in 1:9 if node.domain[rule])) end if !isempty(get_children(node)) node = get_children(node)[1] @@ -44,11 +44,11 @@ end return sequence end - + function test_propagation( - constraint::ForbiddenSequence, - sequence_before_propagation, - sequence_after_propagation + constraint::ForbiddenSequence, + sequence_before_propagation, + sequence_after_propagation ) # An "Int" in the sequence represents a rule (RuleNode) # A "Tuple" in the sequence represents a domain of rules (UniformHole) @@ -57,10 +57,10 @@ expected = sequence_after_propagation @test actual == expected end - + function test_infeasible( - constraint::ForbiddenSequence, - sequence_before_propagation + constraint::ForbiddenSequence, + sequence_before_propagation ) solver = dummy_solver(sequence_before_propagation, constraint) @test isfeasible(solver) == false @@ -88,7 +88,7 @@ tree4 = dummy_tree([1, 2, 1, 2, 3]) tree5 = dummy_tree([3, 2, 1, 1, 2, 3]) tree6 = dummy_tree([1, 1, 2, 2, 3, 3]) - + @test check_tree(constraint, tree1) == false @test check_tree(constraint, tree2) == false @test check_tree(constraint, tree3) == false @@ -98,17 +98,17 @@ end @testset "Valid trees (ignore_if)" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5, 6]) + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5, 6]) tree1 = dummy_tree([1, 2, 5, 3]) tree2 = dummy_tree([5, 1, 5, 2, 5, 3, 1]) - + @test check_tree(constraint, tree1) == true @test check_tree(constraint, tree2) == true end @testset "Invalid trees (ignore_if)" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5, 6]) + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5, 6]) tree1 = dummy_tree([1, 2, 3]) tree2 = dummy_tree([5, 1, 2, 3]) @@ -117,7 +117,7 @@ tree5 = dummy_tree([1, 2, 5, 1, 2, 3]) tree6 = dummy_tree([1, 2, 3, 5, 3]) tree7 = dummy_tree([1, 5, 1, 2, 3]) - + @test check_tree(constraint, tree1) == false @test check_tree(constraint, tree2) == false @test check_tree(constraint, tree3) == false @@ -131,22 +131,22 @@ @testset "propagation" begin @testset "infeasible" begin constraint = ForbiddenSequence([1, 2, 3]) - + test_infeasible( constraint, [1, 2, 3] ) - + test_infeasible( constraint, [1, 2, (1, 2, 3), 3] ) - + test_infeasible( constraint, [1, 2, (1, 2, 3), (1, 2, 3), 3] ) - + test_infeasible( constraint, [1, 2, 3, (1, 2, 3), (1, 2, 3), 3] @@ -177,7 +177,7 @@ [1, (1, 2, 3), 3], [1, (1, 3), 3] ) - + test_propagation( constraint, [1, 2, (1, 2, 3)], @@ -208,8 +208,8 @@ end @testset "infeasible (with ignore_if)" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5]) - + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5]) + test_infeasible( constraint, [1, 2, 3] @@ -219,7 +219,7 @@ constraint, [(1, 2, 3, 4), 1, 2, 3, (1, 2, 3, 4)] ) - + test_infeasible( constraint, [1, 2, 3, 1, 2, 4, 3] @@ -242,7 +242,7 @@ end @testset "0 deductions (with ignore_if)" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5]) + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5]) test_propagation( constraint, @@ -264,7 +264,7 @@ end @testset "1 deduction (with ignore_if)" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5]) + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5]) test_propagation( constraint, @@ -286,7 +286,7 @@ end @testset "ignore_if" begin - constraint = ForbiddenSequence([1, 2, 3], ignore_if=[4, 5, 6, 7, 8]) + constraint = ForbiddenSequence([1, 2, 3], ignore_if = [4, 5, 6, 7, 8]) test_propagation( constraint, diff --git a/test/test_lessthanorequal.jl b/test/test_lessthanorequal.jl index c4b9ab6..7cb5d25 100644 --- a/test/test_lessthanorequal.jl +++ b/test/test_lessthanorequal.jl @@ -1,7 +1,6 @@ using HerbCore, HerbGrammar @testset verbose=false "LessThanOrEqual" begin - function create_dummy_solver(leftnode::AbstractRuleNode, rightnode::AbstractRuleNode) grammar = @csgrammar begin Number = x | 1 @@ -12,7 +11,7 @@ using HerbCore, HerbGrammar tree = RuleNode(4, [ leftnode, RuleNode(3, [ - RuleNode(2), + RuleNode(2), rightnode ]) ]) @@ -30,7 +29,8 @@ using HerbCore, HerbGrammar right = RuleNode(1) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualHardFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualHardFail end @testset "Success, no holes, ==" begin @@ -38,7 +38,8 @@ using HerbCore, HerbGrammar right = RuleNode(1) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess end @testset "Success, no holes, <" begin @@ -46,7 +47,8 @@ using HerbCore, HerbGrammar right = RuleNode(2) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess end @testset "Success, 1 hole (left)" begin @@ -54,7 +56,8 @@ using HerbCore, HerbGrammar right = RuleNode(2) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess end @testset "Success, 1 hole (right), expands" begin @@ -62,7 +65,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((1, 0, 1, 0))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess end @testset "Success, 2 holes" begin @@ -70,7 +74,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((0, 0, 1, 1))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess end @testset "HardFail, 1 hole (left)" begin @@ -78,7 +83,8 @@ using HerbCore, HerbGrammar right = RuleNode(2) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualHardFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualHardFail end @testset "HardFail, 1 hole (right)" begin @@ -86,7 +92,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((1, 1, 0, 0))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualHardFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualHardFail end @testset "HardFail, 2 holes" begin @@ -94,7 +101,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((1, 1, 0, 0))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualHardFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualHardFail end @testset "SoftFail, 2 holes" begin @@ -102,7 +110,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((1, 0, 1, 0))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail end @testset "SoftFail, 2 equal uniform holes" begin @@ -110,7 +119,8 @@ using HerbCore, HerbGrammar right = Hole(BitVector((1, 1, 0, 0))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail end @testset "left hole softfails" begin @@ -118,7 +128,8 @@ using HerbCore, HerbGrammar right = RuleNode(3, [RuleNode(2), RuleNode(2)]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail end @testset "left hole gets filled once, two holes remain" begin @@ -128,7 +139,8 @@ using HerbCore, HerbGrammar # left = 3{hole[1, 2], hole[1, 2, 3, 4]} # this is a softfail, because [left <= right] and [left > right] are still possible - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 2 end @@ -139,7 +151,8 @@ using HerbCore, HerbGrammar # left = 3{1, hole[1, 2]} # this is a success, because [left <= right] for all possible assignments - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 1 end @@ -149,7 +162,8 @@ using HerbCore, HerbGrammar solver, left, right = create_dummy_solver(left, right) # left = 3{1, 1} - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 0 end @@ -159,7 +173,8 @@ using HerbCore, HerbGrammar solver, left, right = create_dummy_solver(left, right) # right = hole[3, 4]{hole[1, 2, 3, 4], hole[1, 2, 3, 4]} - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 3 end @@ -169,27 +184,30 @@ using HerbCore, HerbGrammar solver, left, right = create_dummy_solver(left, right) # right = 4{hole[2, 3, 4], hole[1, 2, 3, 4]} - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 2 end @testset "right hole expands to 4 holes" begin - left = RuleNode(4, [ - RuleNode(4, [ + left = RuleNode(4, + [ RuleNode(4, [ + RuleNode(4, [ RuleNode(2), RuleNode(2) - ]), - ]), - RuleNode(4, [ - RuleNode(2), - RuleNode(2) - ]), - ]) + ]) + ]), + RuleNode(4, [ + RuleNode(2), + RuleNode(2) + ]) + ]) right = Hole(BitVector((0, 0, 1, 1))) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 4 end @@ -197,42 +215,42 @@ using HerbCore, HerbGrammar # 1st comparison: {3, 4} <= 4 #guard1 # 2nd comparison: {1, 2} <= 3 #success # 3rd comparison: {1, 2} <= 4 #success - left = UniformHole(BitVector((0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0))), - Hole(BitVector((1, 1, 0, 0))) - ]) + left = UniformHole(BitVector((0, 0, 1, 1)), + [ + Hole(BitVector((1, 1, 0, 0))), + Hole(BitVector((1, 1, 0, 0))) + ]) right = RuleNode(4, [ - RuleNode(3, [ - RuleNode(2) - RuleNode(2) - ]), + RuleNode(3, [RuleNode(2) + RuleNode(2)]), RuleNode(4) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 3 end - + @testset "1 guard deduction, (node, hole)" begin # 1st comparison: {3, 4} <= 4 #guard1 # 2nd comparison: 2 <= 2 #success # 3rd comparison: 3 > {1, 2} #hardfail # the hardfail on the tiebreak means that the possibility of equality on guard must be eliminated - left = UniformHole(BitVector((0, 0, 1, 1)), [ #this hole should be set to 3 - RuleNode(2), - RuleNode(3, [ - RuleNode(2) - RuleNode(2) - ]), - ]) + left = UniformHole( + BitVector((0, 0, 1, 1)), [ #this hole should be set to 3 + RuleNode(2), + RuleNode(3, [RuleNode(2) + RuleNode(2)]) + ]) right = RuleNode(4, [ RuleNode(2), Hole(BitVector((1, 1, 0, 0))) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 1 end @@ -241,20 +259,20 @@ using HerbCore, HerbGrammar # 2nd comparison: 2 <= 2 #success # 3rd comparison: {3, 4} > 2 #hardfail # the hardfail on the tiebreak means that the possibility of equality on guard must be eliminated - left = UniformHole(BitVector((0, 0, 1, 1)), [ #this hole should be set to 3 - RuleNode(2), - UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(2) - RuleNode(2) - ]), - ]) + left = UniformHole(BitVector((0, 0, 1, 1)), + [ #this hole should be set to 3 + RuleNode(2), + UniformHole(BitVector((0, 0, 1, 1)), [RuleNode(2) + RuleNode(2)]) + ]) right = RuleNode(4, [ RuleNode(2), RuleNode(2) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 1 end @@ -263,20 +281,20 @@ using HerbCore, HerbGrammar # 2nd comparison: 2 <= 2 #success # 3rd comparison: {3, 4} > {1, 2} #hardfail # the hardfail on the tiebreak means that the possibility of equality on guard must be eliminated - left = UniformHole(BitVector((0, 0, 1, 1)), [ #this hole should be set to 3 - RuleNode(2), - UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(2) - RuleNode(2) - ]), - ]) + left = UniformHole(BitVector((0, 0, 1, 1)), + [ #this hole should be set to 3 + RuleNode(2), + UniformHole(BitVector((0, 0, 1, 1)), [RuleNode(2) + RuleNode(2)]) + ]) right = RuleNode(4, [ RuleNode(2), Hole(BitVector((1, 1, 0, 0))) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 2 end @@ -284,17 +302,19 @@ using HerbCore, HerbGrammar # 1st comparison: {3, 4} <= 4 #guard1 # 2nd comparison: 2 <= 2 #success # 3rd comparison: {1, 4} <= {2, 3} #softfails because of the guard - left = UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(2), - Hole(BitVector((1, 0, 0, 1))) - ]) + left = UniformHole( + BitVector((0, 0, 1, 1)), [ + RuleNode(2), + Hole(BitVector((1, 0, 0, 1))) + ]) right = RuleNode(4, [ RuleNode(2), Hole(BitVector((0, 1, 1, 0))) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 3 end @@ -302,17 +322,19 @@ using HerbCore, HerbGrammar # 1st comparison: {3, 4} <= 4 #guard1 # 2nd comparison: {1, 2} <= 2 #guard2 # 3rd comparison: {1, 2} <= 2 #success - left = UniformHole(BitVector((0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0))), - Hole(BitVector((1, 1, 0, 0))) - ]) + left = UniformHole(BitVector((0, 0, 1, 1)), + [ + Hole(BitVector((1, 1, 0, 0))), + Hole(BitVector((1, 1, 0, 0))) + ]) right = RuleNode(4, [ RuleNode(2), RuleNode(2) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test number_of_holes(get_tree(solver)) == 3 end @@ -320,17 +342,19 @@ using HerbCore, HerbGrammar # 1st comparison: {3, 4} <= 4 #guard1 # 2nd comparison: {1, 2} <= 2 #guard2 # 3rd comparison: {1, 2} ?? 1 #softfails - left = UniformHole(BitVector((0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0))), - Hole(BitVector((1, 1, 0, 0))) - ]) + left = UniformHole(BitVector((0, 0, 1, 1)), + [ + Hole(BitVector((1, 1, 0, 0))), + Hole(BitVector((1, 1, 0, 0))) + ]) right = RuleNode(4, [ RuleNode(2), RuleNode(1) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 3 end @@ -341,17 +365,19 @@ using HerbCore, HerbGrammar # Since we have 2 guards, we cannot made a deduction and thus this is a softfail. # Either guard1 must become 3 # Or guard2 must become 1 - left = UniformHole(BitVector((0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0))), - RuleNode(2) - ]) + left = UniformHole( + BitVector((0, 0, 1, 1)), [ + Hole(BitVector((1, 1, 0, 0))), + RuleNode(2) + ]) right = RuleNode(4, [ RuleNode(2), RuleNode(1) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSoftFail + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSoftFail @test number_of_holes(get_tree(solver)) == 2 end @@ -372,7 +398,8 @@ using HerbCore, HerbGrammar solver = GenericSolver(grammar, :Int) new_state!(solver, tree) - @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa HerbConstraints.LessThanOrEqualSuccess + @test HerbConstraints.make_less_than_or_equal!(solver, left, right) isa + HerbConstraints.LessThanOrEqualSuccess @test contains_nonuniform_hole(get_tree(solver)) == true @test number_of_holes(get_tree(solver)) == 1 end diff --git a/test/test_makeequal.jl b/test/test_makeequal.jl index c0eef39..032a283 100644 --- a/test/test_makeequal.jl +++ b/test/test_makeequal.jl @@ -1,7 +1,6 @@ using HerbCore, HerbGrammar @testset verbose=false "MakeEqual (UniformSolver)" begin - function create_dummy_solver(leftnode::AbstractRuleNode, rightnode::AbstractRuleNode) grammar = @csgrammar begin Number = x | 1 @@ -12,7 +11,7 @@ using HerbCore, HerbGrammar uniform_tree = RuleNode(4, [ leftnode, RuleNode(3, [ - RuleNode(2), + RuleNode(2), rightnode ]) ]) @@ -27,22 +26,25 @@ using HerbCore, HerbGrammar right = RuleNode(4, [RuleNode(1), RuleNode(2)]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_equal!(solver, left, right) isa HerbConstraints.MakeEqualSuccess + @test HerbConstraints.make_equal!(solver, left, right) isa + HerbConstraints.MakeEqualSuccess @test left == right end @testset "MakeEqualSuccess, with holes" begin left = RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []), RuleNode(2) ]) - right = UniformHole(BitVector((0, 0, 1, 1)), [ - RuleNode(1), - UniformHole(BitVector((1, 1, 0, 0)), [])] + right = UniformHole(BitVector((0, 0, 1, 1)), + [ + RuleNode(1), + UniformHole(BitVector((1, 1, 0, 0)), [])] ) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_equal!(solver, left, right) isa HerbConstraints.MakeEqualSuccess + @test HerbConstraints.make_equal!(solver, left, right) isa + HerbConstraints.MakeEqualSuccess @test left == RuleNode(4, [RuleNode(1), RuleNode(2)]) @test left == right end @@ -52,139 +54,153 @@ using HerbCore, HerbGrammar right = RuleNode(4, [RuleNode(1), RuleNode(1)]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_equal!(solver, left, right) isa HerbConstraints.MakeEqualHardFail + @test HerbConstraints.make_equal!(solver, left, right) isa + HerbConstraints.MakeEqualHardFail @test left != right end @testset "MakeEqualHardFail, with holes" begin left = RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []), RuleNode(2) ]) right = RuleNode(4, [ - RuleNode(1), + RuleNode(1), RuleNode(1) ]) solver, left, right = create_dummy_solver(left, right) - @test HerbConstraints.make_equal!(solver, left, right) isa HerbConstraints.MakeEqualHardFail + @test HerbConstraints.make_equal!(solver, left, right) isa + HerbConstraints.MakeEqualHardFail @test left != right end @testset "MakeEqualSuccess, 1 VarNode" begin node = RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []), RuleNode(1) ]) varnode = RuleNode(4, [ - VarNode(:a), + VarNode(:a), RuleNode(1) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, node, varnode) isa HerbConstraints.MakeEqualSuccess + @test HerbConstraints.make_equal!(solver, node, varnode) isa + HerbConstraints.MakeEqualSuccess end @testset "MakeEqualSuccess, 2 VarNodes" begin node = RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []), RuleNode(1) ]) varnode = RuleNode(4, [ - VarNode(:a), + VarNode(:a), VarNode(:a) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, node, varnode) isa HerbConstraints.MakeEqualSuccess + @test HerbConstraints.make_equal!(solver, node, varnode) isa + HerbConstraints.MakeEqualSuccess @test node == RuleNode(4, [RuleNode(1), RuleNode(1)]) end @testset "MakeEqualSoftFail, 2 VarNodes" begin - node = RuleNode(4, [ - UniformHole(BitVector((1, 1, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) - ]) + node = RuleNode(4, + [ + UniformHole(BitVector((1, 1, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) varnode = RuleNode(4, [ - VarNode(:a), + VarNode(:a), VarNode(:a) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, node, varnode) isa HerbConstraints.MakeEqualSoftFail + @test HerbConstraints.make_equal!(solver, node, varnode) isa + HerbConstraints.MakeEqualSoftFail end @testset "MakeEqualSuccess, 1 VarNode and a hole" begin - node = RuleNode(4, [ - UniformHole(BitVector((1, 0, 0, 0)), []), - UniformHole(BitVector((1, 1, 0, 0)), []) - ]) + node = RuleNode(4, + [ + UniformHole(BitVector((1, 0, 0, 0)), []), + UniformHole(BitVector((1, 1, 0, 0)), []) + ]) varnode = RuleNode(4, [ - VarNode(:a), + VarNode(:a), RuleNode(1) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, node, varnode) isa HerbConstraints.MakeEqualSuccess + @test HerbConstraints.make_equal!(solver, node, varnode) isa + HerbConstraints.MakeEqualSuccess @test node == RuleNode(4, [RuleNode(1), RuleNode(1)]) end @testset "MakeEqualSuccess, 1 RuleNode and a DomainRuleNode" begin node = RuleNode(4, [ - RuleNode(1), + RuleNode(1), RuleNode(2) ]) domainrulenode = DomainRuleNode(BitVector([0, 0, 1, 1]), [ - RuleNode(1), + RuleNode(1), RuleNode(2) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - - @test HerbConstraints.make_equal!(solver, node, domainrulenode) isa HerbConstraints.MakeEqualSuccess + + @test HerbConstraints.make_equal!(solver, node, domainrulenode) isa + HerbConstraints.MakeEqualSuccess @test node == RuleNode(4, [RuleNode(1), RuleNode(2)]) end @testset "MakeEqualHardFail, 1 RuleNode and a DomainRuleNode" begin node = RuleNode(4, [ - RuleNode(1), + RuleNode(1), RuleNode(2) ]) domainrulenode = DomainRuleNode(BitVector([0, 1, 0, 0]), [ - RuleNode(1), + RuleNode(1), RuleNode(1) ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - - @test HerbConstraints.make_equal!(solver, node, domainrulenode) isa HerbConstraints.MakeEqualHardFail + + @test HerbConstraints.make_equal!(solver, node, domainrulenode) isa + HerbConstraints.MakeEqualHardFail @test node != domainrulenode end @testset "MakeEqualHardFail, 1 AbstractHole and a DomainRuleNode" begin hole = UniformHole(BitVector([1, 0, 0, 0]), []) domainrulenode = DomainRuleNode(BitVector([0, 1, 0, 0]), [ - RuleNode(1), + RuleNode(1), RuleNode(1) ]) solver, hole, _ = create_dummy_solver(hole, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, hole, domainrulenode) isa HerbConstraints.MakeEqualHardFail + @test HerbConstraints.make_equal!(solver, hole, domainrulenode) isa + HerbConstraints.MakeEqualHardFail @test hole != domainrulenode end @testset "MakeEqualSoftFail, DomainRuleNode's with VarNodes" begin - node = RuleNode(4, [ - UniformHole(BitVector([1, 1, 0, 0]), []), - UniformHole(BitVector([1, 1, 0, 0]), []) - ]) - vardomainrulenode = DomainRuleNode(BitVector([0, 0, 0, 1]), [ - VarNode(:a), - VarNode(:a) - ]) + node = RuleNode(4, + [ + UniformHole(BitVector([1, 1, 0, 0]), []), + UniformHole(BitVector([1, 1, 0, 0]), []) + ]) + vardomainrulenode = DomainRuleNode( + BitVector([0, 0, 0, 1]), [ + VarNode(:a), + VarNode(:a) + ]) solver, node, _ = create_dummy_solver(node, RuleNode(1)) - @test HerbConstraints.make_equal!(solver, node, vardomainrulenode) isa HerbConstraints.MakeEqualSoftFail + @test HerbConstraints.make_equal!(solver, node, vardomainrulenode) isa + HerbConstraints.MakeEqualSoftFail @test node != vardomainrulenode end end diff --git a/test/test_ordered.jl b/test/test_ordered.jl index fe56d5a..7590242 100644 --- a/test/test_ordered.jl +++ b/test/test_ordered.jl @@ -1,9 +1,9 @@ @testset verbose=false "Ordered" begin @testset "check_tree true, length(order)=2" begin ordered = Ordered(RuleNode(4, [ - VarNode(:a), - VarNode(:b) - ]), [:a, :b]) + VarNode(:a), + VarNode(:b) + ]), [:a, :b]) tree11 = RuleNode(4, [ RuleNode(1), RuleNode(1) @@ -20,16 +20,17 @@ RuleNode(2), RuleNode(2) ]) - tree_large_true = RuleNode(3, [ - RuleNode(4, [ - RuleNode(2), - RuleNode(3, [ + tree_large_true = RuleNode(3, + [ + RuleNode(4, [ RuleNode(2), - RuleNode(2) - ]) - ]), - RuleNode(2) - ]) + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) + ]), + RuleNode(2) + ]) @test check_tree(ordered, tree11) == true @test check_tree(ordered, tree12) == true @test check_tree(ordered, tree22) == true @@ -39,33 +40,35 @@ @testset "check_tree false, length(order)=2" begin ordered = Ordered(RuleNode(4, [ - VarNode(:a), - VarNode(:b) - ]), [:a, :b]) + VarNode(:a), + VarNode(:b) + ]), [:a, :b]) tree21 = RuleNode(4, [ RuleNode(2), RuleNode(1) ]) - tree_large_false = RuleNode(3, [ - RuleNode(4, [ - RuleNode(3, [ - RuleNode(2), + tree_large_false = RuleNode(3, + [ + RuleNode(4, [ + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]), RuleNode(2) ]), RuleNode(2) - ]), - RuleNode(2) - ]) + ]) @test check_tree(ordered, tree21) == false @test check_tree(ordered, tree_large_false) == false end @testset "check_tree true, length(order)=3" begin - ordered = Ordered(RuleNode(4, [ - VarNode(:a), - VarNode(:b), - VarNode(:c) - ]), [:a, :b, :c]) + ordered = Ordered( + RuleNode(4, [ + VarNode(:a), + VarNode(:b), + VarNode(:c) + ]), [:a, :b, :c]) tree111 = RuleNode(4, [ RuleNode(1), RuleNode(1), @@ -86,25 +89,27 @@ RuleNode(1), RuleNode(1) ]) - tree123 = RuleNode(4, [ - RuleNode(1), - RuleNode(2), - RuleNode(3, [ - RuleNode(1), + tree123 = RuleNode( + 4, [ RuleNode(1), + RuleNode(2), + RuleNode(3, [ + RuleNode(1), + RuleNode(1) + ]) ]) - ]) - tree133 = RuleNode(4, [ - RuleNode(1), - RuleNode(3, [ - RuleNode(1), - RuleNode(1), - ]), - RuleNode(3, [ - RuleNode(1), + tree133 = RuleNode(4, + [ RuleNode(1), + RuleNode(3, [ + RuleNode(1), + RuleNode(1) + ]), + RuleNode(3, [ + RuleNode(1), + RuleNode(1) + ]) ]) - ]) @test check_tree(ordered, tree111) == true @test check_tree(ordered, tree112) == true @test check_tree(ordered, tree122) == true @@ -114,38 +119,41 @@ end @testset "check_tree false, length(order)=3" begin - ordered = Ordered(RuleNode(4, [ - VarNode(:a), - VarNode(:b), - VarNode(:c) - ]), [:a, :b, :c]) + ordered = Ordered( + RuleNode(4, [ + VarNode(:a), + VarNode(:b), + VarNode(:c) + ]), [:a, :b, :c]) tree121 = RuleNode(4, [ RuleNode(1), RuleNode(2), RuleNode(1) ]) - tree133_leftchild_false = RuleNode(4, [ - RuleNode(1), - RuleNode(3, [ - RuleNode(2), - RuleNode(1), - ]), - RuleNode(3, [ - RuleNode(1), + tree133_leftchild_false = RuleNode(4, + [ RuleNode(1), + RuleNode(3, [ + RuleNode(2), + RuleNode(1) + ]), + RuleNode(3, [ + RuleNode(1), + RuleNode(1) + ]) ]) - ]) - tree133_rightchild_false = RuleNode(4, [ - RuleNode(1), - RuleNode(3, [ - RuleNode(1), - RuleNode(2), - ]), - RuleNode(3, [ - RuleNode(1), + tree133_rightchild_false = RuleNode(4, + [ RuleNode(1), + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(1), + RuleNode(1) + ]) ]) - ]) @test check_tree(ordered, tree121) == false @test check_tree(ordered, tree133_leftchild_false) == false @test check_tree(ordered, tree133_rightchild_false) == false diff --git a/test/test_pattern_match.jl b/test/test_pattern_match.jl index fa7fe61..ddbbedf 100644 --- a/test/test_pattern_match.jl +++ b/test/test_pattern_match.jl @@ -22,94 +22,120 @@ using HerbGrammar @testset "PatternMatchSuccess, holes underneath a VarNode" begin hole = Hole(BitVector((1, 1, 1, 1, 1, 1))) node_1hole = RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)] ) - node_2holes = RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - Hole(BitVector((1, 1, 1, 1, 1, 1)))] + node_2holes = RuleNode( + 4, [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1)))] ) @test pattern_match(hole, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess @test pattern_match(node_1hole, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess - @test pattern_match(node_2holes, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess + @test pattern_match(node_2holes, VarNode(:x)) isa + HerbConstraints.PatternMatchSuccess end @testset "PatternMatchSuccess, holes underneath different VarNodes" begin varnodes = RuleNode(4, [VarNode(:x), VarNode(:y)]) - node_2holes = RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - Hole(BitVector((1, 1, 1, 1, 1, 1))) - ]) - node_3holes = RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), + node_2holes = RuleNode( + 4, [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1))) ]) - ]) - node_4holes = RuleNode(4, [ - RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - Hole(BitVector((1, 1, 1, 1, 1, 1))) - ]), - RuleNode(5, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - Hole(BitVector((1, 1, 1, 1, 1, 1))) + node_3holes = RuleNode(4, + [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + RuleNode(4, + [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1))) + ]) ]) - ]) - @test pattern_match(node_2holes, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess - @test pattern_match(node_3holes, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess - @test pattern_match(node_4holes, VarNode(:x)) isa HerbConstraints.PatternMatchSuccess + node_4holes = RuleNode(4, + [ + RuleNode(4, + [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1))) + ]), + RuleNode(5, + [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1))) + ]) + ]) + @test pattern_match(node_2holes, VarNode(:x)) isa + HerbConstraints.PatternMatchSuccess + @test pattern_match(node_3holes, VarNode(:x)) isa + HerbConstraints.PatternMatchSuccess + @test pattern_match(node_4holes, VarNode(:x)) isa + HerbConstraints.PatternMatchSuccess end - + @testset "PatternMatchSuccessWhenHoleAssignedTo, 1 hole with a valid domain" begin - rn_variable_shaped_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) - rn_fixed_shaped_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]) - rn_single_value_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((1, 0, 0, 0, 0, 0)))]) + rn_variable_shaped_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + rn_fixed_shaped_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]) + rn_single_value_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((1, 0, 0, 0, 0, 0)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) - @test pattern_match(rn_variable_shaped_hole, mn) isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo - @test pattern_match(rn_fixed_shaped_hole, mn) isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo - + @test pattern_match(rn_variable_shaped_hole, mn) isa + HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo + @test pattern_match(rn_fixed_shaped_hole, mn) isa + HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo + # the convention for this test changed. holes of domain size 1 are considered to be filled. # `rn_single_value_hole` and `mn` match successfully, as `rn_single_value_hole` is considered to be filled. - @test pattern_match(rn_single_value_hole, mn) isa HerbConstraints.PatternMatchSuccess - + @test pattern_match(rn_single_value_hole, mn) isa + HerbConstraints.PatternMatchSuccess + @test pattern_match(rn_fixed_shaped_hole, mn).ind == 1 end @testset "PatternMatchSuccessWhenHoleAssignedTo, path" begin - mn = RuleNode(4, [ - RuleNode(1), - RuleNode(4, [ - RuleNode(4, [ - RuleNode(1), - RuleNode(4, [ - RuleNode(4, [ - RuleNode(1), - RuleNode(1) - ]), + mn = RuleNode(4, + [ + RuleNode(1), + RuleNode(4, + [ + RuleNode(4, + [ + RuleNode(1), + RuleNode(4, + [ + RuleNode(4, [ + RuleNode(1), + RuleNode(1) + ]), + RuleNode(1) + ]) + ]), RuleNode(1) - ]), - ]), - RuleNode(1) + ]) ]) - ]) - rn = RuleNode(4, [ - RuleNode(1), - RuleNode(4, [ - RuleNode(4, [ - RuleNode(1), - RuleNode(4, [ - RuleNode(4, [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - RuleNode(1) - ]), + rn = RuleNode(4, + [ + RuleNode(1), + RuleNode(4, + [ + RuleNode(4, + [ + RuleNode(1), + RuleNode(4, + [ + RuleNode(4, + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + RuleNode(1) + ]), + RuleNode(1) + ]) + ]), RuleNode(1) - ]), - ]), - RuleNode(1) + ]) ]) - ]) match = pattern_match(rn, mn) @test match.ind == 1 @test get_path(rn, match.hole) == [2, 1, 2, 1, 1] @@ -137,9 +163,9 @@ using HerbGrammar rn = RuleNode(4, [RuleNode(1), RuleNode(1)]) mn_small = RuleNode(1) mn_large = RuleNode(4, [ - RuleNode(1), + RuleNode(1), RuleNode(4, [ - RuleNode(1), + RuleNode(1), RuleNode(1) ]) ]) @@ -148,18 +174,26 @@ using HerbGrammar end @testset "PatternMatchHardFail, 1 hole with an invalid domain" begin - rn_variable_shaped_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((0, 1, 1, 1, 1, 1)))]) - rn_fixed_shaped_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((0, 0, 0, 1, 1, 1)))]) - rn_single_value_hole = RuleNode(4, [RuleNode(1), Hole(BitVector((0, 0, 0, 0, 1, 1)))]) + rn_variable_shaped_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((0, 1, 1, 1, 1, 1)))]) + rn_fixed_shaped_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((0, 0, 0, 1, 1, 1)))]) + rn_single_value_hole = RuleNode( + 4, [RuleNode(1), Hole(BitVector((0, 0, 0, 0, 1, 1)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) - @test pattern_match(rn_variable_shaped_hole, mn) isa HerbConstraints.PatternMatchHardFail - @test pattern_match(rn_fixed_shaped_hole, mn) isa HerbConstraints.PatternMatchHardFail - @test pattern_match(rn_single_value_hole, mn) isa HerbConstraints.PatternMatchHardFail + @test pattern_match(rn_variable_shaped_hole, mn) isa + HerbConstraints.PatternMatchHardFail + @test pattern_match(rn_fixed_shaped_hole, mn) isa + HerbConstraints.PatternMatchHardFail + @test pattern_match(rn_single_value_hole, mn) isa + HerbConstraints.PatternMatchHardFail end @testset "PatternMatchHardFail, 1 hole with a valid domain, 1 hole with an invalid domain" begin - rn1 = RuleNode(4, [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((0, 1, 1, 1, 1, 1)))]) - rn2 = RuleNode(4, [Hole(BitVector((0, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + rn1 = RuleNode( + 4, [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((0, 1, 1, 1, 1, 1)))]) + rn2 = RuleNode( + 4, [Hole(BitVector((0, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn1, mn) isa HerbConstraints.PatternMatchHardFail @test pattern_match(rn2, mn) isa HerbConstraints.PatternMatchHardFail @@ -172,37 +206,43 @@ using HerbGrammar end @testset "PatternMatchHardFail, 2 holes with invalid domains" begin - rn = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), [Hole(BitVector((0, 0, 1, 1, 1, 1))), RuleNode(1)]) + rn = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), + [Hole(BitVector((0, 0, 1, 1, 1, 1))), RuleNode(1)]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn, mn) isa HerbConstraints.PatternMatchHardFail end @testset "PatternMatchHardFail, 1 uniform hole with a valid domain, 1 hole with an invalid domain" begin - rn = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), [Hole(BitVector((0, 0, 1, 1, 1, 1))), RuleNode(1)]) + rn = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), + [Hole(BitVector((0, 0, 1, 1, 1, 1))), RuleNode(1)]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn, mn) isa HerbConstraints.PatternMatchHardFail end @testset "PatternMatchHardFail, 1 uniform hole with an invalid domain, 1 hole with a valid domain" begin - rn1 = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) - rn2 = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + rn1 = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), + [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) + rn2 = UniformHole(BitVector((0, 0, 0, 0, 1, 1)), + [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn1, mn) isa HerbConstraints.PatternMatchHardFail @test pattern_match(rn2, mn) isa HerbConstraints.PatternMatchHardFail end @testset "PatternMatchHardFail, 2 holes with valid domains, but rule node mismatch" begin - rn = RuleNode(4, [ - RuleNode(4, [ - Hole(BitVector((1, 1, 1, 1, 1, 1))), - Hole(BitVector((1, 1, 1, 1, 1, 1))) - ]), - RuleNode(1) - ]) + rn = RuleNode(4, + [ + RuleNode(4, + [ + Hole(BitVector((1, 1, 1, 1, 1, 1))), + Hole(BitVector((1, 1, 1, 1, 1, 1))) + ]), + RuleNode(1) + ]) mn = RuleNode(4, [ RuleNode(4, [ - RuleNode(2), + RuleNode(2), RuleNode(2) ]), RuleNode(2) @@ -212,15 +252,18 @@ using HerbGrammar end @testset "PatternMatchSoftFail, 1 uniform hole with an valid domain, 1 hole with a valid domain" begin - rn1 = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) - rn2 = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + rn1 = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), + [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) + rn2 = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), + [RuleNode(1), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn1, mn) isa HerbConstraints.PatternMatchSoftFail @test pattern_match(rn2, mn) isa HerbConstraints.PatternMatchSoftFail end @testset "PatternMatchSoftFail, 2 holes with valid domains" begin - rn = RuleNode(4, [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + rn = RuleNode( + 4, [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) mn = RuleNode(4, [RuleNode(1), RuleNode(1)]) @test pattern_match(rn, mn) isa HerbConstraints.PatternMatchSoftFail end @@ -257,7 +300,8 @@ using HerbGrammar sm = HerbConstraints.StateManager() h1 = StateHole(sm, UniformHole(BitVector((1, 0, 0)), [RuleNode(3)])) h2 = StateHole(sm, UniformHole(BitVector((1, 1, 0)), [RuleNode(3)])) - @test pattern_match(h1, h2) isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo + @test pattern_match(h1, h2) isa + HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo end @testset "Softfail" begin @@ -284,8 +328,12 @@ using HerbGrammar @test pattern_match(node_fail, mn) isa HerbConstraints.PatternMatchHardFail end @testset "Depth2" begin - node_success = RuleNode(4, [RuleNode(4, [RuleNode(1), RuleNode(1)]), RuleNode(4, [RuleNode(1), RuleNode(1)])]) - node_fail = RuleNode(4, [RuleNode(4, [RuleNode(1), RuleNode(1)]), RuleNode(4, [RuleNode(2), RuleNode(1)])]) + node_success = RuleNode(4, + [RuleNode(4, [RuleNode(1), RuleNode(1)]), + RuleNode(4, [RuleNode(1), RuleNode(1)])]) + node_fail = RuleNode(4, + [RuleNode(4, [RuleNode(1), RuleNode(1)]), + RuleNode(4, [RuleNode(2), RuleNode(1)])]) mn = RuleNode(4, [VarNode(:x), VarNode(:x)]) @test pattern_match(node_success, mn) isa HerbConstraints.PatternMatchSuccess @test pattern_match(node_fail, mn) isa HerbConstraints.PatternMatchHardFail @@ -307,14 +355,16 @@ using HerbGrammar @test match.ind == 1 end @testset "Hole in the left VarNode, depth 2" begin - n1 = RuleNode(4, [ - RuleNode(4, [Hole(BitVector((1, 1, 0, 0, 0, 0))), RuleNode(1)]), - RuleNode(4, [RuleNode(2), RuleNode(1)]) - ]) - n2 = RuleNode(4, [ - RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]), - RuleNode(4, [RuleNode(1), RuleNode(2)]) - ]) + n1 = RuleNode(4, + [ + RuleNode(4, [Hole(BitVector((1, 1, 0, 0, 0, 0))), RuleNode(1)]), + RuleNode(4, [RuleNode(2), RuleNode(1)]) + ]) + n2 = RuleNode(4, + [ + RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]), + RuleNode(4, [RuleNode(1), RuleNode(2)]) + ]) match1 = pattern_match(n1, mn) match2 = pattern_match(n2, mn) @test match1 isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo @@ -323,14 +373,16 @@ using HerbGrammar @test match2.ind == 2 end @testset "Hole in the right VarNode, depth 2" begin - n1 = RuleNode(4, [ - RuleNode(4, [RuleNode(2), RuleNode(1)]), - RuleNode(4, [Hole(BitVector((1, 1, 0, 0, 0, 0))), RuleNode(1)]) - ]) - n2 = RuleNode(4, [ - RuleNode(4, [RuleNode(1), RuleNode(2)]), - RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]) - ]) + n1 = RuleNode(4, + [ + RuleNode(4, [RuleNode(2), RuleNode(1)]), + RuleNode(4, [Hole(BitVector((1, 1, 0, 0, 0, 0))), RuleNode(1)]) + ]) + n2 = RuleNode(4, + [ + RuleNode(4, [RuleNode(1), RuleNode(2)]), + RuleNode(4, [RuleNode(1), Hole(BitVector((1, 1, 0, 0, 0, 0)))]) + ]) match1 = pattern_match(n1, mn) match2 = pattern_match(n2, mn) @test match1 isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo @@ -343,43 +395,52 @@ using HerbGrammar @testset "VarNode HardFails with holes" begin mn = RuleNode(4, [VarNode(:x), VarNode(:x)]) @testset "Disjoint Holes, after RuleNode Success" begin - n1 = RuleNode(4, [ - RuleNode(4, [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((1, 1, 0, 0, 0, 0))) - ]), - RuleNode(4, [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((0, 0, 1, 1, 0, 0))) + n1 = RuleNode(4, + [ + RuleNode(4, + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((1, 1, 0, 0, 0, 0))) + ]), + RuleNode(4, + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((0, 0, 1, 1, 0, 0))) + ]) ]) - ]) @test pattern_match(n1, mn) isa HerbConstraints.PatternMatchHardFail end @testset "Disjoint Holes, after UniformHole SoftFail" begin - n1 = RuleNode(4, [ - UniformHole(BitVector((0, 0, 0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((1, 1, 0, 0, 0, 0))) - ]), - UniformHole(BitVector((0, 0, 0, 1, 1, 0)), [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((0, 0, 1, 1, 0, 0))) - ]), - ]) + n1 = RuleNode(4, + [ + UniformHole(BitVector((0, 0, 0, 0, 1, 1)), + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((1, 1, 0, 0, 0, 0))) + ]), + UniformHole(BitVector((0, 0, 0, 1, 1, 0)), + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((0, 0, 1, 1, 0, 0))) + ]) + ]) @test pattern_match(n1, mn) isa HerbConstraints.PatternMatchHardFail end @testset "Disjoint UniformHoles" begin - n1 = RuleNode(4, [ - UniformHole(BitVector((0, 0, 0, 0, 1, 1)), [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((1, 1, 0, 0, 0, 0))) - ]), - UniformHole(BitVector((0, 0, 0, 1, 0, 0)), [ - Hole(BitVector((1, 1, 0, 0, 0, 0))), - Hole(BitVector((1, 1, 0, 0, 0, 0))) - ]), - ]) + n1 = RuleNode(4, + [ + UniformHole(BitVector((0, 0, 0, 0, 1, 1)), + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((1, 1, 0, 0, 0, 0))) + ]), + UniformHole(BitVector((0, 0, 0, 1, 0, 0)), + [ + Hole(BitVector((1, 1, 0, 0, 0, 0))), + Hole(BitVector((1, 1, 0, 0, 0, 0))) + ]) + ]) @test pattern_match(n1, mn) isa HerbConstraints.PatternMatchHardFail end end -end \ No newline at end of file +end diff --git a/test/test_pattern_match_domainrulenode.jl b/test/test_pattern_match_domainrulenode.jl index 6c4d8f6..2ddac94 100644 --- a/test/test_pattern_match_domainrulenode.jl +++ b/test/test_pattern_match_domainrulenode.jl @@ -21,7 +21,9 @@ using HerbGrammar @testset "PatternMatchSuccess, RuleNode, multiple DomainRuleNodes" begin node = RuleNode(4, [RuleNode(1), RuleNode(1)]) - drn = DomainRuleNode(BitVector((0, 0, 0, 1, 1, 1)), [DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), []), DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), [])]) + drn = DomainRuleNode(BitVector((0, 0, 0, 1, 1, 1)), + [DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), []), + DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), [])]) @test pattern_match(node, drn) isa HerbConstraints.PatternMatchSuccess end @@ -38,12 +40,16 @@ using HerbGrammar @testset "PatternMatchSuccess, UniformHole subsets, but children fail" begin # The root UniformHole match the DomainRuleNode, but the children do not match - hole_hardfail = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), [Hole(BitVector((0, 1, 1, 1, 1, 0))), RuleNode(1)]) - hole_successwhen = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) - hole_softfail = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) + hole_hardfail = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), + [Hole(BitVector((0, 1, 1, 1, 1, 0))), RuleNode(1)]) + hole_successwhen = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), + [Hole(BitVector((1, 1, 1, 1, 1, 1))), RuleNode(1)]) + hole_softfail = UniformHole(BitVector((0, 0, 0, 1, 1, 0)), + [Hole(BitVector((1, 1, 1, 1, 1, 1))), Hole(BitVector((1, 1, 1, 1, 1, 1)))]) drn = DomainRuleNode(BitVector((0, 0, 0, 1, 1, 1)), [RuleNode(1), RuleNode(1)]) @test pattern_match(hole_hardfail, drn) isa HerbConstraints.PatternMatchHardFail - @test pattern_match(hole_successwhen, drn) isa HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo + @test pattern_match(hole_successwhen, drn) isa + HerbConstraints.PatternMatchSuccessWhenHoleAssignedTo @test pattern_match(hole_softfail, drn) isa HerbConstraints.PatternMatchSoftFail end @@ -107,7 +113,8 @@ using HerbGrammar # at the second child node = RuleNode(4, [RuleNode(1), UniformHole(BitVector((1, 1, 0, 0, 0, 0)), [])]) - drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), [RuleNode(1), DomainRuleNode(BitVector((0, 0, 1, 1, 0, 0)), [])]) + drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), + [RuleNode(1), DomainRuleNode(BitVector((0, 0, 1, 1, 0, 0)), [])]) @test pattern_match(node, drn) isa HerbConstraints.PatternMatchHardFail end @@ -119,7 +126,8 @@ using HerbGrammar # at the second child node = RuleNode(4, [RuleNode(1), RuleNode(1)]) - drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), [RuleNode(1), DomainRuleNode(BitVector((0, 0, 1, 1, 0, 0)), [])]) + drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), + [RuleNode(1), DomainRuleNode(BitVector((0, 0, 1, 1, 0, 0)), [])]) @test pattern_match(node, drn) isa HerbConstraints.PatternMatchHardFail end @@ -130,12 +138,17 @@ using HerbGrammar end @testset "PatternMatchSoftFail, 2 PatternMatchSuccessWhenHoleAssignedTo" begin - drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), [DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), []), DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), [])]) + drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), + [DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), []), + DomainRuleNode(BitVector((1, 1, 0, 0, 0, 0)), [])]) + + node_roothole = UniformHole( + BitVector((0, 0, 0, 1, 1, 1)), [RuleNode(1), RuleNode(1)]) + node_childhole = RuleNode( + 6, [UniformHole(BitVector((1, 1, 1, 0, 0, 0)), []), RuleNode(1)]) + node_2holes = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), + [UniformHole(BitVector((1, 1, 1, 0, 0, 0)), []), RuleNode(1)]) - node_roothole = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), [RuleNode(1), RuleNode(1)]) - node_childhole = RuleNode(6, [UniformHole(BitVector((1, 1, 1, 0, 0, 0)), []), RuleNode(1)]) - node_2holes = UniformHole(BitVector((0, 0, 0, 1, 1, 1)), [UniformHole(BitVector((1, 1, 1, 0, 0, 0)), []), RuleNode(1)]) - match_roothole = pattern_match(node_roothole, drn) match_childhole = pattern_match(node_childhole, drn) match_2holes = pattern_match(node_2holes, drn) @@ -158,4 +171,4 @@ using HerbGrammar drn = DomainRuleNode(BitVector((0, 0, 0, 0, 1, 1)), [RuleNode(1), RuleNode(1)]) @test pattern_match(hole, drn) isa HerbConstraints.PatternMatchSoftFail end -end \ No newline at end of file +end diff --git a/test/test_pattern_match_edgecases.jl b/test/test_pattern_match_edgecases.jl index e8dfbb9..2700026 100644 --- a/test/test_pattern_match_edgecases.jl +++ b/test/test_pattern_match_edgecases.jl @@ -3,12 +3,12 @@ using HerbGrammar #These test contain edgecases that fail in the current implemention @testset verbose=false "PatternMatch Edgecase" begin - @testset "3 VarNodes: pairwise Softfail, triplewise HardFail" begin - rn = RuleNode(4, [ - RuleNode(4, [Hole(BitVector((1, 1, 0))), Hole(BitVector((0, 1, 1)))]), - Hole(BitVector((1, 0, 1))) - ]) + rn = RuleNode(4, + [ + RuleNode(4, [Hole(BitVector((1, 1, 0))), Hole(BitVector((0, 1, 1)))]), + Hole(BitVector((1, 0, 1))) + ]) mn = RuleNode(4, [ RuleNode(4, [VarNode(:x), VarNode(:x)]), VarNode(:x) @@ -17,10 +17,11 @@ using HerbGrammar end @testset "3 VarNodes: HardFail on instance 2 and 3" begin - rn = RuleNode(4, [ - RuleNode(4, [Hole(BitVector((1, 1, 1))), RuleNode(1)]), - RuleNode(2) - ]) + rn = RuleNode( + 4, [ + RuleNode(4, [Hole(BitVector((1, 1, 1))), RuleNode(1)]), + RuleNode(2) + ]) mn = RuleNode(4, [ RuleNode(4, [VarNode(:x), VarNode(:x)]), VarNode(:x) diff --git a/test/test_state_fixed_shaped_hole.jl b/test/test_state_fixed_shaped_hole.jl index a9a8282..e8970a0 100644 --- a/test/test_state_fixed_shaped_hole.jl +++ b/test/test_state_fixed_shaped_hole.jl @@ -1,17 +1,17 @@ @testset verbose=false "StateHole" begin @testset "convert, isfilled and get_rule" begin - root_stateless = UniformHole(BitVector((1, 1, 0, 0, 0)), [ # domain size 2 - UniformHole(BitVector((1, 0, 0, 0, 0)), [ # domain size 1 (assigned) - UniformHole(BitVector((0, 0, 0, 1, 0)), []) # domain size 1 (assigned) - RuleNode(4) # remains a rulenode - ]), - RuleNode(5, [ # remains a rulenode - UniformHole(BitVector((0, 0, 1, 1, 0)), []) # domain size 2 + root_stateless = UniformHole(BitVector((1, 1, 0, 0, 0)), + [ # domain size 2 + UniformHole(BitVector((1, 0, 0, 0, 0)), + [UniformHole(BitVector((0, 0, 0, 1, 0)), []) # domain size 1 (assigned) + RuleNode(4)]), + RuleNode(5, [ # remains a rulenode + UniformHole(BitVector((0, 0, 1, 1, 0)), []) # domain size 2 + ]) ]) - ]) sm = HerbConstraints.StateManager() root = HerbConstraints.StateHole(sm, root_stateless) - + @test size(root.domain) == 2 @test 1 ∈ root.domain @test 2 ∈ root.domain @@ -22,7 +22,7 @@ @test 1 ∈ node.domain @test isfilled(node) == true @test get_rule(node) == 1 - + node = root.children[1].children[1] @test size(node.domain) == 1 @test 4 ∈ node.domain @@ -45,15 +45,15 @@ end @testset "contains_hole" begin - root_stateless = UniformHole(BitVector((1, 1, 0, 0, 0)), [ # domain size 2 - UniformHole(BitVector((1, 0, 0, 0, 0)), [ # domain size 1 (assigned) - UniformHole(BitVector((0, 0, 0, 1, 0)), []) # domain size 1 (assigned) - RuleNode(4) # remains a rulenode - ]), - RuleNode(5, [ # remains a rulenode - UniformHole(BitVector((0, 0, 1, 1, 0)), []) # domain size 2 + root_stateless = UniformHole(BitVector((1, 1, 0, 0, 0)), + [ # domain size 2 + UniformHole(BitVector((1, 0, 0, 0, 0)), + [UniformHole(BitVector((0, 0, 0, 1, 0)), []) # domain size 1 (assigned) + RuleNode(4)]), + RuleNode(5, [ # remains a rulenode + UniformHole(BitVector((0, 0, 1, 1, 0)), []) # domain size 2 + ]) ]) - ]) sm = HerbConstraints.StateManager() root = HerbConstraints.StateHole(sm, root_stateless) @@ -63,7 +63,8 @@ end @testset "is_filled (empty domain)" begin - hole = HerbConstraints.StateHole(HerbConstraints.StateManager(), UniformHole(BitVector((0, 0, 0)), [])) + hole = HerbConstraints.StateHole( + HerbConstraints.StateManager(), UniformHole(BitVector((0, 0, 0)), [])) @test isfilled(hole) == false end diff --git a/test/test_state_manager.jl b/test/test_state_manager.jl index 1845075..28b84a8 100644 --- a/test/test_state_manager.jl +++ b/test/test_state_manager.jl @@ -102,7 +102,7 @@ save_state!(sm) a = StateInt(sm, 0) # initialize a new state int, set its value to 0 (post a new constraint) set_value!(a, 1) # immediately update the state int to 1 (activate the newly posted constraint) - restore!(sm) + restore!(sm) @test get_value(a) == 0 # on backtrack, the new constraint should be deactivated end end diff --git a/test/test_state_sparse_set.jl b/test/test_state_sparse_set.jl index 56cb576..11e9718 100644 --- a/test/test_state_sparse_set.jl +++ b/test/test_state_sparse_set.jl @@ -31,7 +31,7 @@ remove!(set, 2) remove!(set, 3) @test findlast(set) == 10 - + set = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), 10) remove!(set, 10) @test findlast(set) == 9 @@ -48,14 +48,14 @@ @testset "in" begin n = 5 - for remaining_value ∈ 1:n + for remaining_value in 1:n set = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), n) - for i ∈ 1:n + for i in 1:n if i != remaining_value remove!(set, i) end end - for i ∈ 1:10 + for i in 1:10 if i == remaining_value @test i ∈ set else @@ -114,10 +114,10 @@ set = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), 10) HerbConstraints.remove_below!(set, 5) @test size(set) == 6 - for i ∈ 1:4 + for i in 1:4 @test i ∉ set end - for i ∈ 5:10 + for i in 5:10 @test i ∈ set end end @@ -126,10 +126,10 @@ set = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), 10) HerbConstraints.remove_above!(set, 4) @test size(set) == 4 - for i ∈ 1:4 + for i in 1:4 @test i ∈ set end - for i ∈ 5:10 + for i in 5:10 @test i ∉ set end end @@ -157,7 +157,7 @@ HerbConstraints.remove!(set, 4) HerbConstraints.remove!(set, 1) vec = Vector{Int}() - for value ∈ set + for value in set push!(vec, value) end @test length(vec) == 3 @@ -186,7 +186,8 @@ end @testset "findall" begin - set = HerbConstraints.StateSparseSet(HerbConstraints.StateManager(), BitVector((1, 0, 1))) + set = HerbConstraints.StateSparseSet( + HerbConstraints.StateManager(), BitVector((1, 0, 1))) @test findall(set) == [1, 3] end end diff --git a/test/test_state_stack.jl b/test/test_state_stack.jl index 3ec86e4..fe8a505 100644 --- a/test/test_state_stack.jl +++ b/test/test_state_stack.jl @@ -51,15 +51,22 @@ sm = HerbConstraints.StateManager() stack = HerbConstraints.StateStack{Int}(sm) - push!(stack, 10); @test size(stack) == 1 - push!(stack, 20); @test size(stack) == 2 + push!(stack, 10) + @test size(stack) == 1 + push!(stack, 20) + @test size(stack) == 2 - save_state!(sm); @test size(stack) == 2 - push!(stack, 30); @test size(stack) == 3 - push!(stack, 40); @test size(stack) == 4 + save_state!(sm) + @test size(stack) == 2 + push!(stack, 30) + @test size(stack) == 3 + push!(stack, 40) + @test size(stack) == 4 - restore!(sm); @test size(stack) == 2 - push!(stack, 50); @test size(stack) == 3 #overwrites "30" with "50" + restore!(sm) + @test size(stack) == 2 + push!(stack, 50) + @test size(stack) == 3 #overwrites "30" with "50" values = collect(stack) @test values[1] == 10 @@ -71,22 +78,34 @@ sm = HerbConstraints.StateManager() stack = HerbConstraints.StateStack{Int}(sm) - push!(stack, 10); @test size(stack) == 1 #[10] - push!(stack, 20); @test size(stack) == 2 #[10, 20] - - save_state!(sm); @test size(stack) == 2 #[10, 20] - push!(stack, 30); @test size(stack) == 3 #[10, 20, 30] - push!(stack, 40); @test size(stack) == 4 #[10, 20, 30, 40] - - save_state!(sm); @test size(stack) == 4 #[10, 20, 30, 40] - push!(stack, 50); @test size(stack) == 5 #[10, 20, 30, 40, 50] - push!(stack, 60); @test size(stack) == 6 #[10, 20, 30, 40, 50, 60] - - restore!(sm); @test size(stack) == 4 #[10, 20, 30, 40] - push!(stack, 70); @test size(stack) == 5 #[10, 20, 30, 40, 70] + push!(stack, 10) + @test size(stack) == 1 #[10] + push!(stack, 20) + @test size(stack) == 2 #[10, 20] - restore!(sm); @test size(stack) == 2 #[10, 20] - push!(stack, 80); @test size(stack) == 3 #[10, 20, 80] + save_state!(sm) + @test size(stack) == 2 #[10, 20] + push!(stack, 30) + @test size(stack) == 3 #[10, 20, 30] + push!(stack, 40) + @test size(stack) == 4 #[10, 20, 30, 40] + + save_state!(sm) + @test size(stack) == 4 #[10, 20, 30, 40] + push!(stack, 50) + @test size(stack) == 5 #[10, 20, 30, 40, 50] + push!(stack, 60) + @test size(stack) == 6 #[10, 20, 30, 40, 50, 60] + + restore!(sm) + @test size(stack) == 4 #[10, 20, 30, 40] + push!(stack, 70) + @test size(stack) == 5 #[10, 20, 30, 40, 70] + + restore!(sm) + @test size(stack) == 2 #[10, 20] + push!(stack, 80) + @test size(stack) == 3 #[10, 20, 80] values = collect(stack) @test values[1] == 10 diff --git a/test/test_treemanipulations.jl b/test/test_treemanipulations.jl index 26e57c7..f288ffe 100644 --- a/test/test_treemanipulations.jl +++ b/test/test_treemanipulations.jl @@ -1,7 +1,6 @@ using HerbCore, HerbGrammar @testset verbose=false "Tree Manipulations (GenericSolver)" begin - function create_dummy_solver() grammar = @csgrammar begin Number = x | 1 @@ -15,12 +14,12 @@ using HerbCore, HerbGrammar solver = create_dummy_solver() new_state!(solver, Hole(BitVector((0, 0, 1, 1)))) #HerbConstraints.simplify_hole!(solver, Vector{Int}()) this will be done inside `new_state!` - + tree = get_tree(solver) @test tree isa UniformHole @test tree.domain == BitVector((0, 0, 1, 1)) @test length(tree.children) == 2 - for child ∈ tree.children + for child in tree.children @test child isa Hole @test child.domain == BitVector((1, 1, 1, 1)) end @@ -30,12 +29,12 @@ using HerbCore, HerbGrammar solver = create_dummy_solver() new_state!(solver, Hole(BitVector((0, 0, 0, 1)))) #HerbConstraints.simplify_hole!(solver, Vector{Int}()) this will be done inside `new_state!` - + tree = get_tree(solver) @test tree isa RuleNode @test tree.ind == 4 @test length(tree.children) == 2 - for child ∈ tree.children + for child in tree.children @test child isa Hole @test child.domain == BitVector((1, 1, 1, 1)) end @@ -45,12 +44,12 @@ using HerbCore, HerbGrammar solver = create_dummy_solver() new_state!(solver, UniformHole(BitVector((0, 0, 0, 1)), [RuleNode(1), RuleNode(1)])) #HerbConstraints.simplify_hole!(solver, Vector{Int}()) this will be done inside `new_state!` - + tree = get_tree(solver) @test tree isa RuleNode @test tree.ind == 4 @test length(tree.children) == 2 - for child ∈ tree.children + for child in tree.children @test child isa RuleNode @test child.ind == 1 end @@ -58,13 +57,14 @@ using HerbCore, HerbGrammar @testset "remove_node!" begin solver = create_dummy_solver() - new_state!(solver, RuleNode(1, [ - RuleNode(1, [ # | This node will be 'removed'. It will be replaced with a hole - RuleNode(3), # | - RuleNode(3) # | - ]), # _| - RuleNode(2) - ])) + new_state!( + solver, RuleNode(1, [ + RuleNode(1, [ # | This node will be 'removed'. It will be replaced with a hole + RuleNode(3), # | + RuleNode(3) # | + ]), # _| + RuleNode(2) + ])) remove_node!(solver, [1]) tree = get_tree(solver) @test tree.children[1] isa Hole @@ -74,6 +74,4 @@ using HerbCore, HerbGrammar @test tree.children[1].domain[4] == true @test tree.children[2] == RuleNode(2) end - end - diff --git a/test/test_unique.jl b/test/test_unique.jl index 5cc9b45..d160d20 100644 --- a/test/test_unique.jl +++ b/test/test_unique.jl @@ -9,60 +9,65 @@ addconstraint!(grammar, unique1) @testset "check_tree" begin - tree_two_leaves = RuleNode(3, [ - RuleNode(3, [ - RuleNode(1), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - RuleNode(1) + tree_two_leaves = RuleNode(3, + [ + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + RuleNode(1) + ]) ]) - ]) - tree_two_inner = RuleNode(3, [ - RuleNode(1, [ - RuleNode(2), - RuleNode(2) - ]), - RuleNode(1, [ - RuleNode(2), - RuleNode(2) + tree_two_inner = RuleNode(3, + [ + RuleNode(1, [ + RuleNode(2), + RuleNode(2) + ]), + RuleNode(1, [ + RuleNode(2), + RuleNode(2) + ]) ]) - ]) - - tree_one_leaf = RuleNode(3, [ - RuleNode(3, [ - RuleNode(1), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - RuleNode(2) + + tree_one_leaf = RuleNode(3, + [ + RuleNode(3, [ + RuleNode(1), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) ]) - ]) - tree_one_inner = RuleNode(3, [ - RuleNode(1, [ - RuleNode(2), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - RuleNode(2) + tree_one_inner = RuleNode(3, + [ + RuleNode(1, [ + RuleNode(2), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) ]) - ]) - tree_zero = RuleNode(3, [ - RuleNode(3, [ - RuleNode(2), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - RuleNode(2) + tree_zero = RuleNode(3, + [ + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + RuleNode(2) + ]) ]) - ]) @test check_tree(unique1, tree_two_leaves) == false @test check_tree(unique1, tree_two_inner) == false @@ -79,30 +84,32 @@ ]) @test !isfeasible(GenericSolver(grammar, node)) - node_with_holes = RuleNode(3, [ - RuleNode(3, [ - Hole(BitVector((1, 1, 1, 1))), - RuleNode(1) - ]), - RuleNode(3, [ - RuleNode(1), - Hole(BitVector((1, 1, 1, 1))) + node_with_holes = RuleNode(3, + [ + RuleNode(3, [ + Hole(BitVector((1, 1, 1, 1))), + RuleNode(1) + ]), + RuleNode(3, [ + RuleNode(1), + Hole(BitVector((1, 1, 1, 1))) + ]) ]) - ]) @test !isfeasible(GenericSolver(grammar, node_with_holes)) end @testset "propagate softfail" begin - node_with_holes = RuleNode(3, [ - RuleNode(3, [ - Hole(BitVector((true, true, true, true))), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(2), - Hole(BitVector((true, true, true, true))) + node_with_holes = RuleNode(3, + [ + RuleNode(3, [ + Hole(BitVector((true, true, true, true))), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(2), + Hole(BitVector((true, true, true, true))) + ]) ]) - ]) solver = GenericSolver(grammar, node_with_holes) tree = get_tree(solver) @test isfeasible(solver) @@ -112,16 +119,17 @@ end @testset "propagate deduction" begin - node_with_holes = RuleNode(3, [ - RuleNode(3, [ - Hole(BitVector((true, true, true, true))), - RuleNode(2) - ]), - RuleNode(3, [ - RuleNode(1), #a 1 is present, so all 1s from other holes must be removed - Hole(BitVector((true, true, true, true))) + node_with_holes = RuleNode(3, + [ + RuleNode(3, [ + Hole(BitVector((true, true, true, true))), + RuleNode(2) + ]), + RuleNode(3, [ + RuleNode(1), #a 1 is present, so all 1s from other holes must be removed + Hole(BitVector((true, true, true, true))) + ]) ]) - ]) solver = GenericSolver(grammar, node_with_holes) tree = get_tree(solver) @test isfeasible(solver) diff --git a/test/test_varnode.jl b/test/test_varnode.jl index 1b06b3c..4ab6e69 100644 --- a/test/test_varnode.jl +++ b/test/test_varnode.jl @@ -1,16 +1,17 @@ @testset verbose=false "VarNode" begin - @testset "number_of_varnodes" begin @test HerbConstraints.contains_varnode(RuleNode(1), :a) == false @test HerbConstraints.contains_varnode(VarNode(:a), :a) == true @test HerbConstraints.contains_varnode(VarNode(:b), :a) == false - @test HerbConstraints.contains_varnode(RuleNode(2, [ - VarNode(:b), - VarNode(:a) - ]), :a) == true - @test HerbConstraints.contains_varnode(RuleNode(2, [ - VarNode(:b), - VarNode(:b) - ]), :a) == false + @test HerbConstraints.contains_varnode( + RuleNode(2, [ + VarNode(:b), + VarNode(:a) + ]), :a) == true + @test HerbConstraints.contains_varnode( + RuleNode(2, [ + VarNode(:b), + VarNode(:b) + ]), :a) == false end end