Skip to content
sawtoothgeek edited this page Oct 14, 2018 · 27 revisions

C++ Guide Series
Architecture | Knowledge Base | Networking | Containers | Threads | Optimizations | KaRL | Encryption | Checkpointing | Knowledge Performance | Logging


Introduction

Knowledge and Reasoning Language (KaRL) is a specialized scripting language for referencing and mutating knowledge in a MADARA knowledge base. There are several benefits to using KaRL.

1.) It is fast and efficient, generally with very predictable execution times 2.) It can be extended with user functions implemented in the host language 3.) It can be used to quickly prototype agent logic 4.) It can be connected to other knowledge bases 5.) It can be used to monitor status of other program such as those built in GAMS (http://gams.ai)


Table of Contents


Basics of KaRL

Just like any language, a KaRL script is a collection of constants, variables, functions and operations.However, the intent of KaRL was to manipulate knowledge and also to wait on knowledge to change state. Because of this, KaRL has some unique properties.


Local variables

In KaRL, local variables start with a period ("."). These variables will not be disseminated over a network transport. Global variables that need to be disseminated after they are modified start with any letter.

knowledge.evaluate ("
// local variables start with period
.my_x = 10;
.my_y = 20;

/**
 * global variables start with alphabet characters.
 * these will be sent over the network when modified
 **/
my_state = 'waiting'
");

Arrays

KaRL supports arrays of integers and doubles in an intuitive way.

knowledge.evaluate ("
// Setup a position array with latitude, longitude and an altitude set to 3
.latitude = 42.0;
.longitude = 70.1;
position = [.latitude, .longitude, 3];

// change array values
position[0] = get_latitude();
position[1] = get_longitude();
");

All operations return a value

KaRL features many operators that will feel very familiar but that work differently than how the operators are used in other languages. The biggest ones that need some explaining are the semicolon (;) and comma (,). In KaRL, these operators separate expressions, such as setting a variable to a value (e.g., "x = 11; y = 12") but they also return a value. For semicolons, the return value is the maximum value of the left and right hand side. So, "x = 11; y = 12" returns 12 (the maximum of 11 and 12). Conversely, "x = 11, y = 12" returns 11 (the minimum of 11 and 12).

For a listing of most of the supported operators, what they mean and how they are used, see the following powerpoint: http://sourceforge.net/projects/madara/files/presentations/KaRL_Primer.pptx/download

One of the more interesting operators is the choose-right operator ";>", a semi-colon followed by a greater-than. Like a semi-colon operator, this operator evaluates both the left and right hand side. However, the choose-right operator always returns the result of the right-hand side evaluation. This is incredibly useful when creating initialization knowledge while using a wait call on a knowledge base.

Consider the following KaRL snippet that showcases the choose-right operator.

knowledge.wait ("
// use the choose-right operator to indicate not to return latitude and longitude
latitude = 42 ;>
longitude = 70 ;>

is_gps_in_the_us (latitude, longitude)");

The above wait statement above would initialize latitude and longitude to 42 and 70, respectively. It would then return the value of is_gps_in_the_us, which would be a custom function created by a user and attached to a knowledge base with the define_function call. Contrast that to the following code example.

knowledge.wait ("
// use the max operator to return maximum of 42, 70 and return value of function
latitude = 42 ;
longitude = 70 ;

is_gps_in_the_us (latitude, longitude)");

The above code would return the maximum of latitude, longitude, and the return value of is_gps_in_the_us which would almost certainly be a zero or one (false or true), meaning that the resulting evaluation would always be 70 (the longitude initialization), since the semi-colon operator returns the maximum of the left and right evaluations.


Utility functions are built-in

KaRL includes many built-in functions for accessing operating system capabilities like timestamps, printing, accessing operating system environment variables, and other similar functions. System calls begin with a "#" and can take zero or more arguments.

To see all utility functions and documentation for arguments, you can call "#print_system_calls()". This listing is also kept in the source code repo at: https://github.com/jredmondson/madara/blob/master/docs/system_calls.txt


KaRL can be called directly from your applications

KaRL was originally intended to be called explicitly via the evaluate and wait calls on a Knowledge Base. Evaluate is used to evaluate a knowledge expression and then immediately return. A wait also evaluates a knowledge expression but does not return until either a timeout occurs or the results of the evaluation is true (non-zero).


KaRL can be called from the interpreter

MADARA includes a specialized tool called the karl interpreter inside the bin directory. The karl interpreter is invoked from the command line to evaluate one or more logics, similar to how you might call perl or java or any other type of interpreter. However, the karl interpreter has command line options for network transports, iteration and various other features.

As with most tools in MADARA, help for the tool can be invoked with the "-h" or "--help" option. An example of this help file can be found here: https://github.com/jredmondson/madara/blob/master/docs/karl_help.txt

The karl interpreter has many unique features that can help quickly debug other running applications. First, are the network options. If your distributed application is using multicast, you can provide -m with the multicast IP and port, and the karl interpreter will listen for updates on this IP:port, and it will also send updates you make with the karl interpreter to other agents in the network listening to that same IP:port.

The next important option is the wait option (-w). The wait option turns the karl interpreter into a wait. This is useful for listening to the network transport for updates in order to evaluate KaRL expressions in response to knowledge that changes over time.

The wait option is often paired with the frequency option (-y) to indicate how frequently the KaRL expressions should be evaluated. The frequency is specified in hertz (evaluations per second). And if the evaluation result is important to your tests, you can specify the -c option, which will exit the karl interpreter if the evaluation is non-zero. An additional wait can be used (-wy), specified in seconds, which delays the evaluations until a certain amount of time has passed. This is useful to wait for an initialization period before evaluating. Pairing what we've learned so far, the following creates a simple karl interpreter call that runs for 60s and evaluates once per second, checking to see if "mission.failure" has been set to non-zero.

karl -m "239.255.0.1:4150" -c -y 1 -w 60 "mission.failure"

The above listens for multicast messages on 239.255.0.1:4150 for up to 60s or until mission.failure is non-zero, and checks for mission.failure every 1 second. However, one important thing is missing. This will not print knowledge or tell you what has been updated.

The karl interpreter has many debug features related to printing knowledge. First, is -k, which prints knowledge at its final state. The second option is -ky, which prints knowledge after each evaluation. The final debug option worth mentioning in regards to printing is --debug. This option prints uses the aggregate knowledge filter to print all knowledge received over the transport, exactly when it is received.

To perform the same evaluation as earlier but waiting 5 seconds and then printing knowledge after every evaluation, we can call the following:

karl -m "239.255.0.1:4150" -c -y 1 -ky -wy 5 -w 60 "mission.failure"


KaRL interpreter can load and save from binary knowledge base checkpoints

MADARA provides the ability to save knowledge bases to and from checkpoints with the KnowledgeBase::save_context and KnowledgeBase::load_context methods. The KaRL interpreter includes the ability to load an initial context from such a binary knowledge base checkpoint and also to save a new checkpoint after modifications are made to the knowledge base through the command line.

Consider the following examples, which create some knowledge, save the knowledge to a fast, binary format, and then load the knowledge from the saved file.

Creating a simple knowledge base and saving it to my_data.kb karl -sb my_data.kb -k ".location=[1,2,3] ; .status='happy'"

Loading the knowledge base, changing it and saving it again to my_new_data.kb karl -0b my_data.kb -sb my_new_data.kb -k ".status='irritated'"

To print the contents of what we saved in my_data.kb and my_new_data.kb, we read the contents of the knowledge bases using the -0b parameter, which means the 0-state binary or initial binary. -k means print the final knowledge. karl -0b my_data.kb -k karl -0b my_new_data.kb -k

Consequently, use -sb or --save-binary to save knowledge as binary. Use -0b or --init-bin to load knowledge as binary.


KaRL interpreter can load configuration files containing command flags

Introduction:

Welcome. We are proud to introduce the ability of KaRL interpreter to be able load a series of commands via configuration files. These files are simple ascii text files with one command line flag and it's parameter if it has one per line in the file.

Example Usage:

Example command usage

karl -cf karl.cfg
karl -config-file karl.cfg
karl -l 10 -ky -l 2 --debug -cf ../karl.cfg -w 5
karl -l 10 -ky -l 2 -cf ../karl.cfg -w 5 -a

Example config files

File 1

--save-binary ../kb1.bin
--queue-length 256
-ky
--debug
-ls 256
-a

File 2

-l 2
-f ../logfile1.txt
-a
-t 12
-w 2
-cf ../karl.cfg
-w 10

File 3

-l 2
-f ../logfile1.txt
-a
-t 12
--wait 1
-0f $(MADARA_ROOT)/scripts/linux/test_config_files_init.karl
--wait 1
-i $(MADARA_ROOT)/scripts/linux/test_config_files.karl
-k


Examples

Other projects that use MADARA have used KaRL to do things like waiting on knowledge to reach a certain state or to monitor state in running distributed applications.


More Information

If you are looking for code examples and guides, your best bet would be to start with the tutorials (located in the tutorials directory of the MADARA root directory--see the README.txt file for descriptions). After that, there are many dozens of tests that showcase and profile the many functions, classes, and functionalities available to MADARA users.

Users may also browse the Library Documentation for all MADARA functions, classes, etc. and the Wiki pages on this website.


Video Tutorials

First Steps in MADARA: Covers installation and a Hello World program.
Intro to Networking: Covers creating a multicast transport and coordination and image sharing between multiple agents.


C++ Guide Series
Architecture | Knowledge Base | Networking | Containers | Threads | Optimizations | KaRL | Encryption | Checkpointing | Knowledge Performance | Logging