Kahina for QType Tutorial Part 6: Defining Projects and Behavior

This tutorial presupposes that you have worked through QTypeTutorial5. It represents your last essential step towards complete knowledge of Kahina's core components. You will learn how to create and administer projects, how to handle control agent profiles, and how to define your own control agents by editing sensors in the control agent profile editor. For reasons of brevity, we will refrain from giving complete example walkthroughs throughout this tutorial. Instead, the reader is expected to put the freshly acquired knowledge into practice by playing around with the new concepts and features.

Creating a New Project

While the previous tutorials were built on predefined projects, you will now learn how to create a new project from scratch. Minimally, a QType project consists of a path to a QType grammar file and a string identifier. You will be required to specify both as soon as you start creating a new project by clicking on the menu item Project -> New Project. First, you will be asked to enter a name for the project in a simple prompt. Then, a file chooser allows you to select the grammar file the project will refer to.

In this tutorial, it will not be relevant which name or grammar file you choose here. In the screenshots, we simply took one of the largest grammars distributed with QType: an HPSG fragment implemented by Petra Barg which provides lexical entries for some aspects of human physiology, and which resides in the grammar file hpsg_test.qrm in the GRM folder of your QType distribution. Whichever grammar file you choose, you have just created a (trivial) new QType project, on which we will now build to learn how the most relevant parts of a project can be modified.

Saving and Loading Projects

To make it possible to restore a project, it needs to be stored in a project configuration file. For the moment, projects are stored in a rather ad-hoc XML format in order to make project properties easily editable from outside Kahina. Saving a project works via the Project -> Save Project As ... menu option. Selecting this menu entry will open a standard save file dialogue. We recommend giving the project file the suffix ".xml", although this is not strictly necessary. Project files can be stored anywhere you find it convenient, but in most cases you will want to put project files into a new folder in the directory where your grammar files reside.

In the current version, not all project properties can be edited from inside Kahina once a project was created. If you want to change the name of a project or the path to the grammar file after you created it, you will need to manually edit the project file instead. For this reason, we now have a quick look at the structure of the project files. If you open the project file in your favourite XML or text editor, you will see that the root element kahina:project has two relevant attributes. The kahina:appid attribute needs to have the value qtype for any QType project, since it is used by Kahina's project loader to ensure that the project was defined for the correct application. The kahina:name attribute stores the name of the project. At the moment, it should have the value you specified when you created the project. If you want to rename the project, you can change the value of this attribute to any other string.

The root element contains a kahina:mainFile child element, which stores the path to the grammar file in its only attribute kahina:path. The value of this attribute should be the absolute path of the grammar file you specified when you created the project. The kahina:path attribute also supports relative paths, but Kahina's save project option will always spell out the absolute path to the grammar file in the project file it creates. If you want to make project files portable, you need to manually edit the kahina:path values for now.

The project XML file contains two other major parts. The contents of the kahina:perspective element determines the layout and behavior of the various view components, representing an entire window arrangement as well as view configurations just as explained in the upcoming QTypeTutorial7?. The kahina:controlAgentProfiles element allows you to store control agent profiles together with the project. These settings are normally handled from inside Kahina as described in the next section.

To load a saved project from a file, Kahina provides the menu entry Project -> Open Project -> Load Project .... A standard file chooser dialogue will appear, allowing you to select the project file to be loaded. Project import is not yet very robust against invalid project files, so you best pay some attention to avoid accidentally loading a file which is not in the Kahina for QType project XML format, as unpredictable behavior such as crashes can result.

Once the project file was successfully loaded, you will see that the compile option in the grammar menu gets activated. If you have defined a project for our large example grammar, be warned that skipping over the compilation might take quite some time. Even in skip mode, you can still determine the progress of the compilation via QType's console output which still appears on the console from which you started Kahina.

Handling Control Agent Profiles

