Equations and External Equations

Last revised 02/04/2023. Contact us.

Introduction

Equations, also known as functions (see Foundational Concepts in Semantic Modeling, Part 2), are snippets of procedural code that provide instructions for computing an output from a set of inputs. At the declaration, or definition level, inputs are typed variables. At execution time, inputs are actual values passed in to the function. In the function declaration, an output is unnamed but its type is defined as the return type of the function. Actually, in the general case a function can return multiple values, as functions can in Python. Functions can be very important in modeling a domain. For example, many reasoners allow rules to have built-in functions to handle math operations, and without the ability to do math operations it may not be possible to construct a useful model.

Equations vs. External Equations

The SADL grammar supports two kinds of equations, one in which the body of the function (the set of instructions for computing the function output) is defined in the SADL statement, and another where the body of the function exists somewhere outside of the ontology. The first kind uses the Equation grammar keyword.

Equation areaOfCircle (float radius) returns float: PI*radius^2 .

Equation volumeOfCylinder (float radius, float height) returns float: areaOfCircle(radius) * height.

As the example illustrates, one Equation may use another in its body. Here the volumeOfCylinder Equation uses areaOfCircle in its body.

The second kind of equation uses the External grammar keyword. This kind of equation provides a name and signature, but the actual specification of the body of the equation (the computational instructions) is located elsewhere. This gives rise to at least two and as many as three resource identifiers.

  1. The external equation has an identifier within the defining model. This consists of the URI of the model containing the statement and the name given following the External keyword. In the example below were in the model with URI "http://sadl.org/examples/externals", then the external equation's URI would be "http://sadl.org/examples/externals#abs".
  2. The identifier of the external implementation of the computational instructions. For implementations expressed coded in Java, this is the fully qualified name of the implementing method. For the example below, this is the "java.lang.Math.abs".
  3. Optionally, an External statement may also contain a "located at" URL string. In the example below, this is specified as "http://java.lang.Math" for purposes of illustration, although that URL isn't useful in this case.

External abs (float x) returns float: "java.lang.Math.abs"
        located
 at "http://java.lang.Math".

Note: in the example above, the external identity URI is not a conformant URI, but rather is the Java package, class, and method name of the external Java method to which the equation maps. For information on how to wrap any Java class method that takes primitive data as inputs and and returns a primitive data type output in a SADL External statement to make it available for use in reasoning, see Wrapping Java Class Methods for the Jena Reasoner.

User-defined Equations Versus Reasoner Built-in Functions

The examples in the previous section are all user-defined equations. Such user-defined equations may or may not be executable during reasoning, depending upon the reasoner/translator pair chosen and their ability to invoke the function. Reasoner/translator pairs may also have a known set of functions which can be used in models. These are defined as  external equations in the SadlBuiltinFunctions.sadl model in the project's ImplicitModel folder. These functions will normally be more tightly integrated with the reasoner that user-defined functions, as is the case with Jena built-ins, or they may be functions native to the language as is the case with the SWI-Prolog reasoner. The content of the SadlBuiltinFunctions.sadl model is obtained from the reasoner/translator pair itself. Generally speaking, built-in functions in the SadlBuiltinFunctions.sadl model, even if implemented in Java, will not conform to the access mechanism described above and illustrated with java.lang.Math.abs. For example, built-in functions for the Jena Reasoner are implemented by a class, not a single method, and take Jena class instances as inputs rather than primitive data types.

While named functions declared with either the Equation or External keyword can be used in expressions in SADL or derivative grammars, using the functions to do actual computation is a task for the reasoner or other related processors.

Signatures

The name of the equation and the type of inputs allowed and the type of output generated is specified in the equation's signature. This information is useful for type checking during model construction. The format of the signature is the name, followed by an opening parenthesis, followed by the type and name of the each argument, each type/name pair separated by a comma, followed by a closing parenthesis, followed by the types of the returned values, comma separated if more than one. The syntax is shown below, where the angle brackets enclose a grammar conforming type or name but are not part of the syntax.

    <name>(<type of 1st argument> <name of first argument>, <type of second argument> <name of second argument>....)<type of first returned value>, <type of second returned value>...

The examples above provide concrete illustrations of signatures.

There are some special notations available for use in signatures. The most vague ambiguous type symbol is the unknown indicator, "--", which is used without a name.

    External foo (--) returns -- : "http://entirely/vague#foo".

This tells us that we do not know what kind of inputs foo accepts or what kind of outputs should be generated. This does not mean that we can't reference the function, only that we know  nothing that will allow us to do type checking while building the model.

An ellipsis (...) is used to indicate a variable number of arguments. An ellipsis may be typed or untyped. A typed ellipsis is preceded by the type of the inputs that are expected. An ellipsis does not have an associated name.

    External formatString(string fmt, float ... vals) returns string : "java.lang.String.format".

This tells us that the formatString function takes a string as the first argument, named "fmt", followed by any number of float inputs, and returns a string as output.

    External print(...) returns --: "com.ge.research.sadl.jena.reasoner.builtin.Print".

This signature tells us that the print function can take any number of inputs of unspecified type and what it will return is not known.

Special Consideration for List and UnittedQuantity Built-in Inputs

