Trindikit4 - differences from Trindikit3 (early draft)

Trindikit4  - a distributed system

In Trindikit4, the system components, e.g. Total Information State, modules, resources, controller,  can be distributed across several OAA agents. Each agent publishes its capabilities as OAA solvables, so that other OAA agents can call make use of them. This allows for using only a part of the Trindikit functionality in a system, since overall system control can be put outside Trindikit itself. This document describes Trindikit4 in a fashion so that it should be understood by someone who has used earlier versions of Trindikit.

Loading and starting and stopping Trindikit

If Trindikit4 is installed at $TRINDIKIT, the following steps are needed to start a system:
  1. load Trindikit by consulting the module trindikit.pl located in $TRINDIKIT/core/prolog
  2. set properties
  3. type control (for starting the Trindikit controller) or oaa_slave (for connecting to OAA and wait for requests)
Quit by typing CTRL-C in the controllers terminal.

Asynchronicity

A previous implementation of asynchronicity in Trindikit, the agent environment (AE),  has been removed. Instead the dialogue system builder (DSB) can define one or more Trindikit agents which communicate via OAA. The Trindikit controller can run several control modules in parallel, coordinating the work of modules. The Trindikit agents work together as one Trindikit system. Currenlty resources need to be in the same agent as the TIS. Se Control Algorithms

Flags

Trindikit does not make use of flags. Instead properties are used, both for defining the system architecture and for the previous system flags.

Configuration file

In previous versions of Trindikit the DSB wrote a system configuration file which specified e.g. what modules and datatypes to use. This functionality is now handled by properties. DSB still needs to write code that sets properties and starts the system. However the system architecture can be changed by setting properties.

Search paths and file names

Most of the trindikit core files have been renamed, to minimize the possibility of name clashes. In most cases a tkit-prefix has been added. DSB does not need to define the search paths and library directories for Trindikit files. However DSB-defined files and modules must be in a SICStus library directory. The directory in which the Trindikit core modules reside, e.g. for starting the system and accessing TIS, is not a library directory anymore, but resides in a special "trindikit" namespace. Thus, when e.g. writing a module that needs TIS access, write the following to load the tkit_tis_access module:
:- use_module(trindikit(tkit_tis_access)).
The directories containing predefined Trindikit modules and datatypes are library directories.

Properties

What was previously handled by flags and predicates in the system configuration file is now handled by properties. The predicates for using properties are defined in the prolog module tkit_properties which is loaded like this (of course all predicates need not be imported):

:- use_module( trindikit(tkit_properties), [prop/2,setprop/2, addprop/3, deleteprop/3] ).
A valid property name is defined as follows (from file tkit_properties.pl):

   is_valid_prop_name(Atomic):-
       atomic(Atomic).

   is_valid_prop_name(A-B):-
       is_valid_prop_name(A),
       is_valid_prop_name(B).



These are the current predifined properties of Trindikit4:

Property
Default value
Permitted value
Description
tis
no
no or yes
The value of property tis determines whether the agent is a TIS agent or not, i.e. whether it contains an information state.
tis-datatype_files [] a list of files containing datatype definitions
A list of files containing datatype definitions, including resource interfaces. All files should be in a library directory. Replaces selected_datatypes/1 and parts of file resource_interfaces.pl.
tis-infostate
none
none or Var:Type, where Var is a variable name (typically is), and Type is a type definition
The definition of the information state proper. Replaces file infostate.pl.
tis-mivs
[]
a list containing elements of the form Var:Type, where Var is a variable name, and Type is a type definition The definition of the module interface variables. Replaces file module_interfaces.pl.
tis-rivs
[]
a list containing elements of the form Var:Type, where Var is a variable name, and Type is a type definition The definition of the resource interface variables. Replaces parts of file resource_interfaces.pl.
tis-typecheck
no
no or yes
Whether TIS checks and updates should be type checked. Replaces flag typecheck.
tis-reset_ops
[]
a list of TIS updates
Updates to be performed at TIS reset. Replaces reset_operations/1.
tis-macros
[]
a list containing elements of the form macro_cond(M,C) or  macro_op(M,O) where C is a TIS condition or a list of TIS conditions and O is a TIS operation or a list of TIS operations
Macro definitions. Macros are shorthand forms for TIS updates or checks. Replaces optional file macros.pl.
tis-aliases
[]
a list containing elements of the form alias(Alias,Path)
Alias definitions. Aliases are shorthand forms for paths.
Replaces optional file alias.pl.
tis-output_format
text
text or xml or latex
Defines how update rules are printed.
Replaces flag output_format.
tis-print_state
all
all or is or no
Defines what parts of the TIS should be printed when print_state is called. Replaces flag print_state.
tis-print_rules
yes
yes or no
Defines whether update rules should be printed when executed.
Replaces flag print_rules.
modules
[]
a list containing elements of the form Module:File, where Module is the name of the module and File is the file in which it is declared
Defines the Trindikit agent's modules. A module M declared in a file F must be declared as a prolog module named M. All exported predicates are considered module algorithms by trindikit.
Replaces predicate selected_modules/1.
resources
[]
a list containing (file) names of Trindikit resources
Defines the Trindikit agent's resources. A resource R must be declared as a prolog module named R. All resources must define resource_of_type/1 which states the type of the resource, i.e. the corresponding resource interface. Replaces predicate selected_resources/1.
oaa
no
yes or no
Defines whether the Trindikit agent should connect to OAA and publish solvables. Needs oaa-libdir to be set to a proper value before it is set to yes.
oaa-name
trindikit
any atom
Defines the oaa name of the Trindikit agent.
oaa-libdir
''
a search path
Defines the directory in which the OAA prolog library resides. If e.g. OAA 2.3.0 is installed at /home/david/oaa2.3.0 the value of oaa-libdir should be '/home/david/oaa2.3.0/src/oaalib/prolog'.
control
no
yes or no
Defines whether the agent should act as a controller (i.e. execute control algorithms) or not.
control-algorithm
[]
a list containing elements of the form Trigger => SerialAlgo, where Trigger is a trigger and SerialAlgo is a serial control algorithm
The control algorithm used by the controller. See Control algorithms section.
Replaces file control.pl

Module read/write access

In previous releases, Trindikit modules needed to define what parts of the TIS they could read and write to by specifying read_access/1 and write_access/1 for each module. This information is not used anymore, but may be used in future releases.

Resource interfaces and resources

The file resource_interfaces.pl was needed by Trindikit to specify:
This file is no longer required.  Instead a resource interface is treated as any other TIS datatype. One resource interface should be declared for each resource type, in fact the resource interface is the type definition. As with datatypes, it does not matter if resource interfaces are defined in separate files or not.

Example resource interface,  lexicon.pl:

    :- multifile is_resource_type/1,resource_relation/2, resource_relation_type/2.
    :- discontiguous resource_relation/2, resource_relation_type/2.

    is_resource_type(lexicon).

    resource_relation( input_form, [Lexicon, Phrase, Move] ) :-
        Lexicon : input_form( Phrase, Move ).
    resource_relation_type( input_form, [ lexicon, string, dmove ] ).

    resource_relation( output_form, [Lexicon, Move, Phrase] ) :-
        Lexicon : output_form( Move, Phrase ).
    resource_relation_type( output_form, [ lexicon, dmove, string ] ).

    resource_relation( yn_answer, [Lexicon, A] ) :-
        Lexicon : yn_answer( A ).
    resource_relation_type( yn_answer, [ lexicon, answer ] ).


Example resource, lexicon_vcr_english.pl:

    :- module( lexicon_vcr_english, [output_form/2, input_form/2, yn_answer/1, resource_of_type/1]).

    resource_of_type( lexicon ).

    output_form( Move, Phrase ) :- ...

    input_form( Phrase, Move ) :- ...

    yn_answer( A ) :- ...


Resources are loaded by setting the property resources to a list containing the resources that should be loaded (this replaces selected_resources/1 in the configuration file). The resources must be in a library directory. Example:

setprop( resources, [ lexicon_vcr_english, lexicon_vcr_svenska, device_vcr, domain_vcr ] )

Resource interfaces are loaded just like other datatypes, they are included when setting the property tis-datatype_files. The resource interfaces must be in a library directory.  TIS resource interface variables are defined by setting the property tis-rivs to a list containing the names of the resource interface variables and their type. Example:

setprop( tis-rivs, [ lexicon:lexicon, devices:record([]), domain:domain ] )