Projects would not be of much use if their only purpose were to assign some name to a grammar file. As you have seen in QTypeTutorial4 and QTypeTutorial5, projects can also define control agent profiles to influence tracing behavior. Note that in the current version of Kahina, the current project settings will not automatically be saved to the project file if you close Kahina. Therefore, if you want to keep control agents across sessions, you will need to explicitly save the project to an XML file again. If you do so, any control agents defined will be stored in the kahina:controlAgentProfiles element of the project XML file.

It is of course possible to define an entirely new set of control agents for each new project. However, you will often need standard sets of control agents which would be tedious to define multiple times. Such commonly used agents can be grouped together stored in separate control agent profile files. QType is distributed with some profile files which provide us with commonly used agents. Let us see how we can load these predefined profiles using the example of the creep agent profile. Agent profiles can be loaded via the Load button in the leftmost panel of each control agent profile editor instance. Switch to the creep agent profile, and click on this button:

This will open a standard open file dialogue. The predefined control agent profiles reside in the kahina-settings/agents directory of your QType distribution. Let us open the predefined creep agent profile by opening the file creep-agent-profile-standard.xml.

After opening the file, you should see the two familiar creep agents from QTypeTutorial4 appear in the control agent list. Selecting the one named creep db_rule, you see that the sensor is defined in exactly the same way as in the tutorial project. Note that the the actuators are not specified in control agent profile files, the behavior of your agents will depend on the control agent profile editor instance into which they are loaded.

You may want to repeat this process by also loading the standard skip agent and complete agent profiles. If you find this process too tedious, it is also possible to add all three standard control agent profiles to your project by copying the kahina:controlAgentProfiles element from the tutorial project into your project XML file.

Sometimes you load some standard control agent profile, but only need some of the predefined agents, or you accidentally create one agent too much. As an example, assume you have loaded the standard skip agent profile, but you decide that you will never want to skip over executions of the mgu predicate.

In such cases, you can remove a control agent from a profile via the agent list's context menu. Select the agent you want to remove, and open its context menu with a right click. The menu will contain a Remove option, which you can click to remove the agent. At the moment, no confirmation of this action is required, so be careful with using this option.

After the agent's removal, our skip agent profile has only one skip agent left:

If you know that you will need your current control agent profile in other projects as well, you can also create your own control agent profile files. From inside Kahina, this is done via the Save button in the leftmost panel of the control agent profile editor:

Again, you will see a standard save file dialogue. Since control agent profiles are stored in another XML format, we recommend the .xml extension for these files as well. Let us store the modified skip agent profile under a new name in the kahina-settings/agents directory:

This will create a new control agent profile file which can be loaded in exactly the same way as the predefined ones.

Defining Simple Sensors

So far, you have only learned how to group together predefined control agents. In QTypeTutorial5, you have created control points, but you do not yet know how to create other types of control agents. This functionality is what we will introduce in the remaining two sections of this tutorial. For a start, it is important to note that when you create a new control agent, you will in fact only define a sensor, the actuator will already be defined by the control agent profile as part of which you create the new agent.

We will now learn how to define control agents of the type you have seen in the predefined control agent profiles. To create such an agent, you need to click on the New button above the list of control agents in the tab of the desired actuator type. Let us do this for a new break agent:

You will see a new entry in the control agent list, with a name consisting of "Control agent" and the number which is used for internal identification. Select the new break agent, and you will see some content in the sensor editor panel to the right of the agent list:

Apart from the hint panel which will try to make helpful suggestions while you are editing the sensor pattern, the sensor editor consists of a boolean operations panel which you will later need for defining complex patterns, and the pattern panel which currently only displays an empty elementary pattern. An elementary pattern consists of a pattern type, a relation and a value. A typical pattern type builds on a specific step property, and the pattern so defined is checked by the sensor by determining whether the step's property value stands in the specified relation to the pattern's value. The available relations are different for numeric and string-based step properties, meaning that the three parts of an elementary pattern should be defined from left to right.

