Collect all “minimum” solutions from a predicate

后端 未结 3 1665
遇见更好的自我
遇见更好的自我 2020-11-30 14:17

Given the following facts in a database:

foo(a, 3).
foo(b, 2).
foo(c, 4).
foo(d, 3).
foo(e, 2).
foo(f, 6).
foo(g, 3).
foo(h, 2).

I want to

3条回答
  •  半阙折子戏
    2020-11-30 14:55

    I don't think that library(aggregate) covers your use case. aggregate(min) allows for one witness:

    min(Expr, Witness) A term min(Min, Witness), where Min is the minimal version of Expr over all solutions, and Witness is any other template applied to solutions that produced Min. If multiple solutions provide the same minimum, Witness corresponds to the first solution.

    Some time ago, I wrote a small 'library', lag.pl, with predicates to aggregate with low overhead - hence the name (LAG = Linear AGgregate). I've added a snippet, that handles your use case:

    integrate(min_list_associated, Goal, Min-Ws) :-
        State = term(_, [], _),
        forall(call(Goal, V, W),    % W stands for witness
            (    arg(1, State, C),  % C is current min
                 arg(2, State, CW), % CW are current min witnesses
                 (   ( var(C) ; V @< C )
                 ->  U = V, Ws = [W]
                 ;   U = C,
                     (   C == V
                     ->  Ws = [W|CW]
                     ;   Ws = CW
                     )
                 ),
                 nb_setarg(1, State, U),
                 nb_setarg(2, State, Ws)
            )),
        arg(1, State, Min), arg(2, State, Ws).
    

    It's a simple minded extension of integrate(min)... The comparison method it's surely questionable (it uses less general operator for equality), could be worth to adopt instead a conventional call like that adopted for predsort/3. Efficiency wise, still better would be to encode the comparison method as option in the 'function selector' (min_list_associated in this case)

    edit thanks @false and @Boris for correcting the bug relative to the state representation. Calling nb_setarg(2, State, Ws) actually changes the term' shape, when State = (_,[],_) was used. Will update the github repo accordingly...

提交回复
热议问题