Some built-in functions may allow inputs which are of type List (see Lists in SADL) or of type UnittedQuantity (see UnittedQuantities in SADL). In order to be able to properly do type checking, built-in functions should be able to tell the reasoner/translator pair whether such inputs are allowed. This information is in addition to the argument and return type information contained in the equation signature. The following rules describe how arguments types interact with list and unitted quantity support.

  1. If a given argument is of a specified type and the function supports lists, then a list with the elements which are of that type are assumed to be valid.
  2. Since a unitted quantity always has a numeric value as well as a unit, if an argument or a returned value has a numeric type and the function supports unitted quantities, it is assumed that a input or output of type UnittedQuantity (or a subclass thereof) is valid.

Additional Argument and Return Type Information

The SADL grammar supports additional information about function arguments and return types. There is support for three special cases.

  1. It is possible that a function does not return a value. In this case the SADL grammar allows the "None" keyword to be used as the return type, e.g., returns None .
  2. It is possible that a function is ill-defined, especially in the case of built-in functions provided by the reasoner and declared in the SadlBuiltinFunctions.sadl file in the ImplicitModel folder. Either for one or more arguments or for the return type,"--" may be used to indicate that the argument or the return type is unknown, or is of a type which cannot be represented in the grammar, such as a list.

    External sadlListToString(--) returns string: "com.naturalsemantics.sadl.jena.reasoner.builtin#sadlListToString".


  3. Some functions may have a variable number of arguments, zero or more. In Java, this is called "VarArgs". In SADL this is indicated with an ellipsis.The ellipsis may follow a type and precede an argument name, or it may appear as an argument by itself. In the first instance the ellipsis indicates that there are a variable number of arguments of the specified type. In the second case the ellipsis indicates that the variable number of arguments can be of any type. In any case, there can only be one argument that uses the ellipsis, either typed or untyped, and it must be the last declared argument. Examples include:

    External formatString<(string fmt, ...) returns string: "java.lang.String.format".
    // The first argument is a string, followed by any number of arguments of any type.

    External strConcat(string str1, string ... moreStrs) returns string: "org.apache.jena.reasoner.rulesys.builtins#strConcat".
    // The first argument is a string, followed by any number of arguments of type string.

While these could be combined, as in this example of a method that takes any type of first argument followed by any number of additional arguments of any type, care should be taken to match the use of special types with what the underlying function actually expects.

External print(--, ...) returns --: "com.ge.research.sadl.jena.reasoner.builtin#print".

Translation to OWL

Translation of equations and external equations to OWL uses the meta-model defined in the SADL Implicit Model. Excluding augmented types, the meta-model is the following.

Language is a class.
{
Java, Python, Text, OtherLanguage} are instances of Language.
Script
is a class,
  described
by language with a single value of type Language,
  described
by script with a single value of type string.

^Equation is a class,
  described
by expression with values of type Script.
arguments
describes ^Equation with a single value of type DataDescriptor List.
returnTypes
describes ^Equation with a single value of type DataDescriptor List.

ExternalEquation is a type of ^Equation,
  described
by externalURI with a single value of type anyURI,
  described
by externalURL with values of type anyURI.

DataDescriptor is a class,
  described
by localDescriptorName with values of type string,
  described
by dataType with values of type anyURI
  described by variableNumArguments with values of type boolean,
  described by descriptorVariable.

localDescriptorName of DataDescriptor has at most 1 value.

dataType of DataDescriptor has at most 1 value.
descriptorVariable
of DataDescriptor has at most 1 value.

The variables which are arguments of an equation have an explicit order which must be preserved in the OWL representation. Therefore the arguments of an equation are a list in order to make the order explicit--in this case a DataDescriptor List. The same is true of returnedTypes as it is possible that more than one value will be returned by equations in some languages. The scope of a variable in an equation is limited to that equation. Two equations in a SADL model (which corresponds to an XML namespace by SADL design) might have argument variables with the same name but they are distinct, unrelated variable instances. Therefore, in the OWL representation we cannot just use the variable name as it appears in the signature as the unique identifier of the variable since the scope of the name can be no more narrow than the current namespace. However, since equation names must be unique within a SADL model, we can create unique identifiers by concatenating the variable name with the equation name. This concatenated name becomes the local name of the value of the descriptorVarible property of instances of the DataDescriptor class. The actual name as it appears in the equation signature is preserved as the value of localDescriptorName. An instance of a GPVariable (definition not shown in the meta-model above, see augmented types) is created and given the unique URI constructed from the namespace URI and the concatenation of the equation localname and the argument local name.

Use of this meta-model is illustrated by the following OWL snippet showing the translation of the areaOfCircle equation above.


Observe that the sadlimplicitmodel:arguments and sadlimplicitmodel:returnTypes properties have values of type _:b0, a subclass of the sadllistmodel:List. Each element of these lists is an instance of a sadlimplicitmodel:DataDescriptor, which captures the variable local and model name, for the argument, and the type, xsd:float, for both the argument and returned value.

The translation of the external equation abs provides a second example.


In this case there is no expression with a language and script but instead there is an externalURI (identity of the equation) and an externalURL (where to find the equation).

See also:

  1. Augmented types: capturing additional knowledge in equation declarations
  2. The SADL Implicit Model, where the meta-model for Equations and Externals is defined