So let us begin to define our first elementary pattern. For the pattern type, we have the choice between a pattern referring to a step's label, and a pattern referring to a step's ascending numerical ID. For the moment, let us choose the first variant by clicking on the first chooser in the elementary pattern, and selecting the step label option:

This pattern type gives us a choice between different string relations for the pattern. These range from string equality to pattern matching against a full-blown regular expression. Here, we will select the relation you will probably use most often: the contains relation provides a simple way to check whether a step relates to some Prolog predicate.

As the last step, we click into the third chooser to define the pattern's value. Unlike for the other parts of the pattern, we are allowed to enter any string here. Let us enter the string "db_rule" in order for our sensor to match any step whose label contains that string.

From now on, this newly defined break agent will cause leap operations to pause whenever an instance of db_rule/4 is called. Note that this type of pattern is more general than that of a control point, as it matches all calls to the db_rule/4 predicate, not only the ones associated with a given source code line.

The predefined control agents of previous chapters had informative names in order to make them easier to identify on the message console. But the control agent we just defined still has the not very helpful name "Control Agent 4". In the last tutorial, you have already seen how control agents can be renamed via the context menu. Alternatively, Kahina offers the option of generating a name which represents the defined sensor pattern. This option is also accessible via the context menu, via a menu entry called Suggest Name:

A click on this menu entry will replace the control agent's name with a concise, but full description of the sensor. Note that the suggested name "ca.contains(db_rule)" informs us about the type ("ca" stands for "caption"), the relation, and the value of the sensor's pattern, but it does not tell us anything about the agent's actuator. This is sensible because the agent type can be seen as part of the console messages anyway. However, you might still want to give your new control agent a different name, as the auto-generated names may be too long or appear too much like terms of a programming language.

Defining Complex Sensors

Now that you know how to define elementary patterns for creating custom sensors, it is time to advance to the possibilities for defining more complex sensors. The most important mechanism offered by the current version of Kahina for this purpose consists in boolean combinations of elementary patterns. The sensor editor panel includes a simple, yet powerful editor for manipulating such boolean combinations.

To get to know this editor, we first learn how to add additional elementary patterns. This is done by clicking on the add pattern button marked with a green plus sign next to an existing elementary pattern:

This will add a new pattern definition just below the one where you clicked the add pattern button. Note that to the left of the two definition lines, a node marked with a logical AND symbol connects the two squares protruding from the definition lines. This is the way in which the sensor editor displays the tree of boolean connectives over the elementary patterns. Kahina enforces that multiple elementary patterns are always connected by a tree structure, such that the contents of the sensor editor define a valid step pattern at any point. By default, elementary patterns are connected via conjunction.

Just like the single definition line of a newly created sensor, the new pattern definition line contains the three choosers for pattern type, relation, and value. In our example, we again choose the type step label and the relation contains. For the value, we choose db_word, so that your first complex pattern will match steps whose label contains both the string db_rule and the string db_word:

This is of course not a very useful pattern. We want the pattern to match occurrences of both predicates, so what we need is a disjunction, not a conjunction, of the two elementary patterns we have defined. Changing the type of a binary connective is very simple and can be done with a few clicks. First, you need to select the connective whose type you want to change, which will cause the node and its outgoing edges to be highlighted in red:

In this state, you can change the type of the connective by clicking again on the selected node. The first click will transform the conjunction into the desired disjunction, the AND symbol is replaced by an OR symbol on the connective:

This modified pattern does exactly what we want. You may want to try clicking on the connective node again to shuffle through the other types of binary connectives available. Note that the implication occurs in two variants because of its non-commutative nature. After three clicks, you should be back at the AND operator, and one more click brings you back to the disjunction.

To demonstrate the more advanced features for editing boolean combinations of elementary patterns, we need at least three elementary patterns. Let us add another elementary pattern, a constraint on the ID range of matching steps. Click on the plus symbol again to add another pattern, and select step id as the pattern type and >= as the relation. With the value 500, the pattern will match steps whose internal ID is larger or equal to 500.