Module interfaces

The file module interfaces is no longer needed. Instead the name and type of module interface variables is determined by setting the property tis-mivs to a list containing the module interface variables and their type, e.g. like this:

setprop( tis-mivs, [ input:string, output:string, latest_speaker:participant, latest_moves:oqueue(dmove), next_moves:oqueue(dmove), program_state:program_state, score:real, timeout:real, language:language ] )

Information State definition

The definition of the information state is determined by setting the property tis-infostate to the name of the information state variable (typically is) and its type definition, e.g. like this IS type definition from godis-aod:

ISDef = record( [ private : Private,
               shared : Shared ] ),
     Shared = record( [ com : set( proposition ),
                        actions : stackset( action ),
                        issues: stackset( question ),
                        qud : stackset( question ),
                        pm : set( move ),
                        lu : LU ] ),
     Private = record( [ agenda: oqueue( action),
                         plan : stackset( action ),
                         bel : set( proposition ),
                         tmp : record( [ usr : TMP, sys: TMP ] ),
                         nim : oqueue( pair( participant, move ) ) ] ),
     LU = record( [ speaker : participant,
                    moves : set( move ) ] ),
     TMP = record( [ com : set( proposition ),
                     issues : stackset( question ),
                     qud : stackset( question ),
                     actions : stackset( action ),
                     agenda : oqueue( action ),
                     plan : stackset( action ) ] ),
setprop( tis-infostate, is : ISDef).

Calling Trindikit components

There are four main component types in Trindikit:
Each component type, except for resources, has its own interface which is used to make use of the components capabilities, These interfaces are defined in the prolog modules tkit_control_access, tkit_module_access, and tkit_tis_access. When a predicate defined in one of the interfaces is called, the value of property control, modules, or tis is checked to decide whether the call should be executed locally or if it should be routed via OAA to another trindikit agent. Since each Trindikit agent (connected to OAA) publishes its components capabilities as solvables, all Trindikit agents connected to the same facilitator can work as one system transparently. The different components do not need to know what other components are part of the system. Also non-Trindikit OAA agents can make use of the Trindikit components' functionality by using the Trindikit OAA API. The real components (called via the interfaces and the OAA API) are tkit_control, tkit_tis and the modules defined by the modules property. The interfaces tkit_control_access, tkit_module_access, and tkit_tis_access are imported as follows:

:-use_module(trindikit(tkit_control_access)).
for  tkit_control_access,

:-use_module(trindikit(tkit_module_access)).
for tkit_module_access,

:-use_module(trindikit(tkit_tis_access)).
for tkit_tis_access

tkit_control_access  predicates

Predicate
Description
control
Starts the control algorithm as defined by property control-algorithm if property control is set to yes.
trigger(TriggerCond)
When called:
  • if property control is set to yes, all serial control algorithms triggered by TriggerCond are appended to their respective threads (see Control algorithms). 
  • if property control is set to no, the call is routed via OAA by calling oaa_Solve(tkit_trigger(TriggerCond)).

tkit_module_access predicates

Predicate
Description
call_module(M,A)
When called:
  • if Trindikit module M is a component of the current agent (as defined by property modules) module algorithm A defined in module M is called. A can be a predicate of any arity; if it is of arity > 0, one or several arguments can become bound after the call. The algorithms of a module is determined by its exported predicates.
  • else the call is routed via OAA by calling oaa_Solve( tkit_call_module(M,A) )  to give another Trindikit agent (which may be defining module M) the opportunity of executing algorithm A.

tkit_tis_access predicates

