Difference between revisions of "Variable"

From Developer Documents
Jump to navigation Jump to search
 
(39 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
= Intro =
 
= Intro =
  
This interface is the most important abstraction in Simantics between the user and the implementation. Variable interfaces addresses
+
The Variable interface provides an uniform access model to data in Simantics. It includes
  
* Browsing of the model structure (see [[Model Browser]])
+
* Tree-structured address space for accessing model '''structure''' and '''properties'''
* Browsing and manipulation of objects (see [[Selection View]])
+
* Uniform access to model '''configuration''' and '''state'''
* Tabular data (see [[Spreadsheets]])
 
  
The implementation of Simantics variables combines data from ontological definitions, modelled structures and custom implementation in integrated software plugins. The interface needs to address
+
Key use cases include
  
* Ontological data
+
* Browsing of the '''model configuration and states''' (see [[Model Browser]])
* Modelled reusable and procedural structures (see [[Structural]])
+
* '''Manipulation of objects''' (see [[Selection View]])
* Runtime data of solvers (see [[Experiments]])
+
* Representation of '''tabular data''' (see [[Spreadsheets]])
* Historical data stored in the database
 
  
The solution includes
+
Main functional requirements include representation of
  
* Establishing the concept of a context which represents a unique structure and valuation for a model.
+
* '''Structural models''' with '''procedural''' features (see [[Structural]])
* Establishing a contextual varible identity for referencing the same variable in different contexts.
+
* '''Runtime''' data of solvers (see [[Experiments]])
 
+
* '''Historical''' data from experiments
Identified technical issues include
+
* '''Ontological''' data
 
 
* On-demand generation of semantic representation
 
* Textual and semantic variable identities with conversions for user manipulation and database persistence
 
* Unit conversions
 
* Value formatting
 
* Textual user input parsing and validation
 
* Modelling and evaluation of expressions
 
* Representation of time series values
 
  
 
= Solution =
 
= Solution =
  
The following concepts are identifier
+
'''Variable''' is a tree-structured view into the Simantics data model. Each variable is either a '''child''' or a '''property''' and can further contain own children and properties. The difference between a child and a property is that a property contains a '''value'''.
  
*A '''''model''''' is a container for all data related to some user task e.g. simulation model.
+
The variable space browsing methods are used to obtain
*A '''''variable''''' is an interface with means for producing children, properties and value
 
*A '''''context''''' is an entity under a '''''model''''' which spans a set of '''''variables''''' specified by '''''paths'''''
 
*A '''''path''''' is an ''identifier'' which can be used to retrieve a variable from given '''context'''
 
*A path '''''separator''''' which identifies traversal of parents based on '''''role'''''. Specified separators are '.', '/', '#'
 
  
The specified roles are defined as
+
* all children
*Parent variable is denoted by the '.' separator
+
* children by name
*Children are denoted by the '/' separator.
+
* all properties
*Properties are denoted by the '#' separator. All properties contain a value.
+
* properties by name
 +
* variable by '''path'''
 +
* '''parent''' variable
  
Procedural children and variables are used with large data sets. E.g. query-based views can be exposed. Procedural properties also enable efficient slicing of arrays e.g. URI#Array_Property/0-99
+
Other services are
  
A model typically contains a number of contexts which are browsed using the Variable interface. Typical contexts are//
+
* accessing (get/set) the value of a property variable
 +
* querying adapter interfaces
  
*The base context, which can be used to browse the structure and configuration values of the model
+
A set of built-in properties is required for all variables. These properties have also dedicated interface methods.
*Configuration value contexts with e.g. set point values for some variables
 
*Experiment contexts with structure and values retrieved from simulator using Databoard Accessor interface
 
  
Generic tools such as Model Browser, Selection View, Diagram, Chart, Spreadsheet, OperationUI use the the path identifiers to refer to their data. Once a desired Variable has been obtained its value can be accessed using direct database requests or Databoard Accessor.
+
* '''URI''', which is an unique string identifier and locator of the variable in the tree structure
 +
* '''Parent''', which is the tree parent of the variable
 +
* '''HasName''', which is a local identifier for the variable within its parent. Names are also used to create URIs.
 +
* '''HasLabel''', which is a short textual representation of the variable
 +
* '''hasStandardResource''', which returns the context resource in a '''standard graph-based child variable'''
 +
* '''Represents''', which is a resource representing the variable '''TODO'''
 +
* '''Type''', which returns a single type resource classifying the variable
 +
* '''Role''', which tells whether the variable is a '''child''' or a '''property''' (TODO: could be deprecated)
 +
* '''DATATYPE''', which returns the data type of a property variable. (TODO: should be HasDatatype)
  
The variable system processes two kinds of textual identifiers
+
Other properties and the structure of the variable space is configured in the semantic graph or contributed by custom variable implementations.
  
*A '''''URI''''' is a complete reference to a '''''variable'''''
+
Variables can be located using an '''URI''', which
**Examples: 
 
***http://www.asd.org/Projects/AprosProject/AprosModel1/BaseRealization/Diagram/PI_X#PI_MASS_FLOW
 
***http://www.asd.org/Projects/AprosProject/AprosModel1/ExperimentConfiguration/RunName/Diagram/PI_X#PI_MASS_FLOW#Unit
 
**Models and contexts are identified by URIs
 
***http://www.asd.org/Projects/AprosProject/AprosModel1
 
***http://www.asd.org/Projects/AprosProject/AprosModel1/ExperimentConfiguration/RunName
 
  
*A '''''path''''' is a relative reference to a '''''variable''''' based on another '''''variable'''''
+
* Represents the path from '''root variable''' (Variables.getRootVariable) into the variable such that
**A path can contain a number of leading parent steps denoted by '.'
+
** '''var/xx''' represents a getChild(unescaped(xx)) query from var
**Examples:
+
** '''var#yy''' represents a getProperty(unescaped(yy)) query from var
***/Diagram/PI_X#PI_MASS_FLOW
+
** the escape function is bidirectional (URIStringUtils.escape and URIStringUtils.unescape)
***./Diagram2/PI_X#PI_MASS_FLOW#HasDatatype
+
* Is an '''identifier''' (two variables with the same URI are the same in the sense of Java Object.equals)
 +
* Is a random access identifier (by Variables.getVariable())
 +
* Examples:
 +
** http://www.acme.org/Projects/MyProject/MyModel/Configuration/DiagramN/PI_X#PI_MASS_FLOW
 +
** http://www.acme.org/Projects/MyProject/MyModel/ExperimentConfiguration/RunName/DiagramN/PI_X#PI_MASS_FLOW#DATATYPE
  
Path identifiers can also be serialized into graph representation, which is name-independent and survives export/import. In e.g. structural this is an ordered set of path separators and configuration resources.
+
A common way of identifying a variable is by supplying a '''base variable''' and a '''Relative Variable Identifier (RVI)'''.
  
= Assumptions =
+
* RVI represents the path from '''base variable''' into another variable
 +
* In textual RVI notation (Variable.browse())
 +
** '''.''' represents a getParent() query
 +
** '''/xx''' represents a getChild(unescaped(xx)) query
 +
** '''#yy''' represents a getProperty(unescaped(yy)) query
 +
* A literal RVI (Variable.getRVI(), RVI.resolve())
 +
** Does not need to depend on the names visible in the URI
 +
** Is based on e.g. resource ids
 +
** Survives export/import
  
* §1 Everything after '#' has a value
+
A '''model''' variable represents the root of a Simantics model
* §2 For all realization resources a variable can be obtained by graph.adapt(r, Variable.class)
+
* Model variables correspond directly to instances of SIMU.Model in the database
* §3 For all realization resources the variable URI equals graph.getURI(r)
+
** Variable and resource URIs are the same
* §4 A variable can be part of at most one Context
+
* For all variables under a model, the model variable can be obtained using Variables.getModel()
* §5 A variable can be part of at most one Model
 
* $6 All values can be accessed using either Variable.getValue or Variable.getInterface(Accessor.class)
 
* $7 All properties retrieved using Variable.browseProperties shall be available using Variable.getProperty
 
  
= Standard modelling in Layer0 =
+
A '''context''' variable under a model provides a view into a '''state''' of the model
 +
* The '''Type''' property of a context variable is inheried from L0.RVIContext
 +
* A RVI obtained from e.g. model configuration can be used to access similarly identified data from different model states
 +
** E.g. /DiagramX/ComponentY#PropertyZ can have different values in different contexts
 +
* The '''configuration''' context can be used to browse the structure and configuration values of the model
 +
* ''Experiment run''' contexts are used to monitor values from simulations or history
  
[[File:Realizations.png]]
+
The variable interface is bound to Simantics database '''transactions''', but is not in any other way bound to the semantic data model, which allows variable implementations to represent arbitrary data models somehow related to Simantics models. All variable-based requests can be listened using standard Simantics database listening.
  
== Standard required properties ==
+
Procedural children and variables are used with large data sets. E.g. query-based views can be exposed. Procedural properties also enable efficient slicing of arrays e.g. URI#Array_Property/0-99
 
 
=== For all variables ===
 
  
* NAME: String
+
= General assertions in the Variable model =
  
The name of the resource exactly as in the URI.
+
* All variables except the '''root''' have a parent
 +
* Let p be the parent of v. Then v#URI equals p#URI + '/'|'#' + escape(v#HasName)
 +
* Iff v1#URI equals v2#URI, then v1 and v2 are equal in Java Object.equals sense
 +
** Other identifications can be established by property values
 +
* A variable v2 equaling variable v can always be obtained by calling Variables.getVariable(v#URI)
 +
** The obtained variable '''need not be the same object''' but '''can be'''
 +
** Variables.getVariable can return also variables, which are not reachable by browsing ('''TODO''')
 +
* All property variables have a value
 +
** No child variable has a value
 +
** The value of a property variable may be '''null'''
 +
** The value of '''DATATYPE''' property can be null for property variables i.e. property values can be arbitrary Java objects
 +
* Variable.getProperty returns all the variables returned from Variable.browseProperties
 +
** Variable.getProperty can return variables not returned by Variable.browseProperties
 +
* Variable.getChild returns all the variables returned from Variable.browseChildren
 +
** Variable.getChild can return variables not returned by Variable.browseChildren
 +
* A variable can be part of at most one '''model'''
 +
* A variable can be part of at most one '''context'''
 +
* All values can be accessed using either Variable.getValue or Variable.getInterface(Accessor.class)
 +
* All properties retrieved using Variable.browseProperties shall be available using Variable.getProperty
 +
* No variable can have a name that begins with one or more dots ('.') due to '.' being a reserved character for browsing the variable address space towards the parent. In other words names matching the pattern '''"^\.+.*$"''' are forbidden.
  
* LABEL: String
+
= Standard properties =
  
The standard textual representation for the variable.
+
== Connections ==
  
* TYPE: Resource
+
* Connection point properties are classified with '''http://www.simantics.org/Structural-1.0/ConnectionRelation'''
 +
* The value of a connection point property is an object of class '''org.simantics.structural2.variables.Connection'''
  
A single type related to the variable.
+
<pre>
  
* URI: String
+
public interface Connection {
  
The variable URI, see Implementations
+
  Collection<Variable> getConnectionPoints(ReadGraph graph) throws DatabaseException;
  
* SERIALIZED: String
+
}
  
An immutable string identified for this part
+
</pre>
  
* PARENT: Variable
+
It is assumed that instances of '''org.simantics.structural2.variables.Connection''' have proper identities (equals/hashCode) based on flattened connections.
  
The parent variable
+
The value of connection point properties can be '''null'''. This means that the connection point is not connected.
  
* ROLE: Role
+
== String editing operations ==
  
Is Role.Property if URI contains '#', else is Role.Child. If role is Role.Property, then the variable has a value.
+
* '''HasDisplayValue''' is a String-valued property, which is a formatted and unit-converted representation of the property value.
 +
* '''expression''' is a String-valued property, which is an SCL-formula used to compute the value of the property. If the property can be computed using an expression, this property is always available and returns '''null''' if an expression has not been defined.
 +
* '''validator''' is a '''org.simantics.utils.strings.StringInputValidator'''-valued property. The validator is used for checking values to be written into a property.
  
* CONTEXT : Variable
+
<pre>
  
The context variable of this variable. The URI of the context variable is a prefix of the URI of this variable.
+
public interface StringInputProblem {
  
* CHILD_COUNT: Integer
+
  enum Severity {
 +
    Error, Warning
 +
  }
  
The amount of children.
+
  String getDescription();
 +
  int getBegin();
 +
  int getEnd();
 +
  Severity getSeverity();
  
* PROPERTY_COUNT: Integer
+
}
  
The amount of properties.
+
public interface StringInputValidator {
  
=== For variables, where Role is Role.Child ===
+
  Collection<StringInputProblem> validate(String input);
  
* REPRESENTS: Resource
+
}
  
The configuration resource related to this variable.
+
</pre>
  
=== For variables, where Role is Role.Property ===
+
* '''valid''' is a Boolean-valued property, which indicates whether the property contains a valid value.
  
* REPRESENTS: Resource
+
== Property properties ==
  
The literal resource related to this variable.
+
* '''required''' is a Boolean-valued property, which indicates that the property should contain a valid value
 +
* '''default''' is a Boolean-valued property, which indicates that the property value is a default value
 +
* '''readOnly''' is a Boolean-valued property, which indicates that the property value can not be written
  
* EXPRESSION: String
+
== Complex datatypes ==
  
The expression for determining the value of the property. Null if there is no expression.
+
* Record
 +
** All named fields are '/name'
 +
** Tuples are named after position e.g. '/11'
 +
* Union
 +
** Union does not show in URI
 +
* Array
 +
** Elements are named after position e.g. '/i-11'
 +
* Map
 +
** Items are named after key
  
* PROPERTY_RESOURCE: Resource
+
= Standard graph based variable implementation =
  
The property ( <R L0.HasProperty) resource related to this variable.
+
The standard child and property variables are
  
* CONTAINER_RESOURCE: Resource
+
* org.simantics.db.layer0.variable.StandardGraphChildVariable
 +
* org.simantics.db.layer0.variable.StandardGraphPropertyVariable
  
The subject of the property statement.
+
Their implementation is based on the following interfaces
  
* DATATYPE: Datatype
+
<pre>
  
The data type of the property.
+
package org.simantics.db.layer0.variable;
  
* VALUE_LABEL: String
+
public interface VariableMap {
 +
    Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException;
 +
    // Must not modify collection in any way not possible with put-method.
 +
    void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException;
 +
}
  
A descriptive representation of the value. Applies all modelled formatting. Used in user interface.
+
</pre>
  
== Standard adapters ==
+
<pre>
  
* org.simantics.db.layer0.variable.VariableSpaceManipulator: for modifying the variable space
+
package org.simantics.db.layer0.variable;
* org.simantics.db.layer0.variable.InputValidator: for validating user input
 
* org.simantics.db.layer0.variable.Formatter: for representing values
 
* org.simantics.databoard.units.IUnitConverter: for representing values according to user needs
 
  
 +
public interface ValueAccessor {
 +
    Object getValue(ReadGraph graph, Variable context) throws DatabaseException;
 +
    Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException;
 +
    void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException;
 +
    void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException;
 +
}
  
== Standard implementation ==
+
</pre>
  
=== org.simantics.db.layer0.variable.StandardRealizationVariable(resource) ===
+
Implementations of the above interfaces can be bound to instances and types in the database via the following standard properties
  
* Children with ChildMapOfResource(resource) + adapt(child, Variable.class)
+
<pre>
* Literal-valued properties with PropertyMapOfResource(resource) + adapt(resource, PropertyFactory.class)
 
* Resource-valued properties with FunctionalRelationMapOfResource(resource)
 
  
=== org.simantics.db.layer0.variable.StandardPropertyVariable(variable, resource) ===
+
L0.Entity
 +
  >-- L0.hasStandardResource ==> "Resource" <R L0.HasProperty : L0.FunctionalRelation
 +
    L0.HasDescription "The backend resource for standard graph-based Variables."
 +
  >-- L0.domainProperties ==> "VariableMap" <R L0.HasProperty : L0.FunctionalRelation
 +
    L0.HasDescription "Retruns a map of all domain properties of the entity."
 +
  >-- L0.domainChildren ==> "VariableMap" <R L0.HasProperty : L0.FunctionalRelation
 +
    L0.HasDescription "Retruns a map of all domain children of the entity."
 +
  >-- L0.valueAccessor ==> "ValueAccessor" <R L0.HasProperty : L0.FunctionalRelation
 +
    L0.HasDescription "Returns an interface for accessing the value."
 +
  @L0.assert L0.hasStandardResource
 +
    L0.Functions.hasStandardResource : L0.Function
 +
  @L0.assert L0.domainProperties L0.Functions.standardChildDomainProperties
 +
  @L0.assert L0.domainChildren L0.Functions.standardChildDomainChildren
  
* Children with ChildMapOfResource + adapt(Variable.class)
+
L0.Value
* Properties with PropertyMapOfResource + adapt(PropertyFactory.class)
+
  @L0.assert L0.domainProperties L0.Functions.standardPropertyDomainProperties
 +
  @L0.assert L0.domainChildren L0.Functions.standardPropertyDomainChildren
 +
  @L0.assert L0.valueAccessor L0.Functions.standardValueAccessor
  
=== org.simantics.db.layer0.variable.StandardPropertyFactory ===
+
</pre>
  
 +
The standard implementation is
  
 +
<pre>
  
The standard implementations are ResourceVariable and PropertyVariable. ResourceVariable is based on a single resource with a named PartOf chain to RootLibrary. PropertyVariable is based on a pair of Variable and Resource <R HasProperty.
+
@SCLValue(type = "ValueAccessor")
 +
public static ValueAccessor standardValueAccessor = new ValueAccessor() {
  
In the standard implementation
+
@Override
 +
public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
 +
    StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
 +
try {
 +
ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
 +
if(propertyAccessor != null) return propertyAccessor.getValue(graph, context);
 +
if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
 +
Layer0 L0 = Layer0.getInstance(graph);
 +
return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
 +
}
 +
if(variable.adapterClass != null) {
 +
return graph.adaptRelated(variable.parentResource, variable.property, variable.adapterClass);
 +
} else {
 +
return graph.getRelatedValue2(variable.parentResource, variable.property, variable);
 +
}
 +
} catch (NoSingleResultException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
 +
} catch (DoesNotContainValueException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
 +
} catch (DatabaseException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
 +
}
 +
}
 +