Note that the new elementary pattern was connected to the existing disjunction by a new top-level conjunction. This is the predefined behavior because we assume that in most cases, you will add new elementary patterns in contexts where you want to impose additional constraints. We are considering to make this behavior user-configurable in future versions of Kahina.

The sensor we have just built matches any step which involves one of the predicates db_rule/4 and db_word/4 after the 500th step. Such a breakpoint would be useful if you already know the first steps of a trace very well because you explored it multiple times, and you only want to leap through the occurrences of the two predicates in the later parts of the trace which you haven't seen so often.

Assume that you nevertheless want to shift your attention back to db_rule and db_word occurrences early in the trace. In this situation like in many others, you will find it desirable to express negation in step patterns you define. This will be our first case for the boolean operations panel in the upper-left corner of the sensor editor. Negation is a simple use case because it is a unary operation for which only one argument needs to be specified. To negate the third elementary pattern, we first select the corresponding node in the boolean structure by clicking on the little square protruding from the respective line, causing it to be highlighted in red.

If you now click on the not button in the boolean operations panel, you will see that a new unary node is inserted above the elementary pattern, with the negation sign displayed on it. As you might expect, the resulting pattern matches all calls to db_rule or db_word with step IDs lower than 500.

We will now learn how to restructure a complex pattern by reshaping the tree of boolean connectives. Assume you have decided that the current bracketing of the three elementary conditions is wrong, and that you want the step ID constraint to only apply to the db_word calls. In this situation, you would want to reshape the tree by introducing a new binary operation which connects the second and the third elementary pattern.

Such binary connectives are introduced in infix style by selecting the first argument, clicking on the button for the desired operator in the boolean operations panel, and selecting the second argument. In our example, we first need to select the second elementary pattern:

If you now click on the and button in the boolean operations panel, the pattern editor assumes that you want to establish a conjunction between the selected node and a second node which still needs to be specified. The hint panel therefore prompts you to select a second child for the new conjunction node.

If you now click on the negation node, you will see that a new conjunction node is created which groups together the second elementary pattern and the negated third pattern. At the same time, the disjunction which connected the first two pattern before has vanished. The dangling first pattern replaces the deleted disjunction node as the upper child of the topmost conjunction node. In this way, we arrive at a valid pattern even after an operation which destroyed parts of the boolean expression.

Note that the resulting pattern does not make much sense, since it requires the label of a matching step to contain both db_word and db_rule as substrings, which will not happen during the execution of any parse. To repair the pattern, you could e.g. click on the topmost connective to change it into a disjunction.

But let us instead assume that in this situation, you decide that you are not interested in applications of db_word/4 after all, but that you would still like to keep the constraint on the step number. The easiest way to make the corresponding edit is to remove the undesired elementary pattern by clicking on the remove button of that line, which is marked with a red cross:

You will observe that the elementary pattern you removed will vanish, and that the boolean connective it was part of rearranges to form a valid pattern. In this case, the boolean AND node which connected the second and the first pattern is removed together with the deleted elementary pattern:

As a rule, the pattern editor will always remove the lowest binary parent of the removed leaf node in the formula tree, and use the other child of the deleted parent to fill the gap in the grandparent connective. This behavior might take some time to get used to, but it makes the reshaping of boolean pattern combinations robust and fast.

Further Steps

You have now been introduced to all the essential components of Kahina for QType. What still remains open is the wide area of view layout customization and view options. An introduction to the concepts of Kahina's window manager and the principles of defining your own view and window arrangements will soon appear in the form of QTypeTutorial7?. For information about the configuration possibilities of individual view components, the reader is referred to the corresponding chapters of the forthcoming handbook.

Last modified 6 years ago Last modified on Oct 17, 2012, 1:00:09 AM

Attachments (30)

Download all attachments as: .zip