Predicate
Description
check_condition(Cond)
If property tis is set to yes, check if condition Cond holds of TIS, else route the call via OAA by calling oaa_Solve(tkit_check(Cond))  to give another Trindikit agent (which may be a TIS agent) the opportunity of checking condition Cond.
check_conditions(Conds) If property tis is set to yes, check if list of conditions Conds hold, else route call via OAA by calling oaa_Solve(tkit_check(Cond)).
apply_update(Op)
If property tis is set to yes, apply update Op to TIS, else route call via OAA by calling oaa_Solve(tkit_apply(Op)).
apply_updates(Ops)
If property tis is set to yes, apply updates Ops to TIS, else route call via OAA by calling oaa_Solve(tkit_apply(Ops)).
apply_rule(Name,Pre,Eff)
If property tis is set to yes, apply rule Name with preconditions Pre and effects Eff to TIS, else route call via OAA by calling oaa_Solve(tkit_apply_rule(Name,Pre,Eff)). Fails if Pre do not hold. 
add_trigger(TriggerCond)
If property tis is set to yes, add trigger with trigger condition TriggerCond to TIS, else route call via OAA by calling oaa_Solve(tkit_add_trigger(TriggerCond)).
clear_triggers
If property tis is set to yes, clear (remove) all triggers, else route call via OAA by calling oaa_Solve(tkit_clear_triggers).
reset
If property tis is set to yes, reset TIS (set all variables to their default value and execute reset operations defined by property tis-reset_operations), else route call via OAA by calling oaa_Solve(tkit_reset).
reset(Var)
If property tis is set to yes, set TIS variable Var to its default value, else fail.
print_state
If property tis is set to yes, print state as specified by property tis-print_state, else route call via OAA by calling oaa_Solve(tkit_print_state).

   

The Trindikit OAA interface

All Trindikit components can be called from OAA provided that the Trindikit agent has connected to OAA (i.e. property oaa is set to yes). The Trindikit solvables are as follows:

Controller solvables

Control agents (Trindikit agents with property control set to yes) declare:

Module solvables

For each of the agent's module algorithms a solvable of the form
where M is the name of the module and A is the algorithm, is declared.

TIS solvables

TIS agents (Trindikit agents with property tis set to yes) declare:
- Trindikit DME operators over OAA:

$latest_moves -> '$'(latest_moves)
/shared/com -> is/shared/com or '/'(shared/com)
$/shared/com -> '$/'(shared/com)
!Cond -> '$'(Cond)
A := B -> ':='(A,B)
< > and ^ can not be used with java oaalib

DME ADL Canonical format

There is also support for a more operator-free canonical format of updates and checks:
As a consequence, the user can not define relations, operations or  functions named val, valfun, assign or force.

Control algorithms

Trindikit control is now multithreaded. It does not need to be a separate agent, but if you want modules to run in parallel with the DME you can  have it in a separate agent. A Trindikit system can be distributed across several (OAA) agents. It is wise though to keep TIS-intensive modules in the same agent as the TIS, since it speeds things up. An asyncronous control algorithm looks as follows:

AsyncAlgo = [ X_1,...,X_n] where
  * X_i is either    init => SerialAlgo    or      condition(TriggerCond) => SerialAlgo
  * SerialAlgo is a serial control algorithm
  * TriggerCond is a triggering condition, one of
      * is_set(Var) - TIS variable Var is set
      * is_unset(Var) - TIS variable Var is unset
      * empty(Var) - TIS variable Var is emptied
      * val(Var,Val) - TIS variable Var is set to Val
      * $Var == Val - TIS variable Var is set to Val

The control/0 starts the control algorithm. It will then:
  - create one empty thread (empty list) for all serial algorithms.
  - reset TIS (according to the TIS definition and reset operations)
  - uninstall any old triggers from TIS
  - install all triggers of the form cond(TriggerCond)=>SerialAlgorithm
  - append the init-triggered algorithms to their corresponding threads
  - start executing all threads in a round-robin fashion. each thread is executed one step at a time.

Control algorithm calls to Trindikit components located in the same agent as the Trindikit control are blocking, calls to trindikit components in other agents are non-blocking, but they block the execution of the calling thread.

When a triggering condition TC becomes true of the TIS after doing a TIS update, the agent containing the TIS will make the call trigger(TC), which will be delegated to the Trindikit control (via OAA if control is not in the same agent as TIS). The Trindikit control will then append the associated algorithm to its dedicated thread, and continue the round-robin execution.

The control language is more powerful, making trindikit a less rigid system architecture, and enabling more processing to take place in the control algorithm.
- module algorithms can have arguments (even return arguments)
- variables can be bound within control algorithms  (variables within repeat- or while-constructs are only bound locally)
- variable bindings can be passed on from a triggering condition to a control algorithm
- control algorithms can contain calls to arbitrary OAA agents
- control algorithms can update TIS (apply_rule/3 or apply_update(s)/1)