Quick introduction =================== 1) Getting and installing: The newest tar gz can be downloaded from: wwwhome.cs.utwente.nl/~schooten/yprolog/ Untar with: tar zxvf yprolog-.tar.gz 2) Prolog examples can be found in yprolog/examples: - util.pro : which contains the classic "append" and "member" predicates - path.pro : original XProlog benchmark program; depth-first exploration of maze. - evilfinder.pro : new benchmark using numbers; find out how your number can be rewritten to the number of the beast! 3) Try YProlog with "util.pro". Start YProlog with the file as argument: java -jar YProlog.jar yprolog/examples/util.pro - List the predicates [Note: in the examples below, DON'T type the prompt "?-" ] ?- listing. ?- listing(full). % to see the loaded primitives - try unifications. ?- X = t(1,fred). ?- t(_,X) = t(1,fred). ?- X=t(1,fred), X=t(Z,Z). % should fail - try "append" ?- append( A,B, [red,white,blue]). % answer "y" to get more answers - try "member" ?- member( Num, [1,2,3,5,7,8,22,17]), Num>4, Num<10. - add facts and list them ?- member( W, [marie,helen,jane]), assert( woman(W)), fail. ?- listing( woman(_)). ?- woman(jane). ?- woman(sue). % should fail - Benchmark program: load it then try it. ?- consult( 'yprolog/examples/path.pro'). ?- solve(p(8,8),L). % if this works in 5 sec or less, ?- solve(p(2,2),L). % try this - Quit. ?- quit. Installing and Running YProlog ============================== All the classes are in the YProlog.jar file. If you wish to compile/build YProlog, see the AA_README file. You can start the command interpreter with: java -jar YProlog.jar Optionally, you can specify a number of Prolog files to be consulted on start-up: java -jar YProlog.jar file1.pro file2.pro file3.pro You can also run YProlog in batch mode. It will read some files, execute one or more queries, dump the results to output files, and exit. You can supply queries to execute using the '-d' and '-t' switches. For example: java -jar YProlog.jar file1.pro file2.pro -d 'cow(10,X)' -t 'horse(X)' It will dump all answers to the two queries in the files 'a1.out' and 'a2.out'. The '-d' will output the result as Prolog termlists; -t will output the result as a tab-separated table file. It is also possible to read table files into the database using '-r' and '-k'. The following will read a tab-separated, a space-separated, and a comma-separated file into resp. the predicates 'pred1', 'pred2', and 'pred3', and then start the command interpreter: java -jar YProlog.jar -r pred1.tsv '-r ' pred2.txt -r, pred3.csv The following command will read a tab-separated table file, and ensure that duplicate facts are removed by successive entries found in the table. Duplicateness is defined by having equal values in all fields that are marked as database keys. A database key is marked by a "*" in the first argument to '-k'. That is: java -jar YProlog.jar -k '*.*....' pred.tbl will replace facts that have equal values at both the first and third field positions. YPROLOG basics =============== The syntax generally conforms to Edinburgh Prolog notation. Atoms: - identifiers starting with lower case letter (i.e. red, green ) - strings within single quotes (ie. 'path.pro', 'Atom' ) - integers: like 123 or 0003 Variables: - identifiers starting with capital letter ( X, Yes ) - '_' ("don't care", each '_' stands for a different variable) Lists: - [] or [1,2,3] or [1,2,3 | Tail ] or [1,[2,3],[4,[5]]] Comments: - anything starting with the "%" character to the END-OF-LINE Predicates: - identifiers starting with lower case letter - quoted string - one of the special predicates, '+' '-' '=' '==' etc. These may be written either as infix, 'A == B', or prefix, '==(A,B)'. The unary operator '\+' must be written using brackets, i.e. '\+(Goal)'. Primitives =========== Primitives are predicates with a special meaning. These cannot be redefined by the user. A list of available primitive follows. Debugging --------- - trace and notrace : to turn on and off a minimal trace facility - step / nostep : to turn on and off the step mode. In step mode, you can answer "s" (skip) to avoid detailled tracing of a goal or "q" to drop out of step/trace or "a" to abort. Basic ----- - true : goal which always succeeds. - fail : always fails. Note: other unknown predicate also fail but in "trace" mode, those predicates provoke a special error message; not so with 'fail'. - = : unification operator ( X=t(_,_) ) - ! : the CUT operator - call(X)... or simply X : try to reduce the X goal - not(X) or \+(X) : succeeds if X fails - var(X) : succeeds if X is not bound to any constant; and can thus be unified with anything - quit : quit interactive mode Output ------- - print( X ) : converts X to String and prints it - nl : skips to next line - println( X ) : ...obvious... Control flow ------------ IF: ( -> ; ) ( -> ) where , and are all sequences of goals. Behaves like IF...THEN...ELSE... or IF...THEN... OR: ( ; ) Knowledge Base -------------- - consult( File ): reads in predicate definitions from "File". - assert(Term) - asserta(Term) : usual meaning. Only works for facts not for rules. - retract( Term ): retracts first matching fact... and others on backtracking. - retractall( functor/arity ): retracts all clauses - listing : prints "user" facts and rules in the knowledge base - listing(full) : prints "primitive" predicates as well - listing( F/N ): prints clauses with Functor "F" and arity "N" Get/Set (not standard Prolog) ------------------------------- These predicates implement "variables": - set( Name, Value) : adds an entry to the database with Name = Value and - get( Name, X ) : will retrieve the value of "Name" and seek to unify it with X Example: set(a,1), ..., get(a,A),... Note 1: setting a new value for "name" wipes out the old value Note 2: both Name and Value can be terms of any complexity; the printable String of the "name" term is used as the Key to the database [and should not contain free variables] This could be used to implement an arrays with O(1) access time as follows: X=13, Y=40, set( p(X,Y), -1) ,..... get( p(13,40), VAL), ..... Arithmetic ---------- Works with "long" integers. The operators are: +,-,*,/ and mod. Arithmetic expressions can include integer, variables bound to integers and "rnd()" which returns a random integer between 0 and . Arithmetic expressions are evaluated as operands of comparison operators and as the RHS of "is" the assignment operator. Comparison operators do not necessarily match those of standard Prolog. They are: == (equal), != (not equal), >, <, >= and <=. Examples: X is 3*2+rnd(100), X >= (Y*10+1) mod 3, ... String processing (not standard Prolog) --------------------------------------- YProlog also comes with a few string processing features. All comparison operators, <, >, <=, >=, == and != also work on strings and non-atoms. The ordering used is lexical order. The operations convert non-atoms to strings to do the comparison. - matchregex(String,Expr) : match String with Java regular expression Expr. The expression must match the entire string rather than just a part of it. Example: matchregex('my string','.*tri.*') Agent Communication =================== YProlog retains the multi-agent communication features of XProlog. You can create multiple YProlog objects, each of which stands for a separate Prolog engine and kb (a "Prolog agent"). These Prolog agents can communicate with each other through special predicates. Each agent is assigned a unique identifier which allows messages to be sent from one specific agent to another. Each agent has an input queue for terms which serve as "messages" as well as a central "PostOffice" which keeps pointers to the input queues of each agent. Note that YProlog objects which are no longer referenced by any code are removed from the PostOffice as well, and can no longer be sent messages. The following agent predicates are provided: - self( ID ) : returns in ID the agent identifier (an integer) - send( Dest, Message) : puts a copy of the term "Message" on the input queue of agent with integer identifier Dest. - broadcast( M ) - shout(M) sends message M to every agent except sender - receive( Src, M ): removes first message off the queue if there is one, fails otherwise. Then unifies "Src" and "M" with the source and content of the message. If either unification fails, the message is lost. - dumpq : prints out the contents of the queue. Agent example ============= The java program "Play.java" is an example of a MAIN program for two agents. It assumes two Prolog agents whose programmes files are given as parameters. The first being the "environment"; the second is an 'explorer' which learns about its environment by trying to move and being informed of the results (move or bumping into something). Play first calls the "init" predicate of the first agent then in turn calls the "go" predicate of each agent 65 times. In the end it asks the explorer agent to list its database and exits. To see it as work try: java -cp YProlog.jar:yprolog/examples Play \ yprolog/examples/robot_env.pro yprolog/examples/robot.pro The files are found in yprolog/examples: - Play.java: main program - robot_env.pro: a Prolog program acting as the environment - robot.pro : an explorer robot Java Database API ================= YProlog has an extended API for using the Prolog engine as a database engine. We shall highlight some of the API features here. The API reference can be found in the javadoc, yprolog/javadocs/index.html You can create a Prolog database using: YProlog db1 = new YProlog(); You can now add facts to it using consult. Consult is optimised to add a lot of facts incrementally. For example: for (int i=0; i<10000; i++) db1.consult( "a("+i+")." ); You can query the database and extract all results as a table using queryToTable(): Vector table = db1.queryToTable("seltbl(X,Y,Z), a(X),b(Y,Z),c(X,Y)",0,true); which will produce a list of the unique combinations of X, Y and Z that are solutions to the query. QueryToTable will return the parameters of the first term in the goal, which is in this case seltbl. The predicate seltbl is analogous to the SQL select statement, which selects the relevant values from a specified query. Seltbl has no effect on the query result as it always succeeds and binds no variables. You can also read and write CSV / tab separated table files using resp. assertStream and queryToStream. You can use queryToString() or dump() to resp. read query results or dump database contents to Strings, which form legal Prolog statements that can be re-entered into another database or saved to a file. For example, you can "serialise" a Prolog database using: printstream.print(db1.dump()); and transfer all solutions to a(X) to another database using: db2.consult( db1.queryToString("a(X)",0,"") ); There is also a fast retract operation, which enables a number of facts to be retracted in one go. Prolog is not very good at retracting stuff, as the retract itself has to match its argument with the database, even if this argument has just been retrieved. For example, to retract 100 elements a(0)...a(99), we would use something like: a(X), X<100, retract(a(X)). This is very slow. Even as a(X) has just been matched, retract has to look it up again. In the YProlog API, we can retract the elements like this: db1.retract("a(X), X<100"); First this solves the goal while collecting all a(X) facts found, and then deletes the facts directly, as in erase/1. YProlog can also return query results as objects: Vector obj = db1.queryToObjects( "seltbl(X1,Y1,X2,Y2), coord(X1,Y1), coord(X2,Y2)", java.awt.Rectangle, 0, false ); The queryToObjects method tries to find an appropriate constructor in Rectangle to create a Vector of Rectangles with the corresponding X1,Y1,X2,Y2 coordinates. We can also convert objects implementing the PrologObject interface to Prolog tables. Vector my_objects; /* ... */ db1.consultFromObjects( "myobj", my_objects ); ConsultFromObjects will store the contents of all objects in my_objects to myobj(...) predicates in the database.