@Override
 +
public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
 +
    StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
 +
try {
 +
ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
 +
if(propertyAccessor != null) return propertyAccessor.getValue(graph, context, binding);
 +
if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
 +
Layer0 L0 = Layer0.getInstance(graph);
 +
return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
 +
}
 +
if(variable.adapterClass != null) {
 +
return graph.adaptRelated(variable.parentResource, variable.property, variable.adapterClass);
 +
} else {
 +
return graph.getRelatedValue2(variable.parentResource, variable.property, variable, binding);
 +
}
 +
} catch (NoSingleResultException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph));
 +
} catch (DoesNotContainValueException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph));
 +
} catch (DatabaseException e) {
 +
throw new MissingVariableValueException(variable.getPossibleURI(graph));
 +
}
 +
}
 +
@Override
 +
public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
 +
    StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
 +
ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
 +
if(propertyAccessor != null) {
 +
propertyAccessor.setValue(graph, context, value);
 +
return;
 +
}
 +
Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
 +
if(modifier == null) modifier = VariableUtils.defaultInputModifier;
 +
try {
 +
modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
 +
} catch (BindingConstructionException e) {
 +
throw new DatabaseException(e);
 +
}
 +
}
 +
@Override
 +
public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
 +
    StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
 +
ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
 +
if(propertyAccessor != null) {
 +
propertyAccessor.setValue(graph, context, value, binding);
 +
return;
 +
}
 +
Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
 +
