Calling Prolog from php

Hey guys, im a newbie to prolog and got a question for which i cant find an answer by myself.
First of all my idea is to create a wordpress plugin, where the user can create some rules and facts which should than be progressed by prolog.
So my question is:
Is it possible to create rules and facts over a http request for example? So my php code creates those rules and facts and also takes inputs-> send them to prolog → and send the results back to php?

Do you guys have any tutorial or lecture about this where i can learn this, if this is even possbile.

Thank you very much :slight_smile:

1 Like

SWISH does this.

GitHub repository: SWISH

@ericzinda was considering adding support for websockets to the machine query interface; if he adds that, you will be able to easily call swiprolog from php using simple json to make queries and get results.

EDIT: you can also use pengines but that is a little harder and you have to worry about sandboxing, etc.

hey thank you. So the machine query inferface stuff isnt working/impletemted yet?
Is there no easy way to achive this? I mean isnt prolog only usefull if we can communicate with different services and apis?
Here is an diagram what i want to achive, i thought this couldnt be that hard…

See this answer for the PHP code in this rather long thread, where we attempted to help to publish on a standard PHP server a Prolog solver.

HTH

This can surely all be done. A key issue is how to deal with security and isolation of different clients. Prolog is a general purpose programming language that can access anything that it is authorized to by the OS. Roughly there are two possible scenarios. One is to use the Pengine infrastructure, either directly or reusing (part of) (previously mentioned) SWISH. That solves the security problem using sandboxing and the isolation problem using a thread and temporary module to deal with a client. The Pengines server acts as an HTTP server that talks either Prolog or JSON.

Alternatively you could create a Prolog instance per task that is sandboxed by the OS. That is certainly doable. I don’t know about a ready-to-go solution there. With some effort you can probable use @ericzinda’s MQI to solve part of the problem.

If my picture of what you want is correct, I think the Pengine approach is the most promising.

thank you, i will try to understand all those possible solutions.
Security doesnt matter in my case. It should just be a proof of concept to understand it and to work on it in the future. Im just looking for the simplest solution to achive this logic.

Pengines is probably still a reasonable choice to look into. It basically provides an HTTP server. You send it a request to create a query given some source code that you can provide as a string or URL from which to download the source. The source is loaded into an isolated environment. The sandbox (which you can disable) computes the reachable call tree from the query and verifies it only contains whitelisted predicates. It than runs the query and returns the result, typically as JSON. If the result is non-deterministic you can ask for the next, etc. or stop. Queries are isolated from each other and the server does not maintain any state after the query completes.

@Jrdn40

FYI

Since you note im a newbie to prolog and this is actually more of a second semester entire semester project than a first semester chapter exercise this will take some time to understand; here are some pointers.

  1. The SWI-Prolog documentation is not written to give examples. It notes

This document is a reference manual . That means that it documents the system, but it does not explain the basics of the Prolog language and it leaves many details of the syntax, semantics and built-in primitives undefined where SWI-Prolog follows the standards. This manual is intended for people that are familiar with Prolog.

So don’t expect to find working code examples in the documentation.

  1. While Pengines (source) is a high level construct that is close to what you need,

Note: I use dark mode which makes the next two images very hard to see. To see them I right click on them and open in a new browser tab.

image

image

you will most likely be working and living in the code from the http libraries. (ref)

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_server_files)).
:- use_module(library(http/http_files)).
:- use_module(library(pengines)).
:- use_module(pengine_sandbox:library(pengines)).
  1. I find that seeing working examples is one of the best ways to understand the code. The best way I know to find working examples is to
    a. Look for examples in the supplied code. pengine has an example directory. (examples)
    b. Look for others who have published code on GitHub. The key to find such code is to search for a word that is unique.
    pengines - pengine_create/1 (GitHub search).
    web sockets - ws_receive/2 (GitHub search).
    For going lower into code I like to search the library http_dispatch (GitHub search)
    Understand that code in the wild my be good as an example or may be horrible as an example. It is a learned skill to know which. List of GitHub accounts with quality Prolog code.

  2. Ask questions here. While you can ask on StackOverflow, StackOverflow is not really a great place to solve a problem that may need a discussion. Also it is better to ask than not to ask. The worse that can happen is that your question will not get answered. Even my questions sometimes don’t get any reply, don’t take it personally.

  3. Expect to be very frustrated often and for a long time, a week or more. Remeber that one learns more from failure than success.

    “The master has failed more times than the beginner has even tried.” - Stephen McCranie

  4. If you use machine query interface realize that it is only a few months old (ref) and I don’t know of any other examples than the one by the creator (Eric Zinda). If you choose this odds are we will be learning more from you about MQI but you will be learning Prolog from us.

  5. Don’t get bogged down in premature optimization. Get the code working correctly first, no matter how bad the code looks and/or how in effective the data structures are, then once you have it all working correctly focus on optimizations. Intel even expands on this idea. (ref)

HTH

1 Like

I put some notes on getting simple Prolog and Erlang scripts to communicate via websocket at erlang-webapp-howto/unit7 at master · roblaing/erlang-webapp-howto · GitHub

I did an example of using Prolog as the server and as the client, and the Erlang code should be replaceable with any language with websocket support.

4 Likes

If you are looking for something quick and dirty @joeblog example is the quickest (copied from his link above):

Write this in pong.pl:

:- use_module(library(http/websocket)).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- http_handler(root(pong), http_upgrade_to_websocket(pong_handler, []), [spawn([])]).

