The Algebraic Level of Amine Platform :
Structures And Operations
by
Adil KABBAJ
AmineObject interface : common operations
Matching interface: A Conceptual Algebra
BindingContext interface and binding information
Collection objects : AmineList and AmineSet (APIs)
Complex objects : Term, Concept, Relation and Conceptual Graph (APIs)
AmineObjects: A "service/dispatcher" class
Appendice : Amine Structures Notation Grammar
Previous: We suggest to consider first Introduction followed by First Level (Ontology, Conceptual Structures, and Lexicon).
The second level of Amine Platform is the algebraic level: various types of structures and operations are provided. Amine Platform allows the use of elementary Java classes (like Boolean, Integer, Double and String) and provides in addition its proper Amine elementary classes which are variant of the elementary Java classes (like Identifier, AmineInteger, AmineDouble and AmineBoolean). Amine provides also collection structures (like AmineList which extends the Java class ArrayList and AmineSet which extends the Java class HashSet) and complex structures (like Term, Concept, Relation and Conceptual Graph).
In addition to operations that are specific to each kind of structure, Amine provides a set of basic common operations (clear(), clone(), toString()) and a set of matching-based operations (match(), equal(), unify(), subsume(), maximalJoin(), and generalize()). These operations are specified in AmineObject and Matching interfaces respectively. These interfaces are implemented by Amine structures. Moreover, Amine is "open" to Java, i.e. any Java class that implements AmineObject and Matching interfaces becomes a "full" Amine structure. AmineObject, Matching and other Amine interfaces are interfaces or gates that allow a Java class to enter/become an Amine structure.
Note that Amine structures are generic structures ; they can contain variables. Operations on Amine structures take into account variables binding (the association between a variable and its value) and binding context (the programming context that determines how variable binding should be interpreted and resolved, i.e. how to get the value of a variable). In Amine, binding context is a "basic concept": variable binding and binding context are explicitly presented and specified in Amine. This decision constitutes a relevant feature and a key step toward more genericity: it is relevant since generic structures (like Amine structures) are essential in any programming environment. Also, binding context in Amine constitutes a key step toward more genericity since BindingContext is defined in Amine as a Java interface, i.e. as a specification or a contract between Amine and any Java class that pretends to implement a binding context. In this way, Amine is not committed to a specific binding context; any Java class that implements BindingContext interface is considered by Amine as a binding context. For instance, the two Amine's programming languages PROLOG+CG and SYNERGY will implement the BindingContext interface. Amine users can define their own programming context that implement BindingContext interface, and so, be able to interpret correctly Amine (generic) structures. An example of this possibility is provided in ContextBinding.
Amine structures can be used in any kind of application. Any one of them can be used as a description structure for CSs in an ontology. They can be used also in various programming contexts (Prolog+CG, Synergy, and others).
Amine is implemented upon Java and it allows the use of elementary Java classes (like Boolean, Integer, Double and String) and provides in addition its proper elementary classes which are variants of elementary Java classes: Identifier, AmineInteger, AmineDouble and AmineBoolean. This section introduces Amine elementary classes.
See Lexicons for the definition of the elementary type Identifier and its API.
AmineInteger, AmineDouble and AmineBoolean
Like the Boolean Java class, AmineBoolean is a Wrapper class for boolean value but unlike the class Boolean, the value of an AmineBoolean object can be modified; the value is muable, that is why this class implements the Muable interface. The same principle holds for AmineInteger and AmineDouble.
Variables can be components of a collection (AmineList) or of a complex structure (Term, Concept, Relation, CG). A variable can be also a component of a Java class that is integrated to Amine.
Definition: Amine Variable is a specialization of Identifier and so, it inherits all the methods of Identifier including the possibility to ignore or not character case. A variable can be bind (associated) to a value. Variable binding is determined by the binding/programming context and the binding information related to the variable.
A variable identifier in Amine should start with a letter followed optionally by a digit or underscore. After the digit or the underscore, a variable can have any sequence of characters. A variable identifier can begin also with an underscore followed optionally by any sequence of characters. There is also special cases of identifiers: "super", "this", "x_source", and "y_target" are considered as variables.
Note: Variable is explicitly defined as an Amine object to avoid the check, at each time, of the identifier in order to infer if it is a variable identifier or a constant identifier. Also, the explicit definition of Variable allows a clear definition of the operations specified in AmineObject and Matching interfaces.
Variable API
Variable implements AmineObject and Matching, and has its own methods. Let us consider briefly Variable's API:
- constructor(): creates a Variable with a specific string,
- finalize(): destroy the Variable,
- clear(): clear the content of the variable,
- clone(): clone the value of the variable (if binding is to be
considered) or the variable itself,
- generateNewVariable(): create a new variable with a generated name,
- toString(): provide a textual formulation of the value of the variable (if binding is to be considered),
- all matching based operations (equal(), generalize(), maximalJoin(), subsume(), subsumeWithResult(), and unify()) are defined in term of the generic match() operation: match the current variable with the specified object according to the specified type of matching, binding context and binding information. First, the operation attempts to get values of the involved variables. If both variables have specific values, the matching is applied on their values, otherwise the operation considers different cases of matching depending on the type of the matching. See Detail on Structures Matching for details on the different cases of matching that are considered by variable matching.
See Amine APIs Specification for further details on specification of all Variable's methods.
Amine Platform provides several interfaces (AmineObject, Matching, BindingContext, DescriptionWithGenus, Muable, ToString) that play the role of gates allowing any Java class to integrate Amine platform. These interfaces testify some aspects of Amine genericity and openess.
Definition: ToString interface specifies the operation toString() that should return the textual formulation of an object, taking into account the specified lexicon of the current ontology.
public interface ToString {
public String toString(Lexicon lexicon) throws
ToStringException;
}
ToString interface is specialized by AmineObject interface.
AmineObject interface : common operations
Definition: AmineObject interface specifies a set of methods/operations that are implemented by Variable, collection and complex structures of Amine Platform. Of course, AmineObject interface can be implemented by any Java class defined by the user and then the class can be used like any Amine structure.
Here is a brief specification of AmineObject methods :
- clear() clears the content of the current object,
- clone() creates a clone of the current object,
- getVariables() get the variables that are contained in the current object,
- toString() returns the textual formulation of the content of the current object.
Most of the operations have two variants: one that takes into account binding context and resolution and another that ignore them.
Matching interface: A Conceptual Algebra
Definition: Matching interface specifies a set of matching-based operations that are implemented by Variable, collection (AmineSet, AmineList), and complex structures (Term, CG, Concept, Relation) of Amine Platform. Matching interface specifies the Conceptual Agebra of Amine.
Matching interface can be implemented by any Java class defined by the user, and so the class becomes fully integrated to the algebraic level of Amine and can be used like any Amine structure.
Here is a brief specification of Matching methods :
- match() matchs the current object and the specified object,
- equal() checks if the current object is equal to the specified object,
- generalize() computes the generalization of the current object and the specified object,
- maximalJoin() computes the maximal join of the current object and the specified object,
- subsume() checks if the current object subsumes the specified object,
- subsumeWithResult() checks if the current object subsumes the specified object and returns the image of the current object on the specified object, and
- unify() attempts to unify the current object with the specified object.
The above operations have two variants: one that takes into account binding context and resolution and another that ignore them.
BindingContext interface and binding information
The basic feature of a variable is its binding with a value. The modality of this binding relation depends on the programming context where the structures (with variables) are used. For instance, Prolog+CG has an unification-based programming context with unification stack and variables renaming (or variables indices) as binding information related to each variable. Synergy has another programming context and various other programming contexts can be defined and used for other languages or applications. To allow this genericity and independence (i.e. independence of structures and operations from a specific programming context), Amine provides the BindingContext interface and binding information about the current object. Binding context and binding information constitute two parameters for the operations of AmineObject and Matching interface. For instance, a complete specification of an operation oper() (like maximalJoin(), unify(), etc.) is as follows :
public Object oper(BindingContext bindContext,
Object bindInf,
Object obj, Object bindInfObj);
The above specification means that oper() will operate on the current object and the specified object "obj" with the specified binding context "bindContext" (for both the current object and the specified object), with "bindInf" as the binding information specific to the current object and "bindInfObj" as the binding information specific to the object "obj". Note that binding information ("bindInf", "bindInfObj") are declared as Object; the Java root class. The exact nature of the binding information will depend on the programming context of each application.
Definition : BindingContext interface specifies two methods :
getValue(Object obj, Object bindInf) : if the object "obj" is not a variable, the object should be returned. If it is a variable, the method should look for the associated value (unless the variable is free) and returns the value.
setValue(Variable variable, Object value, Object bindInf) : Associate the value to the variable in the current binding context.
See BindingContext for an example of how a user can define his/her own programming context that implements BindingContext interface. Such a context is then used to interpret structures with variables and activate operations on these structures.
Remark: Identifying the binding context as a "primitive concept" in Amine algebraic level constitutes a relevant feature and a key step toward more genericity:
It is relevant since generic structures (structures with variables) are essential in any programming context and they are essential in Amine. Also, the notions of variable binding and binding context where binding resolution is performed are clearly presented and specified in Amine.
Binding context in Amine constitutes a key step toward more genericity since BindingContext is defined in Amine as a Java interface, i. as a specification or a contract between Amine and any Java class that pretends to implement a binding context. In this way, Amine is not committed to a specific binding context; any Java class that implements BindingContext interface can be considered by Amine as a binding context.
Definition: Muable interface specifies the method clone(). Hence any class that implements this interface should define this method.
public interface Muable {
public Object clone();
}
Definition: DescriptionWithGenus interface specifies the method getGenus() which should return an enumeration of Types CS that stand for the direct superTypes of the defined type (this later is defined as a specialization of those direct superTypes).
public interface DescriptionWithGenus {
public Enumeration getGenus();
}
Note: If concept type definition has to be specified in term of genus and differentia, then the used description scheme has to implement this interface. This is the case of CG.
Collection objects and their API : AmineList and AmineSet
AmineList
Definition: AmineList is a specialization of the Java class ArrayList. An element of an AmineList can be any Amine object (including Variable).
Syntax of an AmineList: An AmineList is a sequence of Amine objects separated by comma ',' and enclosed by '[' and ']'. An AmineList can be empty: no element in the list (i.e. []). An AmineList can terminate with the constructor operator ('|') followed by a variable (called constructor variable).
Examples : [23, June, 1980], [], [is, x, [76, toto], "Rita Franklin", aaa|y]
AmineList API
AmineList API provides two variants for most of its methods: one variant ignores variable binding and the other considers variable binding. AmineList implements AmineObject and Matching interfaces.
Let us consider first the operations that are proper to AmineList:
- constructor(): various constructors are provided,
- copy(): perform a deep copy of the list,
- isMember(): checks if the specified object is a member of the current list,
- parse(): parses a string that represents an AmineList,
- toAmineSet(): returns an AmineSet composed of the elements of the current list (if the elements of the list can be also elements of an AmineSet).
All the methods are defined with the possibility that the structures can contain variables: for instance, copy() performs a deep copy of the list, including the copy of variables values if binding context is defined (otherwise the variables are considered as undefined).
Also, the definition of AmineList follows the definition of list structure in Prolog language : a list can terminate with a constructor (|) followed by a variable and the methods take into account this possibility.
About the implementation of the Matching operations:
- equal(): tests if the two lists have the same number of elements and it checks equality of the elements according to their range. It considers also the case of list constructor at the end of lists in which case equal() will operate recursively,
- generalize(): attempts to generalize the elements of the two lists,
- maximalJoin(): attempts to perform maximalJon on the elements of the two lists,
- subsume(): checks if elements of the first list subsume their corresponding elements in the second list,
- unify() attempts to unify elements of the two list according to their range and like equal() it considers the presence of list constructor.
Examples:
Here is excerpts from the Java class AmineListTest that calls/uses most of the methods of AmineList. See BindingContext for examples on list unification.
parse() and toString()
The Java code below illustrates the use of methods parse() and toString() to allow an easy and "natural" manipulation of lists. The method parse() is static. Note also that the method toString() of AmineList is called implicitly by the method println(), when an AmineList is an argument.
AmineList
amineSimpleList = AmineList.parse("[a, 23, 78]");
AmineList amineEmptyList = AmineList.parse("[]");
AmineList amineEmbededList =
AmineList.parse("[bon,
[345, \"this is a sentence\", a], www]");
AmineList amineListWithConstr = AmineList.parse("[a, 23, 78|x]");
System.out.println("\nA simple List : " + amineSimpleList);
System.out.println("An Empty List : " + amineEmptyList);
System.out.println("An Embeded List : " + amineEmbededList);
System.out.println("Amine List With Constructor : " + amineListWithConstr);
Result of the above code:
A simple List : [a, 23, 78]
An Empty List : []
An Embeded List : [bon, [345, "this is a sentence", a], www]
Amine List With Constructor : [a, 23, 78|x]
Remark: We use brackets '[' and ']' as delimiters for both AmineList and
Concept structures. In general, distinction between a list and a concept is made
by syntactic analysis and by considering the context. But there is a case where the distinction is
not possible: [Identifier] (i.e. [Man]). If it occurs as an argument of a term
or as an element of a list, it can be interpreted as a list of
one element and the element is Identifier, or it can be
interpreted as a concept where only the type is specified. Of course, if the
above construct is used as a
concept of a CG, it is interpreted as a concept (i.e. [Man]<-agnt-[Eat]).
But the ambiguity occurs when the context can not help, i.e. pred(34, [Man],
quality). How to interpret [Man] in this case ? as a list or as a concept ? Our decision is to interpret, by default, [Man] and similar cases as a list. The user should
precise his/her description if he/she intend another interpretation. For
instance, to precise that [Man] is a concept (and not a list), user can specify
[Man :x] or [Man #0].
isMember() and toAmineSet()
The following code illustrates the use of two AmineList's methods: isMember() that tests if an element is a member of a list, and toAmineSet() that creates an AmineSet with the same elements as those of the original AmineList. In our example, toAmineSet() will abort because the list contains a variable; an object that can not be an element of an AmineSet.
AmineList with an ontology as background
An ontology is loaded (in the example: C:/ManOntology.ont), a lexicon is selected (in the example, the main lexicon), and an AmineList is parsed according to the specified lexicon. The code shows also that the internal representation of the list can be textualized in English or in French, depending on what lexicon is provided to the method toString(). To get the French lexicon for the current ontology, we use the method getLexicon().
Result of the above code:
The list [Drink, Man, Water, 23, fast] in English.
The same list in French : [Boire, Homme, Eau, 23, Rapide]
Convert to an AmineSet : {Fast, Man, Water, 23, Drink}
AmineList and Matching operations:
This example illustrates some methods of Matching: maximalJoin() and generalize().
Result of the above code:
amineEmbededList : [bon, [345, "this is a sentence", a], www]
newList : [bon, [345, "this is a sentence", 89], s]
result of maximalJoin: [bon, [345, "this is a sentence", 89], www]
result of generalize: [bon, [345, "this is a sentence", _v0], _v1]
See the Java class
AmineListTest for the
complete code, see
APIs Specification for the detailed specification of the AmineList API and
Detail on Structures
Matching for detail
on Amine structures matching.
AmineSet
Definition: AmineSet is a specialization of the Java class HashSet : Like a Set, no order is applied on the elements of an AmineSet. Also, only Amine elementary objects can be elements of an AmineSet.
Syntax of an AmineSet: AmineSet is a sequence of Amine elementary objects separated by comma ',' and enclosed by '{' and '}'. A variable cannot be an element of an AmineSet. A amineSet can be empty.
Examples: {bon, jour, "one string"}, {}, {one}.
AmineSet API
AmineSet implements AmineObject and Matching interfaces.
- Methods inherited from HashSet have been overriden to take into account the constraint that only Amine elementary objects can be elements of an AmineSet : this is the case for add() and addAll(). Other methods of AmineSet include :
- constructors,
- canBeElement() is a static method that checks if the given element can be an element of an AmineSet,
- clear() clears the content of the set,
- clone() and copy() to construct a shallow copy of the current set,
- intersection() computes the intersection of the current set and returns the intersection set,
- isMember() checks if the specified element is an element of the current set,
- isSubSet() checks if the specified set is a subset of the current set,
- parse() parses a string that represents an AmineSet,
- toAmineList() returns an AmineList composed of the same elements as the current set,
- union() returns the union of the current set with the specified set or the specified element.
About the implementation of the Matching operations:
- equal() uses the inherited method equals() of HashSet to test equality of the two sets,
- generalize() corresponds to intersection(),
- maximalJoin() corresponds to union(),
- subsume() corresponds to isSubSet(), and
- unify() corresponds to subsume() since variables are not allowed in AmineSet.
Examples:
Here is excerpts from the Java class AmineSetTest that calls/uses most of the methods of AmineSet.
parse() and toString()
The Java code below illustrates the use of methods parse() and toString() to allow an easy and "natural" manipulation of sets. The method parse() is static. Note also that the method toString() of AmineSet is called implicitly by the method println(), when an AmineSet is an argument.
AmineSet amineSet = AmineSet.parse("{bo, 78, true}");
System.out.println("\nAn amine set: " + amineSet);
Result of the above code:
An amine set : {bo, 78, true}
AmineSet proper operations: add(), isMember(), intersection(), union(), isSubSet()
The AmineSet copyOfAmineSet: {true, bo, 78}
Attempt to
add the variable a23 to copyOfAmineSet :
copyOfAmineSet.add(new Variable("a23"))
returns false because a variable is not a simple object and so, cannot be added to an amine Set.
Here is examples of some AmineSet's methods in action:
AmineSet with an Ontology as background
This is similar to the case of AmineList: an ontology is loaded (in the example: C:/ManOntology.ont), a lexicon is selected (in the example, the main lexicon), and an AmineSet is parsed according to the specified lexicon. The code shows also that the internal representation of the set can be textualized in English or in French, depending on what lexicon is provided to the method toString().
Result of the above code:
The AmineSet {Water, Man, Fast, Drink} in English.
The same amineSet in French : {Eau, Homme, Rapide, Boire}
AmineSet and Matching operations: equal(), maximalJoin(),
generalize(), etc.
Value of the sets in the example:
copyOfAmineSet : {bo, ba, 67, 78, jour}
newSet : {89, "this is a sentence", bon, 78, jour}
newSet2 : {89, "this is a sentence", bon, 78, jour}
Operations and Results:
See the Java class AmineSetTest for a more complete view of the call/use of most of the methods of AmineSet, see APIs Specification for the detailed specification of the AmineSet API and Detail on Structures Matching for detail on Amine structures matching.
Complex objects : Term, Concept, Relation and Conceptual Graph (CG) APIs
Term
Definition: Term is a specialization of AmineList. An argument of a term can be any Amine object (including Variable). A term is a special case of AmineList: the term identifier corresponds to the first element of a list (and it should be an identifier, a string or a CS reference) and a term can not end with a list constructor.
Syntax of a Term: Term is an identifier followed by a sequence of Amine objects separated by comma ',' and enclosed by '(' and ')'.
Examples of term: person(Nina, x), father(Karl, [Hurk, Frik, Karla], [Man:Karl]-ageOf->[Age =56]).
Term API
Since Term is a specialization of AmineList, it inherits methods of AmineList and of course, inheritance includes the implementation of AmineObject and Matching interfaces. Some methods have been overriden:
- toString() is overriden to returns a textual formulation of the term (as a term not as a list)
- copy(): construct a term (not an AmineList).
About the implementation of Matching operations: the four operations (equal, generalize, maximalJoin and subsume) have the same pattern : the two terms should have the same number of arguments and the operation is applied recursively on the arguments of the two terms according to their range.
Examples:
Here is excerpts from the Java class TermTest that calls/uses most of the methods of Term. See BindingContext for examples on term unification.
parse() and toString()
The Java code below illustrates the use of methods parse() and toString() to allow an easy and "natural" manipulation of terms. The method parse() is static. Note also that the method toString() of Term is called implicitly by the method println(), when a term is an argument.
Term simpleTerm = (Term) Term.parse("pere(Ahmad,
Karim)");
System.out.println("\nA simple term : " + simpleTerm);
Term embededTerm = (Term) Term.parse(
"person(Ahmed, 34, address(453, \"Ishbilya
road\", Rabat), TaxiDriver)");
System.out.println("An embeded term : " + embededTerm);
Result of the above code:
A simple term : pere(Ahmad, Karim)
An embeded term : person(Ahmed, 34,
address(453, "Ishbilya road", Rabat),
TaxiDriver)
Use of Term with an ontology as background
An ontology is loaded (in the example: C:/ManOntology.ont), a lexicon is selected (in the example, the main lexicon), and a term is parsed according to the specified lexicon. The code shows also that the internal representation of the term can be textualized in English or in French, depending on what lexicon is provided to the method toString().
Result of the above code:
The Term Drink(Man, Water, Fast, [Car, Bus, Pxv]) in English.
The same term in French : Boire(Homme, Eau, Rapide, [Voiture, Autobus, Pxv])
Term and Matching operations: equal(), maximalJoin(), generalize(), etc.
Operations and Results:
See the Java class TermTest for the call/use of most of the methods of Term, see APIs Specification for the detailed specification of the Term API and Detail on Structures Matching for detail on Amine structures matching.
Concept, Relation and Conceptual Graph (CG) : These structures are defined in CG .
Appendice : Amine Structures Notation Grammar
Syntactic rules presented here are conform to the EBNF notation : (X | Y) means category X OR category Y, (X)* means 0 or several occurrences of X, {X}* means 1 or several occurrences of X, [X] means that X is optional.
R1. Amine_Object_Var ::= Amine_Object | Variable .
R2. Amine_Object ::= Elementary_Object | AmineList | AmineSet | Term | CG .
R3. Elementary_Object ::= Integer | Double | Boolean | String | Identifier .
R4. AmineList ::= "[" [ Amine_Object_Var ("," Amine_Object_Var)* [ "|" Variable] ] "]" .
R5. AmineSet ::= "{" [ Elementary_Object ("," Elementary_Object)* ] "}" .
R6. Term ::= Identifier "(" Amine_Object_Var ("," Amine_Object_Var)* ")" .
R7. Identifier ::= Letter Letter (Character)* .
R9. Variable ::= ( Letter [ (Digit | "_") (Character)* ] ) | ( "_" (Character)* ) .
AmineObjects: A "service/dispatcher" class
The class AmineObjects provides static methods only. It can be viewed as a "common" and "service" class in the sense that the class provides methods common to all Amine structures. It can be viewed also as a "dispatcher"; the class redirects the treatment according to the type of the structure.
Note that methods specified in interfaces like AmineObject, Matching, and ToString are defined in this class which considers both simple objects (like Integer, Boolean, etc.) and structured objects (like AmineList, Concept, CG, etc.).
Also, the class AmineObjects provides a "generic" parse() method which determines the type of object to parse and performs directly the parsing or deleguates the parsing to a specific parse() method that is associated to a specific Amine structure. This class is responsible also for the analysis of the XML formulation of an ontology and for the production of an internal representation of the ontology.