Write domain dependent knowledge

In this section, you will be defining the types of arguments you will be using and also adding an operator / constraint / feature-predicate/input matcher to the existing SimStudent. This assumes you have downloaded SimStudent Author's Toolkit and configured it with the CTAT Tutor. If not, you must first go through the SimStudent Author's ToolKit.

Prerequisites:

  • CTAT 2.0 or greater

  • SimStudent Authors Toolkit

Defining types of arguments and a Type Checker

1. Make a Java class

First you have to define the different types of arguments you will use in the target domain, and a method that given an argument returns what the type of that argument (i.e. the "type checker") . For example, for the domain of algebra equations appropriate types might be "algebraic expression", "number", "coefficient", whereas for fraction addition appropriate types might be "complex fraction", "mixed fraction" etc. In this example, you will be defining types and a type checker for a hypothetical domain that involves two different types: "numbers" and "words". To do so, you must first create a class named e.g. "MyFeaturePredicates" in the same package that you copied the files from the SimStudent. This class must extend the "FeaturePredicate.class" and will contain

  1. the type definitions, in the form of integers where each integer refers to a different type

  2. the type checker, i.e. a function named e.g. valueTypeCheckerForMyDomain, that takes a String as an argument and returns the type of this string.

/*********************************************************************

**********************************************************************

************************MyFeaturePredicate.java***********************

**********************************************************************

**********************************************************************/

package packagename;

import java.util.Vector;

import edu.cmu.pact.miss.FeaturePredicate;

public abstract class MyFeaturePredicate extends FeaturePredicate{

/*definition of the types*/

public static final int TYPE_NUMBER = 11;

public static final int TYPE_WORD = 12;

/*function that checks if a string represents a word or a number*/

private boolean isNumber(String line){

return line.matches("[+-]?\\d*(\\.\\d+)?");

}

/*the type checker. This function is invoked by SimStudent to determine the type of a string value*/

public static Integer valueTypeCheckerForMyDomain( String value ) {

int valueType;

if (isNumber(value)) {

valueType = TYPE_NUMBER;

} else {

valueType = TYPE_WORD;

}

return new Integer(valueType);

}

}

2. Updating the files

Now you need to make changes on one file in the same folder where your tutoring interface java file is located. You should have the file "runTutor.sh" in this folder. For SimStudent to invoke the function "valueTypeCheckerForMyDomain" in order to determine the type of an argument, you must add the line

TutorArg="${TutorArg} -ssTypeChecker packageName.valueTypeCheckerForMyDomain"

in your runTutor.sh file.

Adding an operator

1. Make a Java class

First, you write our own operator in the same package where you copied the files from the SimStudent Toolkit. Operators are generic functions to manipulate various form of objects involved in a target task. For example, Algebra operators addTerm("3x", "2x") returns "5x" and getCoefficient("-4y") returns "-4". In this example, you will be developing an operator which can concatenate two words. Let us call this file Concatenate.java. For this you can copy the code below and paste it in a file Concatenate.java

But before you proceed, make sure you understand the entire structure of the class.

Here we define a class Concatenate.java which extends the MyFeaturePredicate class (defined in the section "Defining types of arguments"). This class has a constructor "Concatenate()" in which we can set the following fields.

  1. setArity() - Arity means the number of arguments that a function can take. In this case, you are concatenating two words and hence the number of arguments are specified as 2.

  2. setName() - This defines the String equivalent of our operator class.

  3. setReturnValueType() - This defines what is the type of the return value. For this, you define it as TYPE_WORD , which means that the return type is a word.

  4. setArgValueType() - As implied by the name, it is used to set the types of arguments expected. So, you define it as an integer array of TYPE_WORD which implies that the arguments are words.

Next, you see that our class has a method called "apply()". Essentially, what the apply() method does is it takes the arguments passed to it, and applies the arithmetic operation specified to the arguments and returns the result as a String object. It should be noted that the arguments passed to the "apply()" function of this class is the value of a working memory element (e.g. the value of a cell, or a text box).

/*********************************************************************

**********************************************************************

************************Concatenate.java******************************

**********************************************************************

**********************************************************************/

package packagename; // packagename is the package where you put this file.

import java.util.Vector;

import packagename.MyFeaturePredicate;

public class Concatenate extends MyFeaturePredicate {

private static final long serialVersionUID = 1L;

public Concatenate()

{

setArity(2);

setName("concatenate");

setReturnValueType(TYPE_WORD);

setArgValueType(new int[]{TYPE_WORD, TYPE_WORD});

}

public String apply(Vector args)

{

String expString1 = (String)args.get(0);

String expString2 = (String)args.get(1);

return (expString1 + expString2);

}

}

2. Updating the files

Now you need to make changes to two files in the same folder where your Concatenate.java is located. You should have the following two files in your folder - operators.txt and UserDefSymbols.java.

    1. operators.txt - In this you need to make an entry of the operator file that you just created above. So for this, your entry should be like packagename.Concateante, where packagename is the name of the package where your Concatenate.java is located.

    2. UserDefSymbols.java - If you go through the file, you can see that there is an entry where all operators that have so far been used are defined. You also need to add your own operator to the UserDefSymbols.java. For your case you need to add:

rete.addUserfunction(new Concatenate());

3. compileMyTutor.sh -Now run compileMyTutor.sh (on Mac or Linux) and compileMyTutor.bat (on Windows).

Adding a feature-predicate

1. Make a Java class