if(modifier == null) modifier = VariableUtils.defaultInputModifier;
 +
modifier.apply(graph, context, value, binding);
 +
}
 +
};
  
*getChild returns all named children of the associated resource linked with ConsistsOf and adapted to Variable
+
@SCLValue(type = "VariableMap")
*getProperty collects all p so that there exists (s, p <R L0.HasProperty, o) and adapts them to PropertyVariableFactory which is used to create the Variable
+
public static VariableMap standardChildDomainProperties = new VariableMap() {
**PropertyVariable additionally also includes all p <R L0.HasProperty browsed from the object of its corresponding statement
 
*getValue for PropertyVariable first searches for L0.HasExpression from the object of its corresponding statement and tries to adapt org.simantics.db.layer0.variable.Expression from its object. If this fails PropertyVariable tries ReadGraph.getValue from the object of its corresponding statement
 
*browse(ReadGraph, Resource) uses getChild with URIStringUtils.escape(graph.getRelatedValue(resource, b.HasName))
 
*browse(ReadGraph, String) uses getChild and getProperty for browsing segments starting with '#' and '/' and browse(ReadGraph, String) from RootLibrary for the RVI with the last segment removed
 
*getURI uses ReadGraph.getURI for ResourceVariable and variable.getURI + "#" + URIStringUtils.escape(graph.getRelatedValue(resource, b.HasName)) for PropertyVariable
 
  
 +
@Override
 +
public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
 +
      final StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
 +
      return getPossiblePropertyFromContext(graph, variable, variable.resource, name);
 +
}
 +