server(Port) :-
  http_server(http_dispatch, [port(Port)]).

pong_handler(Request) :-
  ws_receive(Request, Message),
  debug(websocket, "Got ~p~n", [Message]),
  format("Received ~p~n", [Message]),
  (   Message.opcode == close
  ->  ws_send(Request, close(1000, "Bye")),
      format("Pong finished~n")
  ;   ws_send(Request, text("Pong")),
      format("Sent Pong~n"),
      pong_handler(Request)
  ).

Now in a terminal run:

$ swipl -g 'server(8001)' pong.pl

while running this in another terminal:

$ websocat ws://127.0.0.1:8001/pong                                                   09:26:51  ✔ 0 
hello
Pong
hi
Pong
goodbye
Pong

You’ll get this output:

$ swipl -g 'server(8001)' t.pl
% Started server at http://localhost:8001/
1 ?- Received websocket{data:"hello\n",format:string,opcode:text}
Sent Pong
Received websocket{data:"hi\n",format:string,opcode:text}
Sent Pong
Received websocket{data:"goodbye\n",format:string,opcode:text}
Sent Pong
Received websocket{code:1000,data:"",format:string,opcode:close}
Pong finished

From there you can easily see how to connect with the server using php and websockets.

3 Likes

I agree with @jan that I’d start with Penguines. The MQI interface gives you full access to the power of Prolog, which can basically do anything. You could certainly use the MQI with PHP since PHP has support for regular old sockets, how to go about it is described here. But: you’ll need to build the right security and server infrastructure around it and penguines already has that.

This might be similar to what you want – it’s a sample JavaScript client that communicates with a Prolog server, sending a query and displaying the result. It has zero security and allows any Prolog command (e.g., you can use assertz/1 to create facts).

Thank you guys for all these recommendations. I really appreciate it. This community is awesome!
I will check all of these and choose the one which best suites my needs. Thanks!

Hi,
Again, thanks for the kind help you gave to publish this Prolog solver. It works fine.
But I just tried to use this example to adapt it for other solvers, and nothing worked.
For a similar Quine prover working not with variables (upper case letter A), but with lower case, I get:

there was a problem:{"proof":"","formula":"TBD"}

It is not an easy task.

By the way, I got a successful result with fCube-verbose.pl prover on this website:
https://rextester.com/SEOO25214
Unfortunately, the same code failed on SWISH. :frowning:

I’m sorry, without more details cannot say anything… seems it’s not a PHP problem.

Here PHP returns to Javascript the Prolog_script’ result

   ...
   header('Content-type: application/json');
   echo json_encode(['proof'=>$Proof,'formula'=>'TBD']);
   ...

Here Javascript just exposes the outcome of the remote call (from a browser to your server)

     let result = await request("<?=$_SERVER['REQUEST_URI']?>", f)
      if (result.proof)
        proof_show.textContent = result.proof
      else
        proof_show.innerHTML = 'there was a problem:<b>'+JSON.stringify(result)+'<b>'

You should check on the server, from inside the Prolog script, why the result.proof is empty…

I would start verifying that a trace is actually doable, since the basic security policies on servers usually forbid to write in public accessible places…

Yes, you are right. It was not a PHP problem. I had just forgotten to declare a Prolog predicate in “module” at the top of the prolog file, and it work now ! I am very sorry to waste your time. Many thanks again.

1 Like

I noticed that the vertical bar used by TPTP syntax to translate the disjunction operator (eg ~ A | A ) prevents a correct output for the same Quine prover online : with

:- module(quineweb,
          [quine/0,
           getFormula/4,
	   op(700, xfy, <=>),
	   op(600, xfy, =>),
	   op(500, xfy, '|'),
	   op(400, xfy, &),
	   op(300, fy, ~)
          ]).

and whith replacing v by a bar in the clauses, one gets:

there was a problem:{“proof”:“”,“formula”:“TBD”}

This problem does not appear with the Prolog compiler online https://rextester.com/ , but it is also probably a problem with pengines. It is a pity for the syntax adopted by the logicians and computer scientists who published a lot of logical problems for provers… :frowning:

I add a correction to what I wrote: in fact, with adding round brackets to avoid confusion, using a bar instead of v works also fine. It was therefore a minor problem. I will publish soon online my work on fCube.

Sorry, I don’t fully understand the problem… (maybe Jan Burse could help ?)

If you run

?- setof(r(Z,P,A),current_op(P,A,Z),L),maplist(writeln,L).
...
r(1100,;,xfy)
r(1105,|,xfy)
r(1150,discontiguous,fx)
...

You can see that the default precedence is set to 1105, pretty high. Could be that lowering it to 500 changes some formula meaning ?

Yes, here his the code wich works, to use the bar as symbol of disjunction (Jan Burse as Prolog programmer disagrees with this use, I remember it, but I prefer this TPTP convention over Prolog’s). For example, for fCube prover that I am going to publish online, I have this:

:- module(fcubeweb,
          [fcube/0,
           decide/1,
	   op(1200, xfy, <=>),
	   op(1110, xfy, =>),
	   op(1100, xfy, '|'),
	   op(1000, xfy, &),
	   op(500, fy, ~)
          ]).

And, with taking care of writing disjunctions in clauses with round brackets, it works perefectly well.
(I remember that, if the bar symbol for disjunction if set lower, Prolog does not agree.)