Algebraic ProbLog (semirings)

Algebraic ProbLog is an extension to ProbLog where you can define your own semirings to define the arithmetic operations (instead of addition and multiplication). The details are available in:

  • A. Kimmig, G. Van den Broeck and L. De Raedt. An algebraic Prolog for reasoning about possible worlds. Proceedings of the Twenty-Fifth AAAI Conference on Artificial Intelligence, pp. 209 - 214, AAAI Press, 2011. PDF
  • Setup

    To define a custom semiring, load the aproblog module and define the operations using the use_semiring predicate.

    :- use_module(library(aproblog)).
    
    :- use_semiring(
        sr_plus,   % addition (arity 3)
        sr_times,  % multiplication (arity 3)
        sr_zero,   % neutral element of addition (arity 1)
        sr_one,    % neutral element of multiplication (arity 1)
        sr_neg,    % negation of fact label (arity 2)
        true,      % requires solving disjoint sum problem?
        false).    % requires solving neutral sum problem?
    

    Your program should then include definitions for each of the sr_* predicates. This also allows you to use arbitrarily complex weights, that is, any Prolog term is a valid weight as long as it is accepted by the operators you define.

    The last two arguments specify whether this semiring requires solving the disjoint and neutral sum problems.

    • The disjoint sum problem occurs when plus is not idempotent (that is \(a \oplus a \not \equiv a\)).
    • The neutral sum problem occurs when \(a \oplus \mathit{neg}(a) \not \equiv e^\otimes\).

    ProbLog will produce results no matter which flags you set (they just might not be what you expect).

    Example: the probability semiring

    The default semiring used by ProbLog is the probability semiring. The weights are numbers between 0 and 1 and the semiring operations can be defined as shown in the following model.

    For this semiring, we need to address the disjoint sum problem (because \(p + p \not \equiv p\)), but not the neutral sum problem (because \(p + (1-p) \equiv 1\)).

    :- use_module(library(aproblog)). :- use_semiring( sr_plus, % addition (arity 3) sr_times, % multiplication (arity 3) sr_zero, % neutral element of addition sr_one, % neutral element of multiplication sr_neg, % negation of fact label true, % requires solving disjoint sum problem? false). % requires solving neutral sum problem? sr_zero(0.0). sr_one(1.0). sr_plus(A, B, C) :- C is A + B. sr_times(A, B, C) :- C is A * B. sr_neg(A, B) :- B is 1 - A. % An example program: 0.6::edge(1,2). 0.1::edge(1,3). 0.4::edge(2,5). 0.3::edge(2,6). 0.3::edge(3,4). 0.8::edge(4,5). 0.2::edge(5,6). path(X,Y) :- edge(X,Y). path(X,Y) :- edge(X,Z), path(Z,Y). query(path(1,6)).

    Example: Most Probable Explanation

    ProbLog has a special mode for computing the most probable explanation (MPE), that is, the most probable possible world in which a given observation is true.

    In the simple version that only computes the probability of the most probable world, the operators are defined as \(\oplus = \max\) and \(\otimes = \cdot\).

    The model below also returns the truth values of the relevant facts in that most probable world. In this semiring we use weights of the form s(Probability, ListOfFacts).

    In this semiring, we have no disjoint sum problem (because \(\max(a, a) \equiv a\)), but we do have to address the neutral sum problem (because \(\max(a, (1-a)) \not \equiv 1\)).

    :- use_module(library(aproblog)). :- use_module(library(lists)). :- use_semiring( sr_mpestate_plus, % addition (arity 3) sr_mpestate_times, % multiplication (arity 3) sr_mpestate_zero, % neutral element of addition sr_mpestate_one, % neutral element of multiplication sr_mpestate_neg, % negation of fact label false, % requires solving disjoint sum problem? true). % requires solving neutral sum problem? % MPE+state semiring sr_mpestate_zero(s(0.0, [])). sr_mpestate_one(s(1.0, [])). sr_mpestate_plus(s(VA, SA), s(VB, SB), s(VA, SA)) :- VA > VB. sr_mpestate_plus(s(VA, SA), s(VB, SB), s(VB, SB)) :- VA < VB. sr_mpestate_plus(s(VA, SA), s(VB, SB), s(VA, SC)) :- VA == VB, append(SA, SB, SC1), sort(SC1, SC). sr_mpestate_times(s(VA, SA), s(VB, SB), s(VC, SC)) :- VC is VA*VB, append(SA, SB, SC1), sort(SC1, SC). sr_mpestate_neg(s(V, [K]), s(V1, [\+K])) :- V1 is 1.0 - V. s(0.6, [edge(1,2)])::edge(1,2). s(0.1, [edge(1,3)])::edge(1,3). s(0.4, [edge(2,5)])::edge(2,5). s(0.3, [edge(2,6)])::edge(2,6). s(0.3, [edge(3,4)])::edge(3,4). s(0.8, [edge(4,5)])::edge(4,5). s(0.2, [edge(5,6)])::edge(5,6). path(X,Y) :- edge(X,Y). path(X,Y) :- edge(X,Z), path(Z,Y). query(path(1,6)).

    Example: Negation without Negation

    David Buchman and David Poole introduced an alternative representation of probabilities called probability-strengths to express a more intuitive notion of negation in logic programming (and allow for negated effects in cycles):

    • David Buchman and David Poole, Negation Without Negation in Probabilistic Logic Programming, International Conference on the Principles of Knowledge Representation and Reasoning (KR), 2016
    • David Buchman and David Poole, Negation Without Negation in Probabilistic Logic Programming, International Journal of Approximate Reasoning, 2016

    The ideas of Buchman and Poole can be easily implemented in ProbLog using a semiring. We use the s/1 function the wrap a probability-strength and the corresponding probability as p/1. This means that s(S) and p(P) are related as follows: \(P = 1-e^{-S}\) (non-wrapped weights are assumed to be probabilities but you could as well use probability-strenghts as the default to avoid the s/1 function).

    :- use_module(library(aproblog)). :- use_module(library(lists)). :- use_semiring( sr_plus, % addition (arity 3) sr_times, % multiplication (arity 3) sr_zero, % neutral element of addition (arity 1) sr_one, % neutral element of multiplication (arity 1) sr_neg, % negation of fact label (arity 2) true, % requires solving disjoint sum problem? true). % requires solving neutral sum problem? s(0.6931471805599453)::n1. % Wrap a probability-strenght in a function s s(1.203972804325936)::n2. s(-0.8472978603872034)::n3. s(0.7)::n4. s(-0.7)::n5. % inverse probability-strenghts cancel each other a :- n1. b :- n2. b :- n3, a. c :- n4. c :- n5. query(a). query(b). query(c). % MPE+state semiring sr_zero(p(0.0)). sr_one(p(1.0)). sr_plus(s(VA), s(VB), p(V)) :- V is (1-exp(-VA)) + (1-exp(-VB)). sr_plus(s(VA), p(VB), p(V)) :- V is (1-exp(-VA)) + VB. sr_plus(p(VA), s(VB), p(V)) :- V is VA + (1-exp(-VB)). sr_plus(p(VA), p(VB), p(V)) :- V is VA + VB. sr_times(s(VA), s(VB), p(V)) :- V is (1-exp(-VA)) * (1-exp(-VB)). sr_times(s(VA), p(VB), p(V)) :- V is (1-exp(-VA)) * VB. sr_times(p(VA), s(VB), p(V)) :- V is VA * (1-exp(-VB)). sr_times(p(VA), p(VB), p(V)) :- V is VA * VB. sr_neg(s(V), p(V1)) :- V1 is exp(-V). sr_neg(p(V), p(V1)) :- V1 is 1.0 - V.