Symbolic models

SoleModels.ConstantModelType
struct ConstantModel{O} <: LeafModel{O}
    outcome::O
    info::NamedTuple
end

The simplest type of model is the ConstantModel; it is a LeafModel that always outputs the same outcome.

Examples

julia> cm = ConstantModel(2);
julia> outcome(cm)
2

See also apply, LeafModel.

source
SoleModels.FunctionModelType
struct FunctionModel{O} <: LeafModel{O}
    f::FunctionWrapper{O}
    info::NamedTuple
end

A FunctionModel is a LeafModel that applies a native Julia Function in order to compute the outcome.

Warning

Over efficiency concerns, it is mandatory to make explicit the output type O by wrapping the Function into an object of type FunctionWrapper{O} (see FunctionWrappers.

See also LeafModel.

source
SoleModels.RuleType
struct Rule{O} <: AbstractModel{O}
    antecedent::Formula
    consequent::M where {M<:AbstractModel{<:O}}
    info::NamedTuple
end

A Rule is one of the fundamental building blocks of symbolic modeling, and has the semantics:

IF (antecedent) THEN (consequent) END

where the antecedent is a formula to be checked, and the consequent is the local outcome of the block.

Examples

julia> Rule(CONJUNCTION(Atom("p"), Atom("q")), ConstantModel(2))
▣ (p) ∧ (q)  ↣  2

See also AbstractModel, antecedent, consequent, SoleLogics.Formula.

source
SoleModels.BranchType
struct Branch{O} <: AbstractModel{O}
    antecedent::Formula
    posconsequent::M where {M<:AbstractModel{<:O}}
    negconsequent::M where {M<:AbstractModel{<:O}}
    info::NamedTuple
end

A Branch is one of the fundamental building blocks of symbolic modeling, and has the semantics:

IF (antecedent) THEN (positive consequent) ELSE (negative consequent) END

where the antecedent is a formula to be checked and the consequents are the feasible local outcomes of the block. If checking the antecedent evaluates to the top of the algebra, then the positive consequent is applied; otherwise, the negative consequent is applied.

See also AbstractModel, antecedent, SoleLogics.check, SoleLogics.Formula, negconsequent, posconsequent, Rule.

source
SoleModels.DecisionListType
struct DecisionList{O} <: AbstractModel{O}
    rulebase::Vector{Rule{_O} where {_O<:O}}
    defaultconsequent::M where {M<:AbstractModel{<:O}}
    info::NamedTuple
end

A DecisionList (or decision table, or rule-based model) is a symbolic model that has the semantics of an IF-ELSEIF-ELSE block:

IF (antecedent_1)     THEN (consequent_1)
ELSEIF (antecedent_2) THEN (consequent_2)
...
ELSEIF (antecedent_n) THEN (consequent_n)
ELSE (consequent_default) END

where the antecedents are formulas to be, and the consequents are the feasible local outcomes of the block.

Using the classical semantics, the antecedents are evaluated in order, and a consequent is returned as soon as a valid antecedent is found, or when the computation reaches the ELSE clause.

See also AbstractModel, DecisionTree, Rule.

source
SoleModels.DecisionTreeType
struct DecisionTree{O} <: AbstractModel{O}
    root::M where {M<:Union{LeafModel{O},Branch{O}}}
    info::NamedTuple
end

DecisionTree wraps a constrained sub-tree of Branch and LeafModel.

In other words, a DecisionTree is a symbolic model that operates as a nested structure of IF-THEN-ELSE blocks:

IF (antecedent_1) THEN
    IF (antecedent_2) THEN
        (consequent_1)
    ELSE
        (consequent_2)
    END
ELSE
    IF (antecedent_3) THEN
        (consequent_3)
    ELSE
        (consequent_4)
    END
END

where the antecedents are formulas to be, and the consequents are the feasible local outcomes of the block.

!!!note Note that this structure also includes an info::NamedTuple for storing additional information.

See also Branch, DecisionList, DecisionForest, LeafModel, MixedModel.

source
SoleModels.printmodelFunction
printmodel(io::IO, m::AbstractModel; kwargs...)
displaymodel(m::AbstractModel; kwargs...)

print or return a string representation of model m.

Arguments

  • header::Bool = false: when set to true, a header is printed, displaying the info structure for m;
  • show_subtree_info::Bool = false: when set to true, the header is printed for models in the sub-tree of m;
  • show_metrics::Bool = false: when set to true, performance metrics at each point of the subtree are shown, whenever they are available in the info structure;
  • max_depth::Union{Nothing,Int} = nothing: when it is an Int, models in the sub-tree with a depth higher than max_depth are ellipsed with "...";
  • syntaxstring_kwargs::NamedTuple = (;): kwargs to be passed to syntaxstring for formatting logical formulas.

See also syntaxstring, AbstractModel.

source

Evaluating symbolic models

SoleModels.evaluateruleMethod
evaluaterule(
    r::Rule{O},
    X::AbstractInterpretationSet,
    Y::AbstractVector{L}
) where {O,L<:Label}

Evaluate the rule on a labeled dataset, and return a NamedTuple consisting of:

  • antsat::Vector{Bool}: satsfaction of the antecedent for each instance in the dataset;
  • ys::Vector{Union{Nothing,O}}: rule prediction. For each instance in X:
    • consequent(rule) if the antecedent is satisfied,
    • nothing otherwise.

See also Rule, SoleLogics.AbstractInterpretationSet, Label, checkantecedent.

source
SoleModels.readmetricsMethod
readmetrics(m::AbstractModel; round_digits = nothing)

Return a NamedTuple with some performance metrics for the given symbolic model. Performance metrics can be computed when the info structure of the model has the following keys:

  • :supporting_labels
  • :supporting_predictions

The round_digits keyword argument, if provided, is used to round accuracy/confidence metrics.

source
SoleModels.rulemetricsMethod
rulemetrics(
    r::Rule,
    X::AbstractInterpretationSet,
    Y::AbstractVector{<:Label}
)

Compute metrics for a rule with respect to a labeled dataset and returns a NamedTuple consisting of:

  • support: number of instances satisfying the antecedent of the rule divided by the total number of instances;
  • error:
    • For classification problems: number of instances that were not classified
    correctly divided by the total number of instances;
    • For regression problems: mean squared error;
  • length: number of atoms in the rule's antecedent.

See also Rule, SoleLogics.AbstractInterpretationSet, Label, evaluaterule, outcometype, consequent.

source

Manipulating symbolic knowledge

SoleModels.joinrulesFunction
joinrules(rules::AbstractVector{<:Rule})::Vector{<:Rule}

Return a set of rules, with exactly one rule per different outcome from the input set of rules. For each outcome, the output rule is computed as the logical disjunction of the antecedents of the input rules for that outcome.

Examples

julia> using SoleLogics

julia> branch = Branch(SoleLogics.parseformula("p"), Branch(SoleLogics.parseformula("q"), "YES", "NO"), "NO")
 p
├✔ q
│├✔ YES
│└✘ NO
└✘ NO


julia> printmodel.(listrules(branch); tree_mode = true);
▣ p ∧ q
└✔ YES

▣ p ∧ ¬q
└✔ NO

▣ ¬p
└✔ NO

julia> printmodel.(joinrules(listrules(branch)); tree_mode = true);
▣ (p ∧ q)
└✔ YES

▣ (p ∧ ¬q) ∨ ¬p
└✔ NO

See also listrules, SoleLogics.DISJUNCTION, LeafModel, AbstractModel.

source
SoleModels.listrulesMethod
listrules(
    m::AbstractModel;
    use_shortforms::Bool = true,
    use_leftmostlinearform::Union{Nothing,Bool} = nothing,
    normalize::Bool = false,
    force_syntaxtree::Bool = false,
)::Vector{<:Rule}

Return a list of rules capturing the knowledge enclosed in symbolic model. The behavior of any symbolic model can be synthesised and represented as a set of mutually exclusive (and jointly exaustive, if the model is closed) rules, which can be useful for many purposes.

The keyword argument force_syntaxtree, when set to true, causes the logical antecedents in the returned rules to be represented as SyntaxTrees, as opposed to other syntax structure (e.g., LeftmostConjunctiveForm).

Examples

julia> using SoleLogics

julia> branch = Branch(SoleLogics.parseformula("p"), Branch(SoleLogics.parseformula("q"), "YES", "NO"), "NO")
 p
├✔ q
│├✔ YES
│└✘ NO
└✘ NO

julia> printmodel.(listrules(branch); tree_mode = true);
▣ p ∧ q
└✔ YES

▣ p ∧ ¬q
└✔ NO

▣ ¬p
└✔ NO

See also AbstractModel, SoleLogics.CONJUNCTION, joinrules, listimmediaterules, LeafModel.

source
SoleModels.submodelsMethod
submodels(m::AbstractModel)

Enumerate all submodels in the sub-tree. This function is the transitive closure of immediatesubmodels; in fact, the returned list includes the immediate submodels (immediatesubmodels(m)), but also their immediate submodels, and so on.

Examples

julia> using SoleLogics

julia> branch = Branch(SoleLogics.parseformula("p∧q∨r"), "YES", "NO");

julia> submodels(branch)
2-element Vector{SoleModels.ConstantModel{String}}:
 ConstantModel
YES

 ConstantModel
NO


julia> branch2 = Branch(SoleLogics.parseformula("s→p"), branch, 42);

julia> printmodel.(submodels(branch2));
Branch
┐ p ∧ (q ∨ r)
├ ✔ YES
└ ✘ NO

ConstantModel
YES

ConstantModel
NO

ConstantModel
42

julia> submodels(branch) == immediatesubmodels(branch)
true

julia> submodels(branch2) == immediatesubmodels(branch2)
false

See also AbstractModel, immediatesubmodels, LeafModel.

source