@Override
 +
public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
 +
    StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
 +
    collectPropertiesFromContext(graph, variable, variable.resource, map);
 +
}
 +
 +
};
  
= Frequent cases =
+
@SCLValue(type = "VariableMap")
 +
public static VariableMap standardPropertyDomainProperties = new VariableMap() {
  
1. Given variable v, obtain model
+
@Override
  Procedure: call Variables.getModel(graph, v)
+
public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
2. Given variable v, obtain realization
+
        StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
  Procedure: call Variables.getRealization(graph, v)
+
        Resource literal = graph.getPossibleObject(variable.parentResource, variable.property);
3. Given Variable URI, obtain Variable
+
        if(literal != null) {
  Procedure: call Variables.getVariable(graph, uri)
+
        Variable result = getPossiblePropertyFromContext(graph, variable, literal, name);
4. Given Variable URI, obtain textual RVI
+
        if(result != null) return result;
  Procedure: call Variables.getRVI(graph, v)
+
        }
+
        return getPossiblePropertyFromContext(graph, variable, variable.property, name);
5. Given a configuration resource r and context variable obtain variable
+
}
  Procedure: call Variable.browse(graph, r)
+
@Override
6. Given two variables v1 and v2, obtain RVI of second based on first
+
public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
  call Variables.getRVI(graph, v1, v2)
