CLIPS Win32 DLL for Embedded Applications Version 0.5 Xiangjun Xu Texas A&M University February 2, 2002 CLIPS Win32 DLL for Embedded Applications, Version 0.5 Table of Contents 1. INTRODUCTION .............................................................................................. 3 2. USAGE MANUAL FOR C++ ............................................................................ 3 2.1 Basic usage .............................................................................................................................................. 3 2.2 Loading constructs ................................................................................................................................. 4 2.3 Redirecting the output messages ........................................................................................................... 4 2.4 User function ........................................................................................................................................... 5 3. JAVA INTERFACE ........................................................................................... 7 4. DATABASE INTERFACE ................................................................................ 7 5. LIMITATIONS AND CAVEATS ........................................................................ 7 6. REFERENCE .................................................................................................... 7 Texas A&M University 2 CLIPS Win32 DLL for Embedded Applications, Version 0.5 CLIPS Win32 DLL for Embedded Applications 1. Introduction There are applications requiring interfacing with expert systems. One approach to achieve this is through external files. The applications write facts and rules into disk files and the users are supposed to invoke the expert system shells and open the save files to start the reasoning process. The outputs of the expert system shells are also saved as files for the applications to read back. As we can see, the whole process may confuse the end users. A better solution is to embed an expert system in the application. In this way, the application can pass the facts and rules to the embedded engine directly. User interference is no longer needed. This type of expert systems is called embedded applications. This report is about such an effort. The CLIPS [1] expert system has been encapsulated as a Win32 C++ DLL, which greatly simplifies the development of embedded expert systems. There are already two CLIPS DLL available. One is from the CMU AI repository [2]. But it is a Win16 DLL for Windows 3.1 and the CLIPS used is the old 5.x version. Another CLIPS6.10 DLL [3] doesn’t provide the source codes, not even the header files, which hinders its use. Also its quality is pretty bad; many protection errors and memory leak problems have been encountered. The Java version CLIPS – Jess [4] is still not supporting all the functionality of CLIPS. For example, in Jess Ver5.1, the conditional element “or” is not yet supported (new versions, such Ver6.0 may have added more functions). Also, Unlike CLIPS, its license is free for non-commercial use only. These are the reasons I decided to create our own CLIPS DLL. The DLL has been compiled using Visual C++ 6.0. Other C++ compilers (e.g. GNU C++, Borland C++) should also work. Note: this new version CLIPS DLL is based on the recently release CLIPS 6.20 Beta source codes. 2. Usage Manual for C++ 2.1 Basic usage The usage of the DLL is very simple. The following code segment shows a typical usage: #include "ClipsEng.h" Texas A&M University 3 CLIPS Win32 DLL for Embedded Applications, Version 0.5 try { CLIPSEngine eng; eng.load("test.clp"); // load constructs eng.reset(); // assert constructs eng.run(); } catch (CLIPSException *ex) { printf(“Error: %s\n”, ex->why()); delete ex; } First, the program creates a CLIPSEngine object, which represents the embedded inference engine will be used in the application. Then it read in the constructs defined in a rule file. Finally, it will start the inference engine. The CLIPSException object encapsulates all the possible errors happened in the engine. 2.2 Loading constructs Both the rules and the facts can be passed to the engine via files or commands. The CLIPS function (load filename) will read in constructs from a file. For example, the following command will open myes.clp file and load all the constructs in it. eng.execCommand(“(load \“myes.clp\”)”); To batch executing a command file, i.e. opening a file and executing every command inside it, please use the eng.batch() method. execCommand("(batch)") will not work unless you are not in a command loop. The CLIPS function (batch filename) depends on the command loop to work. Also, the application developer can define the rules and the facts using CLIPS commands. For example: eng.execCommand(“(defrule rule1 (break-time 100) => (assert (breaker failure) ))”); eng.execCommand(“(deffacts fact1 (breaker STP 220) )”); 2.3 Redirecting the output messages The user can specify the output stream of the CLIPS engine. After that, all the output will be redirected to the specified stream. Usually only the print function will be customized: eng.addRouter("output1", MyQueryFunction, MyPrintFunction); And your query and print functions are: int MyQueryFunction(void* env, char* logicalname) { if(strcmp(logicalname, "output1") == 0)) Texas A&M University 4 CLIPS Win32 DLL for Embedded Applications, Version 0.5 return 1; // only handle "output1" return 0; } int MyPrintFunction(void* env, char* logicalname, char* buffer) { // TODO: write out the info in buffer } In the above example, a new print function is provided for "output1". For example, in CLIPS rules, you can write: (printout output1 "my message" crlf); And the text will be passed to your own print function (MyPrintFunction in this case). To embed the CLIPS DLL in a Windows application, it is better to redirect all the inputs/outputs to some Windows Common Controls such as Edit or RichEdit. By implementing a specific MyPrintFucntion, this can be easily accomplished. For example: int MyPrintFunction(void* env, char* logicalname, char* buffer) { // TODO: write out the info in buffer m_edit.SetWindowText(buffer); } In general your application should already have a message loop if it is a GUI application. Otherwise, you should implement RunEventFunction to provide the necessary message loop. For more information, please see [5]. 2.4 User function The user can define external functions that will be called by CLIPS, which provides a kind of "callback" mechanism. For example, sometimes, we may want to be notified when certain rules fired. To achieve this, we can implement some user functions and call those user functions in the consequent parts of the rules. // In your C++ application // step #1 int MyFunc1(void* env); // function declaration // step #2 eng.defineFunc("myfunc1",'i', MyFunc1, "MyFunc1"); //see [5] ch3 // step #3 // implementation, this function will be called by CLIPS int MyFunc1(void* env) { // do something interesting here Texas A&M University 5 CLIPS Win32 DLL for Embedded Applications, Version 0.5 return 1; } And in your rule: ; step #4 ; In your CLIPS rule file (defrule r1 () … => (myfunc1) …) When the rule fires, MyFunc1 will be called. The engine member function defineFunc simply calls DefineFunction, whose function prototype is: DefineFunction(void* env, char* clips_funcname, char rettype, int (*pfunc)(void), char* actual_funcname) : Where rettype is (excerpted from [5]): a - External Address b - Boolean c - Character d - Double Precision Float f - Single Precision Float i - Integer j - Unknown Data Type (Symbol, String, or Instance Name Expected) k - Unknown Data Type (Symbol or String Expected) l - Long Integer m - Multifield n - Unknown Data Type (Integer or Float Expected) o - Instance Name s - String u - Unknown Data Type (Any Type Expected) v - Void—No Return Value w - Symbol x - Instance Address Compared with DefineFunction, DefineFunction2 provides more strict description of the external functions, whose function prototype is: DefineFunction2(void* env, char* clips_funcname, char rettype, int (*pfunc)(void), char* actual_funcname, char* func_restriction) The format of func_restriction is: <min-args> <max-args> [<default-type> <types>*], e.g. "3*", "*5", "35n", "66fsui" For more information, e.g. passing arguments etc., please consult Chapter 3 of [5]. Texas A&M University 6 CLIPS Win32 DLL for Embedded Applications, Version 0.5 3. Java Interface The Java interface will enable Java application to utilize the CLIPS DLL … 4. Database Interface Database tables can be easily mapped to unordered facts. The name of the table will be the fact name, while the columns form the templates. The database interface requires ODBC to work. 5. Limitations and Caveats Some limitations of the previous version CLIPS DLL have been eliminated. The new version is based on CLIPS 6.20 Beta, while the previous one is on CLIPS 6.10. The new version CLIPS has introduced a new concept "environment", so multiple instances of CLIPS Engine can be created. Also, the memory leak problem has been fixed. But the following usage is still recommended for better performance: Declare a CLIPSEngine as a global object, for example: CLIPSEngine* g_pEngine; Initialize the CLIPSEngine object in InitInstance(), for example: g_pEngine = new CLIPSEngine(); Delete the CLIPSEngine object in ExitInstance(), for example: delete g_pEngine; The DLL is only accessible from a single thread. 6. Reference [1] CLIPS website, http://www.ghg.net/clips/CLIPS.html [2] CLIPS5 DLL at CMU AI Repository, http://www-2.cs.cmu.edu/afs/cs/project/airepository/ai/areas/expert/systems/clips/contrib/clipsdll/v2/ [3] CLIPS6.1 DLL, http://ourworld.compuserve.com/homepages/marktoml/clipstuf.htm [4] Jess website, http://herzberg.ca.sandia.gov/jess [5] CLIPS Reference Manual Vol. II, Advanced Programming Guide Ver 6.10, 1998 [6] ODBC interface for CLIPS, http://www.monmouth.com/~km2580/CLIPODBC.htm Texas A&M University 7