Skip to content

ProbLog Integrations

problog logo

Bases: Solver

A solver that uses problog.

problog is a probabilistic logic programming language.

Example:

>>> from typedlogic.integrations.frameworks.pydantic import FactBaseModel
>>> from typedlogic import SentenceGroup, PredicateDefinition, Forall, Variable
>>> solver = ProbLogSolver()
>>> solver.add_predicate_definition(PredicateDefinition(predicate="AncestorOf", arguments={'ancestor': 'str', 'descendant': 'str'}))
>>> x = Variable('x')
>>> y = Variable('y')
>>> z = Variable('z')
>>> tr_axiom = Forall([x, y, z], (Term('AncestorOf', x, y) & Term('AncestorOf', y, z)) >> Term('AncestorOf', x, z))
>>> solver.add_sentence(tr_axiom)
>>> solver.add_probabilistic_fact(Term('AncestorOf', 'p1', 'p1a'), 0.5)
>>> solver.add_probabilistic_fact(Term('AncestorOf', 'p1a', 'p1aa'), 0.5)
>>> model = solver.model()
>>> print(model.term_probabilities[Term('AncestorOf', 'p1', 'p1aa')])
0.25
Source code in src/typedlogic/integrations/solvers/problog/problog_solver.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@dataclass
class ProbLogSolver(Solver):
    """
    A solver that uses problog.

    [problog](https://dtai.cs.kuleuven.be/problog/index.html) is a
    probabilistic logic programming language.

    Example:

        >>> from typedlogic.integrations.frameworks.pydantic import FactBaseModel
        >>> from typedlogic import SentenceGroup, PredicateDefinition, Forall, Variable
        >>> solver = ProbLogSolver()
        >>> solver.add_predicate_definition(PredicateDefinition(predicate="AncestorOf", arguments={'ancestor': 'str', 'descendant': 'str'}))
        >>> x = Variable('x')
        >>> y = Variable('y')
        >>> z = Variable('z')
        >>> tr_axiom = Forall([x, y, z], (Term('AncestorOf', x, y) & Term('AncestorOf', y, z)) >> Term('AncestorOf', x, z))
        >>> solver.add_sentence(tr_axiom)
        >>> solver.add_probabilistic_fact(Term('AncestorOf', 'p1', 'p1a'), 0.5)
        >>> solver.add_probabilistic_fact(Term('AncestorOf', 'p1a', 'p1aa'), 0.5)
        >>> model = solver.model()
        >>> print(model.term_probabilities[Term('AncestorOf', 'p1', 'p1aa')])
        0.25

    """

    exec_name: str = field(default="problog")
    profile: ClassVar[Profile] = MixedProfile(Probabilistic(), AllowsComparisonTerms(), MultipleModelSemantics())

    def models(self) -> Iterator[ProbabilisticModel]:
        compiler = ProbLogCompiler()
        program = compiler.compile(self.base_theory)
        p = PrologString(program)
        ev = get_evaluatable()
        result = ev.create_from(p).evaluate()
        m = ProbabilisticModel()
        for term, prob in result.items():
            plt_term = compiler.decompile_term(term)
            reified = Probability(prob, That(plt_term))
            reified_as_term = reified.to_model_object()
            if not isinstance(reified_as_term, Term):
                raise ValueError(f"Expected a term, got {reified_as_term}")
            m.ground_terms.append(reified_as_term)
            m.term_probabilities[plt_term] = prob
        yield m

    def model(self) -> ProbabilisticModel:
        models = list(self.models())
        if len(models) == 0:
            raise NotInProfileError("No models found")
        if len(models) > 1:
            raise NotInProfileError("Multiple models found")
        return models[0]

    def check(self) -> Solution:
        models = list(self.models())
        sat = len(models) > 0
        return Solution(satisfiable=sat)

    def dump(self) -> str:
        compiler = ProbLogCompiler()
        return compiler.compile(self.base_theory)

    def add_probabilistic_fact(self, fact: Sentence, probability: float) -> None:
        pr_sent = Probability(probability, That(fact))
        self.add(pr_sent)

    def add_evidence(self, fact: Sentence, truth_value: bool) -> None:
        ev = Evidence(fact, truth_value)
        self.add(ev)