+
StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
7. Given Realization URI and RVI, obtain Variable
+
    collectPropertiesFromContext(graph, variable, variable.property, map);
  call Variables.getVariable(graph, uri, rvi)
+
        Resource literal = graph.getPossibleObject(variable.parentResource, variable.property);
 +
        if(literal != null) collectPropertiesFromContext(graph, variable, literal, map);
 +
}
 +
 +
};
  
8. Obtain string representation for value of Variable v
+
@SCLValue(type = "VariableMap")
  -Obtain value val (Object) by v.getValue()
+
public static VariableMap standardChildDomainChildren = new VariableMap() {
  -Obtain converter c by v.getInterface(IUnitConverter.class)
 
  -Obtain converted value cval (Object) by c.convert(val)
 
  -Obtain formatter f by v.getInterface(Formatter.class)
 
  -Obtain String representation by f.format(cval)
 
  
= Varible space modelling =
+
@Override
 +
public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
 +
StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
 +
Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(variable.resource));
 +
Resource child = children.get(name);
 +
if(child == null) return null;
 +
return graph.getPossibleContextualAdapter(child, variable, Variable.class, Variable.class);
 +
}
 +
@Override
 +
public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
 +
StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
 +
for(Map.Entry<String, Resource> entry : graph.syncRequest(new UnescapedChildMapOfResource(variable.resource)).entrySet()) {
 +
String name = entry.getKey();
 +
Resource child = entry.getValue();
 +
Variable var = graph.getPossibleContextualAdapter(child, variable, Variable.class, Variable.class);
 +
if(var != null) {
 +
map.put(name, var);
 +
} else {
 +
System.err.println("No adapter for " + child + " in " + variable.getURI(graph));
 +
}
 +
}
 +
}
 +
 +
};
  
== Cases ==
+
@SCLValue(type = "VariableMap")
 +
public static VariableMap standardPropertyDomainChildren = new VariableMap() {
  
=== Datatypes ===
+
@Override
 +
public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
 +
        StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
 +
    Datatype dt = variable.getDatatype(graph);
 +
    if (dt instanceof ArrayType) {
 +
        ChildReference ref = getPossibleIndexReference(name);
 +
        if (ref != null)
 +
            return new SubliteralPropertyVariable(variable, ref);
 +
    }
 +
    return null;
 +
}
 +
@Override
 +
public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
 +
}
 +
 +
};
  
==== Record ====
+
</pre>
  
* All named fields are '/name'
+
== Informally ==
* Tuples are named after position e.g. '/11'
 
  
==== Union ====
+
Standard child modelling assumes a context resource res.
  
* Union does not show in URI
+
* childResource : where (res, L0.ConsistsOf, childResource)
 +
* childVariable = graph.adaptContextual(childResource, this, Variable.class, Variable.class)
  
==== Array ====
+
Standard property modelling assumes a context resource res.
  
* Elements are named after position e.g. '/11'
+
* (predicate, object) : where (res, predicate, object) and (predicate <R L0.HasProperty)
 +
* childProperty = graph.adaptContextual(object, ModelledVariablePropertyDescriptor(this, predicate), Variable.class)
  
==== Map ====
+
For property variables there are two context resources available, the associated value and the predicate. Properties are found from the value context first and then from the predicate context.
  
* Items are named after key
+
The graph.adaptContextual step is an extension point for defining custom variable implementations contributed using the adapter (adapters.xml) mechanism.
  
Take for example http://www.asd.org/Project/AprosModel1/BaseRealization/a/TA_1#TA11_POINT_ELEV
+
= Frequent cases =
 
 
=== Property sets ===
 
 
 
Two alternatives
 
 
 
==== Set is also a value ====
 
 
 
http://www.asd.org/Project/BalasModel1/BaseRealization/Valve1/FSET#Set1/Flowrate
 
 
 
Set1 is now a Databoard record.
 
 
 
==== Only items are values ====
 
 
 
http://www.asd.org/Project/BalasModel1/BaseRealization/Valve1/FSET/Set1#Flowrate
 
  
 +
1. Given variable v, obtain model (Resource)
 +
  call Variables.getModel(graph, v)
 +
2. Given variable v, obtain context (Variable)
 +
  call Variables.getContext(graph, v)
 +
3. Given Variable URI, obtain Variable
 +
  call Variables.getVariable(graph, uri)
 +
4. Obtain string representation for value of Variable v
 +
  obtain value of v#HasDisplayValue
  
= Modelling of related concepts =
+
to be continued...
  
== Units ==
+
= Open issues =
  
== Formatting ==
+
== Generic simulator support in Variable ==
  
= Standard variables =
+
Current hypothesis is that we extends standard graph based implementation by a special interface, which serves the simulator (or other) data. The standard implementation then combines data from graph and simulator. The special interface is designed such that is supports custom synchronization and lazy operation and can also be directly utilized in remote simulators.
 
 
== Cases ==
 
 
 
=== Inferred configuration values from structural ===
 
 
 
