Использование (nb_)setarg/3 с gnu.prolog в Java

В настоящее время я пытаюсь использовать пролог из java с помощью gnu.prolog (http://www.gnu.org/software/gnuprologjava/).

Благодаря большой помощи CapelliC теперь у меня есть программа на прологе, которая идеально подходит для моей цели. Проблема в том, что gnu.prolog не поддерживает ни reverse/2, ни nb_setarg/3. Java выдаст ошибку:

Exception in thread "Game" java.lang.IllegalArgumentException: The goal is not currently active

Реализовать reverse/2 самостоятельно не составляет большого труда, но я понятия не имею, как заменить nb_setarg/3 (setarg/3 тоже не работает)

Вот мой код пролога:

findPath(_Limit, [Goal | Rest], Goal, Temp, Temp, [Goal | Rest]) :- !.

findPath(Limit, [A | Rest], Goal, Cost, Temp, Path) :-
    path(A,B,C),
    \+member(B, Rest),
    NewCosts is (Temp + C),
    NewCosts < Limit,
    findPath(Limit, [B, A | Rest], Goal, Cost, NewCosts, Path).

searchPath(Start, Goal, Path_to_goal) :-
    S = path_len([], 50),
    repeat,
    arg(2, S, Limit),
    (   findPath(Limit, [Start], Goal, Cost, 0, Path)
    ->  (   Cost < Limit
        ->  nb_setarg(1, S, Path),
        nb_setarg(2, S, Cost),
        fail
        )
    ;   true
    ),
    arg(1, S, Rev),
    reverse(Rev, Path_to_goal).

Я пытался использовать JPL из SWI Prolog, но не смог запустить его из-за нескольких исключений, указывающих на то, что Eclipse не смог правильно найти библиотеку. Я всегда получаю одно из следующих исключений:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jpl in java.library.path


UnsatisfiedLinkError: D:\Program Files\Prolog\bin\jpl.dll: Can't find dependent libraries

SWI-Prolog: [FATAL ERROR:
    Could not find system resources]

Даже после выполнения этого и это руководство Мне не удалось решить свои проблемы. Ни в Windows (32-битная), ни в Ubuntu (64-битная).

У вас есть решения для меня, как я могу запустить JPL или как использовать nb_setarg/3? До сих пор я провел полтора дня без каких-либо результатов. Довольно неприятно...


person Markus    schedule 05.04.2013    source источник
comment
Я полагаю, вы хотите использовать глобальную переменную GNU Prolog вместо средства SWI. . Поэтому попробуйте вместо этого g_assign/2 и g_read/2.   -  person Daniel Lyons    schedule 05.04.2013


Ответы (2)


Извините, но мое предложение использовать GProlog setarg вместо SWI-Prolog nb_setarg было неверным. Сейчас я переработал код более простым и (надеюсь) более эффективным способом, работающим под любым ISO Prolog.

% this data is from original Prolog Dijkstra' algorithm implementation
:- initialization( consult(salesman) ).

:- dynamic(best_so_far/2).

path(X,Y,Z) :- dist(X, Y, Z).
path(X,Y,Z) :- dist(Y, X, Z).

findPath([Goal | Rest], Goal, Temp, Temp, [Goal | Rest]) :-
    !.
findPath([A | Rest], Goal, Cost, Temp, Path) :-
    path(A, B, C),
    \+ member(B, Rest),
    NewCost is Temp + C,
    best_so_far(Limit, _),
    NewCost < Limit,
    findPath([B, A | Rest], Goal, Cost, NewCost, Path).

% ?- searchPath(aberdeen, glasgow, L, P).
%
searchPath(Start, Goal, BestLen, BestPath) :-
    retractall(best_so_far(_, _)),
    asserta(best_so_far(1000000, [])),
    findPath([Start], Goal, Cost, 0, Path),
    % if we get here, it's because a lower Cost exists
    retractall(best_so_far(_, _)),
    asserta(best_so_far(Cost, Path)),
    fail
    ;
    best_so_far(BestLen, BestPath).

Если вы хотите немного ускориться, есть очень простая эвристика, которая должна быть применима: а именно сделать findPath жадным, выбирая ветки с более низкой стоимостью. Это можно сделать с помощью setof+member...

person CapelliC    schedule 05.04.2013
comment
Даже если retractall/1 указан в Руководстве по GNU-Prolog, на которое ссылается Даниэль, он все равно терпит неудачу, когда дело доходит до этой команды. retract/1 однако работает. Поэтому теперь я заменил retractall на retract_all, тогда как retract_all имеет следующую реализацию: retract_all(Term):- retract(Term),fail. втянуть_все (_). Теперь код работает. Но запуск этого кода в SWI Prolog возвращает результат через 0,016 секунды. Запуск точно такого же кода в Java возвращает результат более чем за 15 секунд... - person Markus; 06.04.2013
comment
Я также понял, что java в какой-то момент дает разные результаты!!! Пожалуйста, смотрите мой ответ ниже. - person Markus; 06.04.2013

Я схожу с ума от этого...

Как я уже упоминал выше, есть некоторые различия между Прологом на Java и Прологом через SWI.

В настоящее время я использую этот код:

% this data is from original Prolog Dijkstra' algorithm implementation
:- dynamic(best_so_far/2).


findPath([Goal | Rest], Goal, Temp, Temp, [Goal | Rest]) :-
    !.
findPath([A | Rest], Goal, Cost, Temp, Path) :-
    path(A, B, C),
    \+ member(B, Rest),
    NewCost is Temp + C,
    best_so_far(Limit, _),
    NewCost < Limit,
    findPath([B, A | Rest], Goal, Cost, NewCost, Path).

% ?- searchPath(aberdeen, glasgow, L, P).
%
searchPath(Start, Goal, BestLen, BestPath) :-
    retract_all(best_so_far(_, _)),
    asserta(best_so_far(50, [])),
    findPath([Start], Goal, Cost, 0, Path),
    % if we get here, it's because a lower Cost exists
    retract_all(best_so_far(_,_)),
    asserta(best_so_far(Cost, Path)),
    fail
    ;
    best_so_far(BestLen, BestPath).


retract_all(Term):-
    retract(Term),fail.
retract_all(_).

Запрашивая результат в SWI Prolog, я получу ответ через 0,016 секунды. Java требуется 15 секунд для того же результата!

Более того и даже хуже: в какой-то момент gnu prolog дает совершенно другой результат.

Вот некоторая схема Java:

From 190 to 221
pathList: [221, 191, 190]
distance: 2

From 191 to 221
pathList: [221, 251, 252, 253, 223, 193, 194, 195, 196, 197, 198, 199, 169, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 151, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191]
distance: 43

From 190 to 221
pathList: [221, 191, 190]
distance: 2

Вы можете ясно видеть, что есть путь от 191 до 221. Но вместо того, чтобы вернуть этот результат (pathList: [221,191]), я получаю совершенно другой путь, ведущий назад, откуда пришел мой призрак. Выполнение запроса searchPath(191,221, Distance, Path) в SWI Prolog (мгновенно) возвращает

7 ?- searchPath(191,221, Cost, Path).
Cost = 1,
Path = [221, 191].

Еще раз: я использую тот же самый код. Я скопировал и вставил его, чтобы убедиться. И я передаю правильные аргументы (поэтому я их распечатываю).

Я действительно не знаю, как вас отблагодарить (особенно CapelliC). Я уверен, что вы и так потратили на меня слишком много времени. Но я определенно не в себе.

Изменить: подумал, что было бы полезно увидеть мой код Java:

private int decideHunterMovement() {
        // term which contains the result of the prolog method
        VariableTerm pathTerm = new VariableTerm("Path");
        VariableTerm distanceTerm = new VariableTerm("Distance");
        Integer movement;
        List<IntegerTerm> pathList = new LinkedList<IntegerTerm>();

        // Create the arguments to the compound term which is the question
        IntegerTerm hunterPosition = new IntegerTerm(hunter.getPosition());
        IntegerTerm targetPosition = new IntegerTerm(pacman.getPosition()); // target for hunter is the pacman position

        long time= System.nanoTime ();
        Term[] arguments = { hunterPosition, targetPosition, distanceTerm, pathTerm};
        // Construct the question
        CompoundTerm goalTerm = new CompoundTerm(AtomTerm.get("searchPath"), arguments);
        // Execute the goal and return the return code.
        int rc;
        System.out.println("From " + hunterPosition + " to " + targetPosition);
        try{
            // Create the answer
            rc = interpreter.runOnce(goalTerm);
            time = (System.nanoTime () - time) / 1000 / 1000;
            System.out.println("Result in:" + time+ "ms");
            // If it succeeded.
            if (rc == PrologCode.SUCCESS || rc == PrologCode.SUCCESS_LAST){
                // Get hold of the actual Terms which the variable terms point to
                Term path = pathTerm.dereference();
                Term distance = distanceTerm.dereference();
                // Check it is valid
                if (path != null){
                    if (path instanceof CompoundTerm){
                        // convert CompoundTerm to a Java LinkedList
                        convertToList((CompoundTerm) path, pathList);
                        if(VERBOSE_MODE){
                            System.out.println("pathList: " + pathList);
                            System.out.println("distance: " + (IntegerTerm) distance + "\n");
                        }
                    }else{
                            throw new NoAnswerException("PROLOG ERROR: Answer is not a CompundTerm: (" + path + ")");
                    }
                }else{
                    throw new NoAnswerException("PROLOG ERROR: Answer null when it should not be null");
                }
            }else{
                throw new NoAnswerException("PROLOG ERROR: Goal failed");
            }
        } catch (NoAnswerException e) {
            e.printStackTrace();
        } catch (PrologException e1) {
            e1.printStackTrace();
        }

        movement = decideMovement(pathList);
        return movement;
    }
person Markus    schedule 06.04.2013
comment
Наконец-то мне удалось использовать JPL из SWI Prolog. С этим фреймворком все работает нормально... - person Markus; 08.04.2013
comment
Настройка такой среды может быть болезненной, но в перспективе это полезный шаг. - person CapelliC; 08.04.2013