The method of defining a feature-predicate is similar to adding an operator for the SimStudent. A feature-predicate is a boolean function that tests the existence of a certain feature. For example, isPolynomial("3x+1") returns true, but isConstantTerm("3x") returns false. Instead of returning true/false, a feature predicate function returns the string "T" when the feature exists, "null" otherwise. The newly created class must extend the class "MyFeaturePredicate" you previously defined in the section "Defining types of arguments". Just like with the operators, the arguments passed to the "apply()" function of this class is the value of a working memory element (e.g. the value of a cell, or a text box). In this example, you will be writing a feature-predicate to check if a number is negative.

/*********************************************************************

**********************************************************************

************************IsNegative .java.java********************************

**********************************************************************

**********************************************************************/

package packagename; // packagename is the package where you put this file.

import java.util.Vector;

import jess.Fact;

import jess.JessException;

import jess.Rete;

public class IsNegative extends MyFeaturePredicates. {

public IsNegative() {

setArity(1);

setName("is-negative");

setArgValueType(new int[]{TYPE_NUMBER});

}

public String apply(Vector args) {

String expString=(String)args.get(0);

return (expString.charAt(0)=='-') ? "T" : null;

}

}

2. Updating the files

Now you need to make changes to two files in the same folder where your IsNegative.java is located. You should have the following two files in your folder - feature-predicates.txt and UserDefSymbols.java.

    1. feature-predicates.txt - In this you need to make an entry of the feature predicates file that you just created above. So for this, your entry should be like packagename.IsNegative, where packagename is the name of the package where your Concatenate.java is located.

    2. UserDefSymbols.java - If you go through the file, you can see that there is an entry where all operators that have so far been used are defined. You also need to add your own operator to the UserDefSymbols.java. For your case you need to add:

rete.addUserfunction(new IsNegative());

3. compileMyTutor.sh -Now run compileMyTutor.sh (on Mac or Linux) and compileMyTutor.bat (on Windows).

Adding a constraint

1. Make a Java class

The constraint defines physical relations among working memory elements (i.e., components on the tutoring interface such as text boxes and cells). The method of defining constraints is similar to defining operators for the SimStudent except that the new class extends TableConstraint. In this example, you will be writing a constraint that checks if the two cells are in the consecutive row. As you will notice in the example bellow, one difference between an operator / feature-predicate and a constraint is that in a constraint, the arguments passed in the "apply()" function are Jess facts and not their values (i.e. the Jess fact that represents a cell and not the value in the cell).

/*********************************************************************

**********************************************************************

************************ConsecutiveRow.java***************************

**********************************************************************

**********************************************************************/

package packagename; // packagename is the package where you put this file.

import java.util.Vector;

import jess.Fact;

import jess.JessException;

import jess.Rete;

public class ConsecutiveRow extends TableConstraint {

public ConsecutiveRow() {

setArity(2);

setName("consecutive-row");

}

public String apply(Vector args,Rete rete) {

try {

return consecutiveRow((Fact)args.get(0),(Fact)args.get(1),rete);

}

catch(JessException e) {

e.printStackTrace();

return null;

}

}

}

2. Updating the files

Now you need to make changes to two files in the same folder where your ConsecutiveRow.java is located. You should have the following two files in your folder - constraints.txt and UserDefSymbols.java.

  1. constraints.txt - In this you need to make an entry of the constraint file that you just created above. So for this, your entry should be like packagename.ConsecutiveRow, where packagename is the name of the package where your ConsecutiveRow.java is located.

  2. UserDefSymbols.java - If you go through the file, you can see that there is an entry where all topological constraints that have so far been used are defined. You also need to add your own constraint to the UserDefSymbols.java. For your case you need to add:

rete.addUserfunction(new ConsecutiveRow());

3. compileMyTutor.sh -Now run compileMyTutor.sh (on Mac or Linux) and compileMyTutor.bat (on Windows).

Defining an Input Matcher

1. Make a Java class

Finally, you must specify you own domain dependent input matcher, in the same package you copied the files from SimStudent toolkit. An "input matcher" is a feature predicate that takes two string arquments (expressions) as an input, and determines if these two expressions are equivalent. The "equivalence" of two expressions is defined by the target domain. For example, strings "6" and "4+2" may not be the same, but in the algebra domain they express the same thing. Thus the input matcher for the algebra domain should return true (i.e. "T") when given these arguments.

In the following example, an input matcher is presented that checks if two strings are identical.

/*********************************************************************

**********************************************************************

************************IsEquivalent.java******************************

**********************************************************************

**********************************************************************/

package packageName;

import java.util.Vector;

import edu.cmu.pact.miss.FeaturePredicate;

public class IsEquivalent extends FeaturePredicate{

public IsEquivalent() {

setArity(2);

setName("is-equivalent");

}

public String apply(Vector args) {

inputMatcher((String)args.get(0),(String)args.get(1))

}

public String inputMatcher(String exp1, String exp2){

return (exp1.equals(exp2)? "T" : null;

}

}

2. Updating the files

Now you need to make changes on one file in the same folder where your Square.java is located. You should have the file "runTutor.sh" in this folder. For SimStudent to use the input matcher you have defined, you must add the line

TutorArg="${TutorArg} -ssInputMatcher packageName.IsEquivalent"

in your runTutor.sh file.

Notes

It is recommended that before running the tutor you remove from the following files any operator, feature predicate, or constraint that you have not written for your domain:

  • operators.txt

  • constraints.txt

  • feature-predicates.txt

  • UserDefSymbols.java

Last Updated May 21, 2015