=== Expressions ===
 
  
 
== Variable syntax in SCL ==
 
== Variable syntax in SCL ==
Line 292: Line 463:
 
** Local variable definitions may shadow context
 
** Local variable definitions may shadow context
  
 +
== Experiment modelling ==
  
= Experiment modelling =
+
The modelling of experiment run contexts and the value types of properties in states is still underway.
 
 
Each running or stored historical experiment in Simantics is modelled as a realization under the Model. Realizations have URIs as defined by ReadGraph.getURI. Some realizations are entirely backed by the semantic graph and some are backed by an Accessor provided by a running simulator or a time series stored as a file in the semantic graph. The structure of the Variable tree under the realization is generated from the semantic model configuration and can be implemented in different ways ranging from persistent graph to lazily produced transient virtual graph. The realizations are browsed using Variable interface methods and variable values can be obtained using Variable methods or by obtaining Databoard Accessor using Variable.getInterface. Each variable serves an instantaneous value and each variable can also contain a property which serves a time series associated to the variable such as in historical data or sampled history of a running experiment.
 
  
= Validation scenario =
+
= Refactoring =
  
The standard model is validated in a headless structural-based setup with
+
* <strike>add Collection<Variable> browseProperties(ReadGraph graph, String classification) throws DatabaseException;</strike>
 +
* add standard property '''classifications''', which returns a set of strings
 +
* <strike>deprecate browseChildren, browseProperties => add get</strike>
  
*Structural configuration with joined diagrams and reusable component types
 
*Procedural children provided by simulator
 
*Accessor-backed simulator
 
  
 
[[Category: Database Development]]
 
[[Category: Database Development]]

Latest revision as of 12:59, 20 March 2013

Intro

The Variable interface provides an uniform access model to data in Simantics. It includes

  • Tree-structured address space for accessing model structure and properties
  • Uniform access to model configuration and state

Key use cases include

Main functional requirements include representation of

  • Structural models with procedural features (see Structural)
  • Runtime data of solvers (see Experiments)
  • Historical data from experiments
  • Ontological data

Solution

Variable is a tree-structured view into the Simantics data model. Each variable is either a child or a property and can further contain own children and properties. The difference between a child and a property is that a property contains a value.

The variable space browsing methods are used to obtain

  • all children
  • children by name
  • all properties
  • properties by name
  • variable by path
  • parent variable

Other services are

  • accessing (get/set) the value of a property variable
  • querying adapter interfaces

A set of built-in properties is required for all variables. These properties have also dedicated interface methods.

  • URI, which is an unique string identifier and locator of the variable in the tree structure
  • Parent, which is the tree parent of the variable
  • HasName, which is a local identifier for the variable within its parent. Names are also used to create URIs.
  • HasLabel, which is a short textual representation of the variable
  • hasStandardResource, which returns the context resource in a standard graph-based child variable
  • Represents, which is a resource representing the variable TODO
  • Type, which returns a single type resource classifying the variable
  • Role, which tells whether the variable is a child or a property (TODO: could be deprecated)
  • DATATYPE, which returns the data type of a property variable. (TODO: should be HasDatatype)

Other properties and the structure of the variable space is configured in the semantic graph or contributed by custom variable implementations.

Variables can be located using an URI, which

A common way of identifying a variable is by supplying a base variable and a Relative Variable Identifier (RVI).

  • RVI represents the path from base variable into another variable
  • In textual RVI notation (Variable.browse())
    • . represents a getParent() query
    • /xx represents a getChild(unescaped(xx)) query
    • #yy represents a getProperty(unescaped(yy)) query
  • A literal RVI (Variable.getRVI(), RVI.resolve())
    • Does not need to depend on the names visible in the URI
    • Is based on e.g. resource ids
    • Survives export/import

A model variable represents the root of a Simantics model

  • Model variables correspond directly to instances of SIMU.Model in the database
    • Variable and resource URIs are the same
  • For all variables under a model, the model variable can be obtained using Variables.getModel()

A context variable under a model provides a view into a state of the model

  • The Type property of a context variable is inheried from L0.RVIContext
  • A RVI obtained from e.g. model configuration can be used to access similarly identified data from different model states
    • E.g. /DiagramX/ComponentY#PropertyZ can have different values in different contexts
  • The configuration context can be used to browse the structure and configuration values of the model
  • Experiment run' contexts are used to monitor values from simulations or history

The variable interface is bound to Simantics database transactions, but is not in any other way bound to the semantic data model, which allows variable implementations to represent arbitrary data models somehow related to Simantics models. All variable-based requests can be listened using standard Simantics database listening.

Procedural children and variables are used with large data sets. E.g. query-based views can be exposed. Procedural properties also enable efficient slicing of arrays e.g. URI#Array_Property/0-99

