Prolog: predicate for maximum without accumulator

后端 未结 2 485
死守一世寂寞
死守一世寂寞 2021-01-18 06:17

Is it possible to create a predicate max/2 without an accumulator so that max(List, Max) is true if and only if Max is the ma

2条回答
  •  梦毁少年i
    2021-01-18 06:23

    Neither the standard predicate is/2 nor a CLP(FD) predicate (#=)/2 can do mathematics here. So that in the end, for certain applications such as exact geometry, they might not be suitable.

    To make a point lets consider an example and the alternative of a computer algebra system (CAS). I am doing the demonstration with the new Jekejeke Minlog 0.9.2 prototype which provides CAS from within Prolog.

    As a preliminary we have two predicates eval_keys/2 and min_key/2, their code is found at the appendix in this post. Lets illustrate what this predicates do, first with integer. The first predicate just makes the keys of a pair list evaluated:

    Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.25-3-gc3a87c2)
    Copyright (c) 1990-2016 University of Amsterdam, VU Amsterdam
    
    ?- eval_keys([(1+3)-foo,2-bar],L).
    L = [4-foo,2-bar]
    

    The second predicate picks this first value where the key is minimum:

    ?- min_key([4-foo,2-bar],X).
    X = bar
    

    Now lets look at other key values, we will use square roots, which belong to the domain of algebraic numbers. Algebraic numbers are irrational and thus never fit into a float. We therefore get for the new example the outcome foo:

    ?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
    L = [20000.62724016424-foo, 20000.627240164245-bar].
    
    ?- min_key([20000.62724016424-foo, 20000.627240164245-bar], X).
    X = foo.
    

    CLP(FD) has only integers and there is no direct way to represent algebraic numbers. On the other hand many CAS systems support radicals. Our Prototype even supports comparison of them so that we can obtain the exact result bar:

    Jekejeke Prolog 2, Runtime Library 1.2.2
    (c) 1985-2017, XLOG Technologies GmbH, Switzerland
    
    ?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
    L = [radical(0,[98428513-1,101596577-1])-foo,
       radical(0,[400025090-1])-bar]
    
    ?- min_key([radical(0,[98428513-1,101596577-1])-foo,
       radical(0,[400025090-1])-bar],X).
    X = bar
    

    That bar is the exact result can be seen for example by using a multi-precision calculator. If we double the precision we indeed see that the last square root is the smaler one and not the sum of the square roots:

    ?- use_module(library(decimal/multi)).
    % 7 consults and 0 unloads in 319 ms.
    Yes
    
    ?- X is mp(sqrt(98428513)+sqrt(101596577), 32).
    X = 0d20000.627240164244658958331341095
    
    ?- X is mp(sqrt(400025090), 32).
    X = 0d20000.627240164244408966171597261
    

    But a CAS need not to proceed this way. For example our Prolog implementation uses a Swinnerton-Dyer polynomial inspired method to compare radical expressions, which works purely symbolic.

    Appendix Test Code:

    % :- use_module(library(groebner/generic)). /* to enable CAS */
    
    eval_keys([X-A|L], [Y-A|R]) :- Y is X, eval_keys(L, R).
    eval_keys([], []).
    
    min_key([X-A|L], B) :- min_key(L, X, A, B).
    
    min_key([X-A|L], Y, _, B) :- X < Y, !, min_key(L, X, A, B).
    min_key([_|L], X, A, B) :- min_key(L, X, A, B).
    min_key([], _, A, A).
    

提交回复
热议问题