1.1 What is QuLog?

QuLog is a flexibly typed multi-paradigm rule based language for programming AI applications, particularly distributed applications comprising communicating and reasoning multi-threaded software agents. It has three forms of rule:

  • Relation rule form: RelCallPtn :: Guard <= RelCallQuery
  • Function rule form: FunCallPtn :: Guard -> FunCallExpression
  • Action rule form: ActCallPtn :: Guard ~> ActCallSeq
    using primitive actions that may:
    • update the dynamic facts of the agent’s Belief Store
    • update and access host file store
    • do intra-agent thread-to-thread message communication
    • do inter-agent and inter-process communication

In each rule form the guard, Guard, which is a RelCallQuery like the body of a relation rule, is optional. If there is no guard the :: is dropped.

A RelCallQuery is a single RelCond, or an & conjunction of RelConds. A RelCond is a single RelCall, or a negated possibly existentially quantified RelCallQuery, or a universally quantified implication of possibly existentially quantified RelCallQuerys.

The following are alternative ways of defining the concept of a father who has no non-adult children.

rel a_father_with_only_adult_children(?atom)
a_father_with_only_adult_children(P) <= 
         male(P) & child_of(_,P) & 
         forall C (child_of(C,P) => exists A age(C,A) & A > 17)
         
rel a_father_with_only_adult_children(?atom)
a_father_with_only_adult_children(P) <= 
         male(P) & child_of(_,P) & 
         not exists C,A (child_of(C,P) & age(C,A) & A <18)
 

The variable P is implicitly universally quantified for each <= implication. The _ is an anonymous variable and is implicitly existentially quantified. Notice how the rules are quite close to how the concept would need to be defined in predicate logic.

The annotated type expression ?atom is a moded type declaration that tells us that the rules may be used to test or to find values for P, which will be atoms - the alphanumeric symbolic data of QuLog and Prolog.

A relation rule with no guard or body is an unconditional rule. Such a rule with no variables is a fact.

Here is a one rule definition of a function to return the number of recorded children of a named person. In function calls all arguments must be ground - i.e. given as variable free terms.

fun num_children(atom) -> nat      
num_children(P) ->  #{C :: child_of(C,P)}

{C :: child_of(C,P)} is a QuLog set expression and # is a primitive function for finding the number of elements of a set or list which can be used as a prefix operator..

Below is a definition of a birthday action that updates the dynamic fact recording a person’s age, if it exists. Otherwise it displays a message.

act birthday(!atom)
birthday(P) :: age(P, A) ~> 
        forget([age(P, A)]; remember([age(P, A+1)])
birthday(P) ~> 
        write_list([P," does not have a recorded age to update"])

The ! annotation signals that the atom argument P must be given in any birthday call. This is the default mode for an unannotated argument, so the declaration act birthday(atom) is equivalent to the given declaration. age must have been declared as a dynamic relation with a declaration dyn age(atom,int).

In order for a relation rule to be used to evaluate a relation call, the call must unify with the RelCallPtn of the rule head. If the rule has a Guard which succeeds, the call’s evaluation will not try to use later rules for the same relation to find more solutions to the call. So in relation rules the :: has the role similar to the ! cut of Prolog.

For function and action calls only one rule is ever used to evaluate the call. For a function call it is the first rule with a head that matches the call and for which the guard, if given, succeeds. For an action call it is the first rule with a head that unifies with the call and for which the guard, if given, succeeds. In effect, function and action rules without a given guard implicitly have the guard true, which always succeeds. If no rule can be used to evaluate a function or action call this is a runtime error.

The agent’s Belief Store comprises a set a facts for the special class of dynamic relations, declared using the dyn type operator, that are disjoint from the rule defined static relations, declared using the rel type operator. Dynamic relations may only be defined by facts. Static relations may be defined by a mixture of rules and facts.

The relation and function rules are for programming the agent’s deliberation, the action rules for programming its behaviour.

Relation rules may query relations and call functions in arguments of relation calls in the rule body. Function rules may call functions, and may query relations in their guards, or in set expressions in arguments of function calls. Action rules may call actions and call functions in arguments of action calls. They may also call relatiions in set expressions in arguments of action calls, and directly as a ? prefixed query action ?Q. If the query Q has no solutions this is a runtime error.

QuLog is higher order in the functional programming sense, but only program defined code, identified by its unique program assigned name, may be given as an argument or returned as a value. Name overloading is not allowed. Each relation, function and action must have its own unique alphanumeric name, beginning with a lower case letter.


On This Site