General assertions in the Variable model

  • All variables except the root have a parent
  • Let p be the parent of v. Then v#URI equals p#URI + '/'|'#' + escape(v#HasName)
  • Iff v1#URI equals v2#URI, then v1 and v2 are equal in Java Object.equals sense
    • Other identifications can be established by property values
  • A variable v2 equaling variable v can always be obtained by calling Variables.getVariable(v#URI)
    • The obtained variable need not be the same object but can be
    • Variables.getVariable can return also variables, which are not reachable by browsing (TODO)
  • All property variables have a value
    • No child variable has a value
    • The value of a property variable may be null
    • The value of DATATYPE property can be null for property variables i.e. property values can be arbitrary Java objects
  • Variable.getProperty returns all the variables returned from Variable.browseProperties
    • Variable.getProperty can return variables not returned by Variable.browseProperties
  • Variable.getChild returns all the variables returned from Variable.browseChildren
    • Variable.getChild can return variables not returned by Variable.browseChildren
  • A variable can be part of at most one model
  • A variable can be part of at most one context
  • All values can be accessed using either Variable.getValue or Variable.getInterface(Accessor.class)
  • All properties retrieved using Variable.browseProperties shall be available using Variable.getProperty
  • No variable can have a name that begins with one or more dots ('.') due to '.' being a reserved character for browsing the variable address space towards the parent. In other words names matching the pattern "^\.+.*$" are forbidden.

Standard properties

Connections


public interface Connection {

  Collection<Variable> getConnectionPoints(ReadGraph graph) throws DatabaseException;

}

It is assumed that instances of org.simantics.structural2.variables.Connection have proper identities (equals/hashCode) based on flattened connections.

The value of connection point properties can be null. This means that the connection point is not connected.

String editing operations

  • HasDisplayValue is a String-valued property, which is a formatted and unit-converted representation of the property value.
  • expression is a String-valued property, which is an SCL-formula used to compute the value of the property. If the property can be computed using an expression, this property is always available and returns null if an expression has not been defined.
  • validator is a org.simantics.utils.strings.StringInputValidator-valued property. The validator is used for checking values to be written into a property.

public interface StringInputProblem {

  enum Severity {
    Error, Warning
  }

  String getDescription();
  int getBegin();
  int getEnd();
  Severity getSeverity();

}

public interface StringInputValidator {

  Collection<StringInputProblem> validate(String input);

}

  • valid is a Boolean-valued property, which indicates whether the property contains a valid value.

Property properties

  • required is a Boolean-valued property, which indicates that the property should contain a valid value
  • default is a Boolean-valued property, which indicates that the property value is a default value
  • readOnly is a Boolean-valued property, which indicates that the property value can not be written

Complex datatypes

  • Record
    • All named fields are '/name'
    • Tuples are named after position e.g. '/11'
  • Union
    • Union does not show in URI
  • Array
    • Elements are named after position e.g. '/i-11'
  • Map
    • Items are named after key

Standard graph based variable implementation

The standard child and property variables are

  • org.simantics.db.layer0.variable.StandardGraphChildVariable
  • org.simantics.db.layer0.variable.StandardGraphPropertyVariable

Their implementation is based on the following interfaces


package org.simantics.db.layer0.variable;

public interface VariableMap {
    Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException;
    // Must not modify collection in any way not possible with put-method.
    void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException;
}


package org.simantics.db.layer0.variable;

public interface ValueAccessor {
    Object getValue(ReadGraph graph, Variable context) throws DatabaseException;
    Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException;
    void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException;
    void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException;
}

Implementations of the above interfaces can be bound to instances and types in the database via the following standard properties


L0.Entity
  >-- L0.hasStandardResource ==> "Resource" <R L0.HasProperty : L0.FunctionalRelation
    L0.HasDescription "The backend resource for standard graph-based Variables."
  >-- L0.domainProperties ==> "VariableMap" <R L0.HasProperty : L0.FunctionalRelation 
    L0.HasDescription "Retruns a map of all domain properties of the entity."
  >-- L0.domainChildren ==> "VariableMap" <R L0.HasProperty : L0.FunctionalRelation 
    L0.HasDescription "Retruns a map of all domain children of the entity."
  >-- L0.valueAccessor ==> "ValueAccessor" <R L0.HasProperty : L0.FunctionalRelation 
    L0.HasDescription "Returns an interface for accessing the value."
  @L0.assert L0.hasStandardResource
    L0.Functions.hasStandardResource : L0.Function
  @L0.assert L0.domainProperties L0.Functions.standardChildDomainProperties
  @L0.assert L0.domainChildren L0.Functions.standardChildDomainChildren

L0.Value
  @L0.assert L0.domainProperties L0.Functions.standardPropertyDomainProperties
  @L0.assert L0.domainChildren L0.Functions.standardPropertyDomainChildren
  @L0.assert L0.valueAccessor L0.Functions.standardValueAccessor

The standard implementation is


@SCLValue(type = "ValueAccessor")
public static ValueAccessor standardValueAccessor = new ValueAccessor() {

	@Override
	public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
	    	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
		try {
			ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
			if(propertyAccessor != null) return propertyAccessor.getValue(graph, context);
			if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
				Layer0 L0 = Layer0.getInstance(graph);
				return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel);
			}
			if(variable.adapterClass != null) {
				return graph.adaptRelated(variable.parentResource, variable.property, variable.adapterClass);
			} else {
				return graph.getRelatedValue2(variable.parentResource, variable.property, variable);
			}
		} catch (NoSingleResultException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
		} catch (DoesNotContainValueException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
		} catch (DatabaseException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph), e);
		}
	}
	@Override
	public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
	    	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
		try {
			ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
			if(propertyAccessor != null) return propertyAccessor.getValue(graph, context, binding);
			if(graph.sync(new IsEnumeratedValue(variable.getRepresents(graph)))) {
				Layer0 L0 = Layer0.getInstance(graph);
				return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding);
			}
			if(variable.adapterClass != null) {
				return graph.adaptRelated(variable.parentResource, variable.property, variable.adapterClass);
			} else {
				return graph.getRelatedValue2(variable.parentResource, variable.property, variable, binding);
			}
		} catch (NoSingleResultException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph));
		} catch (DoesNotContainValueException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph));
		} catch (DatabaseException e) {
			throw new MissingVariableValueException(variable.getPossibleURI(graph));
		}
	}
	@Override
	public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
	    	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
		ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
		if(propertyAccessor != null) {
			propertyAccessor.setValue(graph, context, value);
			return;
		}
		Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
		if(modifier == null) modifier = VariableUtils.defaultInputModifier; 
		try {
			modifier.apply(graph, context, value, Bindings.getBinding(value.getClass()));
		} catch (BindingConstructionException e) {
			throw new DatabaseException(e);
		}
	}
	@Override
	public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
	    	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
		ValueAccessor propertyAccessor = getPossiblePropertyValueAccessor(graph, variable);
		if(propertyAccessor != null) {
			propertyAccessor.setValue(graph, context, value, binding);
			return;
		}
		Function4<WriteGraph, Variable, Object, Object, String> modifier = context.getPossiblePropertyValue(graph, Variables.INPUT_MODIFIER);
		if(modifier == null) modifier = VariableUtils.defaultInputModifier; 
		modifier.apply(graph, context, value, binding);
	}
};

@SCLValue(type = "VariableMap")
public static VariableMap standardChildDomainProperties = new VariableMap() {

	@Override
	public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
	       	final StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
	       	return getPossiblePropertyFromContext(graph, variable, variable.resource, name);
	}
	@Override
	public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
    		StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
    		collectPropertiesFromContext(graph, variable, variable.resource, map);
	}
		
};

@SCLValue(type = "VariableMap")
public static VariableMap standardPropertyDomainProperties = new VariableMap() {

	@Override
	public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
        	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
        	Resource literal = graph.getPossibleObject(variable.parentResource, variable.property);
        	if(literal != null) {
        		Variable result = getPossiblePropertyFromContext(graph, variable, literal, name);
        		if(result != null) return result;
        	}
        	return getPossiblePropertyFromContext(graph, variable, variable.property, name);
	}
	@Override
	public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
		StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
    		collectPropertiesFromContext(graph, variable, variable.property, map);
        	Resource literal = graph.getPossibleObject(variable.parentResource, variable.property);
        	if(literal != null) collectPropertiesFromContext(graph, variable, literal, map);
	}
		
};

@SCLValue(type = "VariableMap")
public static VariableMap standardChildDomainChildren = new VariableMap() {

	@Override
	public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
		StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
		Map<String, Resource> children = graph.syncRequest(new UnescapedChildMapOfResource(variable.resource));
		Resource child = children.get(name);
		if(child == null) return null;
		return graph.getPossibleContextualAdapter(child, variable, Variable.class, Variable.class);
	}
	@Override
	public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
		StandardGraphChildVariable variable = (StandardGraphChildVariable)context;
		for(Map.Entry<String, Resource> entry : graph.syncRequest(new UnescapedChildMapOfResource(variable.resource)).entrySet()) {
			String name = entry.getKey();
			Resource child = entry.getValue();
			Variable var = graph.getPossibleContextualAdapter(child, variable, Variable.class, Variable.class);
			if(var != null) {
				map.put(name, var);
			} else {
				System.err.println("No adapter for " + child + " in " + variable.getURI(graph));
			}
		}
	}
		
};

@SCLValue(type = "VariableMap")
public static VariableMap standardPropertyDomainChildren = new VariableMap() {

	@Override
	public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
        	StandardGraphPropertyVariable variable = (StandardGraphPropertyVariable)context;
    		Datatype dt = variable.getDatatype(graph);
    		if (dt instanceof ArrayType) {
    		    ChildReference ref = getPossibleIndexReference(name);
    		    if (ref != null)
    		        return new SubliteralPropertyVariable(variable, ref);
    		}
    		return null;
	}
	@Override
	public void getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
	}
		
};

Informally

Standard child modelling assumes a context resource res.

  • childResource : where (res, L0.ConsistsOf, childResource)
  • childVariable = graph.adaptContextual(childResource, this, Variable.class, Variable.class)

Standard property modelling assumes a context resource res.

  • (predicate, object) : where (res, predicate, object) and (predicate <R L0.HasProperty)
  • childProperty = graph.adaptContextual(object, ModelledVariablePropertyDescriptor(this, predicate), Variable.class)

For property variables there are two context resources available, the associated value and the predicate. Properties are found from the value context first and then from the predicate context.

The graph.adaptContextual step is an extension point for defining custom variable implementations contributed using the adapter (adapters.xml) mechanism.

Frequent cases

1. Given variable v, obtain model (Resource)

  call Variables.getModel(graph, v)

2. Given variable v, obtain context (Variable)

  call Variables.getContext(graph, v)

3. Given Variable URI, obtain Variable

  call Variables.getVariable(graph, uri)

4. Obtain string representation for value of Variable v

  obtain value of v#HasDisplayValue

to be continued...

Open issues

Generic simulator support in Variable

Current hypothesis is that we extends standard graph based implementation by a special interface, which serves the simulator (or other) data. The standard implementation then combines data from graph and simulator. The special interface is designed such that is supports custom synchronization and lazy operation and can also be directly utilized in remote simulators.

Variable syntax in SCL

  • Implement variable interface methods as normal functions
    • Example: browse entrypoint "./Out#sdf"
  • Use . and #-for browsing
    • How to browse parent? Explicit function
    • Example: (parent entrypoint).Out#sdf
    • Special operator for parents (binds stronger than . or #):
    • Example: !entrypoint.Out#sdf
  • Resolve entrypoints in the context
    • Example: Out#sdf
    • Local variable definitions may shadow context

Experiment modelling

The modelling of experiment run contexts and the value types of properties in states is still underway.

Refactoring

  • add Collection<Variable> browseProperties(ReadGraph graph, String classification) throws DatabaseException;
  • add standard property classifications, which returns a set of strings
  • deprecate browseChildren, browseProperties => add get