Language

Purpose

This document contains the language definition for the Brahms system. This document serves two purposes:

  1. Defining the modeling capabilities of Brahms. This document gives descriptions of the modeling concepts, the formal syntax for the modeling concepts and the semantics related to the modeling concepts. This document describes the language to be used for building Brahms models.
  2. A requirements specification for the parser for Brahms models. The parser will check the model for errors and will create a compiled version of the model which serves as the input for the Brahms virtual machine.

Intended Audience

This document is intended for anyone who wants to build models in Brahms. They will have to comply to the syntax and semantics as defined in this document. This document is also intended for the development team developing the compiler for the Brahms models.

Usage

This document defines the modeling language for Brahms. This document is to be used by model builders to create Brahms models. Brahms model builders will have to comply to the language as defined in this document. This document is also used as a requirements specification for the parser that needs to be build to parse these models.

The language element are defined in BNF (Backus Naur Form) grammar rules. The notation used in these grammar rules is given in the table.

ConstructInterpretation
::= * + {} [] | .Symbols part of the BNF formalism
X ::= YThe syntax of X is defined by Y
{X}Zero or one occurrence of X
X*Zero or more occurrences of X
X+One or more occurrences of X
X | YOne of X or Y (exclusive or)
[X]Grouping construct for specifying scope of operators e.g. [X|Y] or [X]*
symbolPredefined terminal symbol of the language
symbolUser-defined terminal symbol of the language
symbolNon-terminal symbol

Language Definition

This section describes the modeling constructs, the syntax for the modeling constructs and the semantics for the modeling constructs. The semantics describe additional constraints for the syntax which cannot be defined using the BNF grammar rules (static semantics) and describe the meaning of some of the constructs where additional explanation is required (dynamic semantics).

Identifiers

name::=[ letter ][ letter | digit | '-']*
letter::='a' | 'b' |...| 'A' | 'B' | '_'
digit::='0' | '1' |...| '9'
number::=[ integer | long | double ]
integer::={ + | - } unsigned
long::={ + | - } unsigned { l | L }
unsigned::=[ digit ]+
double::=[ integer.unsigned ]
blank-character::='' | '\t' | '\n' | '\f' | '\r'
truth-value::=true | false | unknown
literal-string::="[ letter | digit | '-' | ':' | ';' | '.' ]"
literal-symbol::=name

It is possible to add comments to models. One line comments need to start with '//'. Multi-line comments have to start with '/' and end with '/'.

Compilation Unit

A compilation unit is the goal symbol for the syntactic grammar of Brahms models. A compilation unit consists of three parts, each of which is optional.

  • A package declaration, giving the fully qualified name of the package to which the compilation unit belongs.
  • import declarations that allow types from other packages to be referred to using their simple names.
  • Type declarations of group, agent, class, object, conceptual object class, conceptual object, area definition, area and path types.

Syntax

compilation-unit::=

[ PCK.package-declaration ]* [ IMP.import-declaration ]* [ GRP.group | AGT.agent | CLS.class | OBJ.object | COC.conceptual-class | COB.conceptual-object | ADF.areadef | ARE.area | PAT.path ]*

Semantics

The compiler loads a '.b' file when it is referenced in an import declaration within a '.b' file.

Package Declaration

A package declaration appears within a compilation unit to indicate the package to which the compilation unit belongs. A package can also be referred to as a library. A compilation unit that has no package declaration is part of an unnamed package.

Syntax

package-declaration::=package package-name ;
package-name::=ID.name | package-name . ID.name

Semantics

The package name mentioned in a package declaration must be the fully qualified name of the package. If a type named T is declared in a compilation unit of a package whose fully qualified name is P, then the fully qualified name of the type is P.T; thus in the example:

  package nasa.phonemodel;
  group PhoneUsers { }

the fully qualified name of group PhoneUsers is nasa.phonemodel.PhoneUsers.

The package declaration is used to find Brahms concepts in the file system. A package is to be mapped to a directory in the file system. The package declaration represents a hierarchical directory structure. The package nasa.phonemodel maps to a directory nasa\phonemodel in the file system. If the group PhoneUsers were defined in a file named PhoneUsers.b then this file would be located in the nasa\phonemodel directory. The compiler and Brahms virtual machine use the library path to find concepts in a specific package relative to the library path.

Compilation units that do not have a package statement are part of an unnamed package. The compiler and Brahms virtual machine use the library path to find concepts in an unnamed package by trying to locate them in the directory specified by the library path. It is the responsibility of the model builder to prevent naming conflicts in concepts that are part of an unnamed package. It is highly recommended to use packages for all Brahms concepts.

Import Declaration

The Brahms language supports two types of import declaration, a Brahms import declaration and Java import declaration.

  • The Brahms import declaration allows a Brahms type declared in another package to be referred to by a simple name that consists of a single identifier. The Brahms import declaration makes concepts defined in other compilation units available as one model.
  • The Java import declaration allows for a Java type to be referred to by its simple name. The Brahms compiler uses the Java import declarations to resolve and locate the Java Class file for the Java type to ensure validity of the Java type.

Syntax

import-declaration::=[ brahms-import-declaration | java-import-declaration ]
brahms-import-declaration::=[ import brahms-single-type-import ;| import brahms-multi-type-import ; ]
brahms-single-type-import::=concept-name | PCK.package-name . concept-name
brahms-multi-type-import::=_ | PCK.package-name . _
concept-name::=ID.name
java-import-declaration::=[ jimport java-single-type-import ;| jimport java-type-import-on-demand ; ]
java-single-type-import::=[ ID.name | PCK.package-name . ID.name ]
java-type-import-on-demand::=PCK.package-name . *

Semantics

The Brahms import declaration allows for the import of specific concepts or for the import of a library of concepts defined in a package. The import of a specific concept is realized by referencing its name. The name of the concept must be the same as the name of the file in which it is stored. The extension of the file must always be '.b'.

To reference a specific concept in a library the package name can be used. The package name reflects the directory in which the concept is stored with a 'library-path' as its base path. So for example if the library-path is

library-path = C:\brahms

and I have an import statement like

import nasa.phonemodel.PhoneUsers;

then the concept PhoneUsers is expected to be defined as

package nasa.phonemodel;
    group PhoneUsers { }
 

and is expected to be found in the file

C:\brahms\nasa\phonemodel\PhoneUsers.b

It is also possible to reference all concepts in a specific library. The wildcard '*' can be used in place of a specific concept-name. The following import statement will import all concepts in the phonemodel library:

import nasa.phonemodel.*;

This statement will import all concepts defined in the directory C:\brahms\nasa\ phonemodel defined in the files with the extension '.b' assuming the library-path is set to 'C:\brahms'.

The import statement:

import *;

will import all concepts defined in the files with extension '.b' that are in the same directory as the file in which the import statement is defined.

By default every model imports the 'brahms.base.*' library (referred to as the 'BaseModel') containing base constructs for groups and classes and containing standard available classes and relations. The import of this library does not have to be defined explicitly.

A java single type import declaration imports a single name type, by mentioning its canonical name.

A java type-import-on-demand declaration imports all the accessible types of a named type or package as needed. The import of java.lang.* is not required, the compiler always includes that package in its search path.

A java import declaration makes Java types available by their simple name only within the compilation unit that actually contains the import declaration.

Model

A Brahms model may be thought of, or expressed, as statements in a formal language developed for describing work practice. The language is domain-general, in the sense that it refers to no specific kind of social situation, workplace, or work practice; however it does embody assumptions about how to describe social situations, workplaces and work practice.

Action: Delete

Description

The delete action is an action used to reclaim memory obtained for agents, objects and conceptual objects created at simulation/run-time, the delete action cannot be used on agents, objects, conceptual objects that are created at design-time. The deletion of an agent, object, or conceptual object results in the deregistration of the element from the directory service (in case of a distributed system), removal of references to the element for the calling agent/object, and removal of the element from the model. Elements declared as part of the model at compile time cannot be deleted. Delete operations on static model elements are no-ops and will cause the Brahms virtual machine to print a warning.

Element Creation and References

Agents, objects and conceptual objects are created either when a model is loaded when they are defined as part of the model, when created using one of the create activities or created through the Java API. In distributed mode these elements are registered in the directory service. References to these elements are made in beliefs, facts, and as part of variable contexts maintained for frames defining variables that have their repeat property set to false. References to agents or objects are held using beliefs by either these agents or objects themselves (beliefs about themselves) or references to agents, objects, and conceptual objects are held by other agents or objects (beliefs about those elements). The world state maintains references to elements through facts. In distributed mode beliefs referencing these elements can be communicated to a remote agent or object. Objects that have no frames can be communicated by value to a remote agent or object effectively creating a duplicate copy of the object (this happens when communicating CommunicativeActs).

Reference Counting

To identify when an object can truly be deleted the Brahms virtual machine maintains a reference count for every element per agent/object holding beliefs with a reference to the element.

The reference count will go up:

  1. when an agent/object creates the element
  2. when an agent/object asserts a belief with a reference to the element
  3. when an external agent acquires a memory reference (IActiveInstance::acquireMemoryReference(), IConceptualInstance::acquireMemoryReference())

The count will go down:

  1. when an agent invokes 'delete <element>'
  2. when an external agent releases a memory reference (IActiveInstance::releaseMemoryReference(), IConceptualInstance::releaseMemoryReference())

Notes regarding the reference count:

  1. The agent/object that creates the element and that asserts beliefs with references to the element will only increment the reference count by 1, not 2. Any agent/object can at maximum hold one reference to the element.
  2. References held by remote agents/objects are not counted since we can't guarantee network availability, remote system uptime, and proper notifications of element deletion in a remote Brahms virtual machine.
  3. Object copies (due to transfer by value) will have their own reference count in the Brahms virtual machine in which they were created as a copy and will therefore require separate deletion.
  4. The element for which a reference count is being maintained has itself no impact on the reference count even when beliefs about the element are being asserted in that element about that element.
  5. Multiple invocations of the delete action on the same element by the same agent/object will have no effects on the reference count. Only the first delete will cause the reference count to go down by 1.
  6. If an external agent creates a new dynamic element automatically a reference to it for the external agent will be created! This means that the external agent must release any references to elements it creates using either (IActiveInstance::releaseMemoryReference() or IConceptualInstance::releaseMemoryReference().
  7. When an external agent is notified of a belief (via invocation on onReceive) no automatic reference is obtained for any of the dynamic elements referenced in the belief. It is up to the external agent to acquire and release the necessary references.
Hard and Soft Reference

For the purposes of element deletion the Brahms virtual machine differentiates between hard and soft references.

A hard reference is a reference held by an agent/object that has frames. This agent/object is able to invoke a delete of the element at the appropriate time.

A soft reference is a reference held by an object that has no reasoning capabilities (a data object). It has beliefs in its belief set that reference the element.

If there are no more hard references to an element and only soft references then the element will only be deleted when all agents/objects that have references to the element to be deleted themselves are marked for deletion and have no more hard references to those elements. If object O1 and object O2 have references to each other in their belief sets under normal circumstances neither would ever be deleted since the reference count never goes to 0. Assuming O1 and O2 are data objects then the references to each other would be soft references. If no hard references exist for either of these two objects then the Brahms virtual machine will garbage collect them and perform the final deletion on both O1 and O2.

Results of a Delete

When an agent or object invokes a delete on an element E the Brahms virtual machine will take the following actions:

  1. Retract all beliefs in which E is referenced, whether it be on the left hand side or right hand side of the belief.
  2. Remove all previously executed frame contexts that hold a reference to E in a variable context when the frame has the repeat property set to false.
  3. Reduce the hard reference count by 1 for the caller. If delete was invoked earlier the reference count remains unchanged.
When the Hard Reference Count goes to 0

When there are no soft references to the element E:

  1. Retract all facts referencing E, whether it be on the left hand side or right hand side of the fact.
  2. Deregister E from the directory service.
  3. Remove E from the model.

When there are soft references to the element E:

  1. Mark E for garbage collection.
  2. Verify all soft references that reference E and delete any elements marked for garbage collection that only had a soft reference remaining to E.
Can an element be brought back?

Yes. If an object still has soft references the facts about the object are not yet retracted. This means that object detection is still possible. When an agent/object detects the object and asserts a new belief about the object the hard reference count is incremented and the object is no longer marked for garbage collection.

Remote References

If an element E is created in Brahms virtual machine VM1 and a belief referencing E is communicated to an agent/object in Brahms virtual machine VM2, E is deleted in VM1 and VM1 no longer holds any hard or soft references to E then the element will be deleted. The reference to E held in VM2 becomes stale. Any operations on E in VM2 can result in exceptions. Operations that cause exceptions:

  1. reading of beliefs from E
  2. communication of beliefs referencing E to a remote agent, an exception will be raised in the receiving virtual machine when it attempts to resolve E by looking it up in the directory service (E is longer registered in the directory service and cannot be located)

If E is a data object that was communicated by value then a separate reference count is maintained for this 'copy'. NOTE however that this copy is not registered in the directory service and if its original has been deleted then exceptions will be raised when:

  1. beliefs referencing E are communicated to a remote agent/object. The exception is raised in the receiving virtual machine when it attempts to resolve E using the directory service (E is longer registered in the directory service and cannot be located)

Note that transmitting E in its entirety by value will cause no problems since when transmitting the entire object all relevant information to create a copy of it will be included as part of the message. This is generally only done with CommunicativeActs. It is safe to communicate a copy of a CommunicativeAct using a communicate activity to a remote agent even if its original has been deleted. Just communicating a belief about the CommunicativeAct to a remote agent however will raise an exception in the receiving virtual machine.

Any agent/object holding references to a copy of an element must call 'delete' for that element to ensure that it is deleted just like any other element.

Invoking delete on an element E for which the original does not exist in the virtual machine or where E is not a copy the delete will:

  1. Retract all beliefs referencing E from the belief set of the agent/object invoking delete
  2. Remove all previously executed frame contexts that hold a reference to E in a variable context when the frame has the repeat property set to false.

There will be no reference count modifications since the original/copy is not held in that virtual machine.

Syntax

delete-operation

::=

delete [ VAR.variable-name | PAC.param-name ]

Semantics

Constraints

The variables and parameters refreenced in a delete statement must be of a Group, Class, or Conceptual Class type since delete is not supported on any other types.

The Unknown Value

The Brahms language provides support for the 'unknown' value and 'unknown' truth-value in beliefs, facts, preconditions, consequences, detectables and transfer definitions.

The 'unknown' value is a type independent value and can be assigned to any variable, parameter, attribute or relation. The model builder must be aware that the value 'unknown' can at runtime potentially be assigned to a property of an activity (such as max_duration). Properties such as max_duration do not allow the value 'unknown'. If such a value is assigned anyway at runtime then the virtual machine will generate a warning in the virtual machine's log and use the default value for that property. If however no default value is available for the property an error will be generated and the agent/object in which the error occurred will be halted.

The 'unknown' value can be tested for in preconditions, can be communicated in communication and broadcast activities, can be detected using detectables and can be concluded using consequences. Note that when the value 'unknown' is concluded for a relation that all the previously existing values for that relation are retracted. If an agent concludes that it doesn't know the value of the relation (unknown) it is necessary to remove all existing values for the relation. The reverse is valid as well. If an agent concludes a value for a relation other then 'unknown' and the value 'unknown' was already present for that relation, then the 'unknown' value will be retracted and replaced by the new value.

The value 'unknown' for the truth-value can be used to specify that the truth-value for a relation is unknown or uncertain. The 'unknown' truth-value can also be tested for in preconditions and can be used in consequences to conclude the truth-value.

Before reporting any errors to the support team when a model doesn't behave as expected make sure to check the vm.log file located in <installation directory>/Brahms/AgentEnvironment/logs. This log file might list warnings or errors that relate to assigning the value 'unknown' to a property of an activity that doesn't allow for the value unknown.

Collection Type: Map

The Brahms language lacked support for multi-value attributes, only relations allowed for multiple values. To address this issue the language will now receive support in the form of collection types. The type currently supported in the language is the map type.

The map collection type is a type that can only be use as part of the declaration of attributes. It allows for the assignment of multiple values to the attribute where each value is addressable using an inde or key. The attribute's values are index/value or key/value pairs. The index or key can be any positive integer or string value.

Declaring Maps

A map is declared by declaring an attribute of type 'map'.

attributes:
    public map myMap;

Creating Map Values

A map value is an index/value or key/value pair. Wher we specify index we also imply key. Map values like any other attribute value are represented as beliefs and/or facts. A map is created when at least on belief or fact exists defining a map value. The creation of these beliefs/fact is done like any other beliefs/facts, through initial beliefs/facts or b concluding the beliefs. The index of a map value can only be an integer or string. The value as part of the index/value pair can be any value of any type.

Using initial beliefs/facts map values can be create as:

initial_beliefs:
    (current.myMap(1) = 10);                // int
    (current.myMap(2) = 100L);              // long
    (current.myMap(240) = 10.0);            // double
    (current.myMap(3) = true);              // boolean
    (current.myMap(4) = SomeSymbol);          // symbol
    (current.myMap(5) = "Some String");       // string
    (current.myMap(6) = MyAgent);             // agent
    (current.myMap(7) = MyObject);            // object
    (current.myMap(8) = unknown);             // unknown
    (current.myMap("intValue") = 10);       // int
    (current.myMap("longValue") = 100L);    // long
    (current.myMap("doubleValue") = 10.0);  // double
    (current.myMap("booleanValue") = true); // boolean
    (current.myMap("symbolValue") = SomeSymbol);    // symbol
    (current.myMap("stringValue") = "Some String"); // string
    (current.myMap("agentReference") = MyAgent);    // agent
    (current.myMap("objectReference") = MyObject);  // object
    (current.myMap("unknownValue") = unknown);      // unknown
 
  initial_facts:
    (current.myMap(1) = 10);                // int
    (current.myMap(2) = 100L);              // long
    (current.myMap(240) = 10.0);            // double
    (current.myMap(3) = true);              // boolean
    (current.myMap(4) = SomeSymbol);          // symbol
    (current.myMap(5) = "Some String");       // string
    (current.myMap(6) = MyAgent);             // agent
    (current.myMap(7) = MyObject);            // object
    (current.myMap(8) = unknown);             // unknown
    (current.myMap("intValue") = 10);       // int
    (current.myMap("longValue") = 100L);    // long
    (current.myMap("doubleValue") = 10.0);  // double
    (current.myMap("booleanValue") = true); // boolean
    (current.myMap("symbolValue") = SomeSymbol);    // symbol
    (current.myMap("stringValue") = "Some String"); // string
    (current.myMap("agentReference") = MyAgent);    // agent
    (current.myMap("objectReference") = MyObject);  // object
    (current.myMap("unknownValue") = unknown);      // unknown

The numeric indices do not need to be sequential; they can be any valid positive integer value. A string can be used for the index of a map as well. Generally when a numeric index value is used we refer to it as an index, when a string index value is used we refer to it as a key. The numeric value can be referred to as a key an the string value as an index as well so in this document will just refer to all of them as an index.

Besides defining map values through initial beliefs and facts the map values can also be created using consequences. The following consequences show the most simplistic way to create new map values. Just like with initial beliefs and facts any value can be assigned to an index of a map.

  conclude((current.myMap(100) = "Some Value"));
  conclude((current.myMap("newValue") = 25.0));

It is also possible to change the values of an index fo a map. The value can be changed to any other value, it does not necessarily hav to be of the same value type as the previously assigned value. The followin consequences show examples of this, the first consequence just changes th value, not the type (both strings), the second consequence changes the valu type from double to boolean.

  conclude((current.myMap(100) = "Some Other Value"));
  conclude((current.myMap("newValue") = true));

When a value is replaced the virtual machine will firs retract the old belief/fact for that index/value pair followed by asserting th new belief/fact.

Variables declared for the workframe or thoughtframe ca also be used for either or both the index and value in a consequence. A variabl that is intended to be used for the index must be of type int or string. Th variables must also be bound to a valid value or the virtual machine wil generate an error.

  variables:
    foreach(string) sKey;
    foreach(symbol) sSymbolValue;
    foreach(int) nIntValue;
  when( ... )
  do {
    conclude((current.myMap(25) = sSymbolValue));
    conclude((current.myMap(sKey) = nIntValue));
  } // end do

Parameters declared for activities can also be used fo either or both the index and value in a consequence. They work in the same wa as variables. The parameter must be resolvable to a value, either an actua value passed as an argument for the parameter or a variable passed as a argument for the parameter that is bound to a value. An error is generated b the virtual machine if this is not the case. Parameters used for the index of map value must be declared to be of type int or string.

composite_activity myActivity(string key,
                                symbol symbolValue,
                                int intValue) {
    workframes:
      workframe wf_myWorkframe {
        do {
          conclude((current.myMap(25) = symbolValue));
          conclude((current.myMap(key) = intValue));
        } // end do
      } // wf_myWorkframe
  } // myActivity

It is also possible to assign values to an index of a map by resolving a belief or fact on the right hand side of a consequence. Th right hand side can be an object/attribute tuple or the right hand side ca consist of a reference to the index of a map that is resolved to a value. Agai variables can be used anywhere in these consequences both on the left and right hand side.

  conclude((current.myMap(30) = current.location));
  conclude((current.myMap("value") = current.myMap("intValue")));

It is not possible to assign a map as a value in a map. The compiler will not permit this and will generate a compile error. The following is not permitted:

  conclude((current.myMap("someMap") = current.myMap));

Using Map Values in Preconditions

The use of map values in preconditions is no differen then using regular values. Preconditions now allow you to specify an index fo attributes of type map to allow for the proper matching of beliefs in the preconditions. Variables can be declared for both the index and the index value.

  knownval(current.myMap(1) = 10)
  knownval(current.myMap("stringValue") = "Some String")
  knownval(current.myMap(1) = current.myMap("intValue"))
  knownval(current.myMap(nIndexVar) = 10)
  knownval(nValue = current.myMap(nIndexVar))
  knownval(current manages current.myMap("agentReference"))
  knownval(current manages current.myMap(nIndexVar))
  knownval(current.myMap = unknown)
  known(current.myMap)
  known(current.myMap(1))
  known(current.myMap(nIndexVar))

All of these preconditions are valid preconditions. Th virtual machine ensures that the variables used in these preconditions get th proper matching binding. A few notes about the known preconditions. In the cas of known(current.myMap) the precondition will only evaluate to true if th belief (current.myMap = unknown) exists, if beliefs with index/value pairs exis for the map then that precondition evaluates to false. For the know precondition specifying the index the precondition will only evaluate to true i the index value matches with a belief that has that same index value or i evaluates to true for any index value that is matched for the index if variable is specified for the index that has not been bound in earlie preconditions.

Note that since map values are not typed the virtua machine will do run-time type checking to make sure that any values resultin from the evaluation of a object-attribute-index expression is type compatibl with the opposite side of the condition if an attribute or variable is specifie or if a relation is used.

attributes:
    public int numEmployees;
  relations:
    public BaseGroup manages;
 
  knownval(current.numEmployees = current.myMap("stringValue"))
  knownval(current manages current.myMap("intValue"))

These preconditions will generate warnings in the lo file and will evaluate to false, since the map value for the "stringValue" inde is a string and not an integer and since the map value for "intValue" is a integer and not an agent reference with the agent being a member of BaseGroup.

Using Map Values in Consequences

Map values can be used in the right hand side of consequences to conclude a new value of a single valued attribute or to conclud a new value of a relation. The values of index/value pairs are not strongl typed for maps and any value is supported. However attributes that are not of collection type and relations are strongly typed. Care is therefore require when assigning a value to an attribute using a map value.

attributes:
    public int numEmployees;
 
  conclude((current.numEmployees = current.myMap("intValue")));
  conclude((current.numEmployees = current.myMap("doubleValue")));

The first consequence will succeed since the agen currently beliefs the integer value 10 for the index "intValue" for myMap whic is of the correct type for numEmployees. For the second one however the virtua machine will generate an error in the log file since double values are not type compatible with integers and the double value can therefore not be assigned to numEmployees.

relations:
    public BaseGroup manages;
 
  conclude((current manages current.myMap("agentReference")));
  conclude((current manages current.myMap("objectReference")));

In this case with the use of relations the first consequence again will succeed since the agen currently beliefs MyAgent as the value for the index "agentReference" for myMa which is an agent that is always a memberof BaseGroup and is therefore type compatible with the manages relation. The second consequence however return MyObject from the map when using the index "objectReference" which is of type BaseClass and not type compatible with BaseGroup. The virtual machine wil generate an error in the log file and not execute the consequence.

Copying Maps

The language makes it easy to copy the map values of on map to another map. This is done by using consequences.

Assume that we have two attributes declared myMap an myMapCopy both of type map. Also assume that we have assigned values to myMa already as we''ve shown in the examples for initial beliefs and assume that thi consequence is executed for an agent.

  conclude((current.myMapCopy = current.myMap));

This consequence will copy all beliefs with th index/value pairs for myMap to myMapCopy, creating the identical index/valu pairs for myMapCopy. If myMapCopy had any indices that were identical to thos in myMap then the values for those indices for myMapCopy will be replaced wit those of myMap.

Before the conclude we have the following beliefs:

  (current.myMap(1) = 10)
  (current.myMap("stringValue") = "Some String")
  (current.myMapCopy(1) = 50)

After the conclude we have the following beliefs:

  (current.myMap(1) = 10)
  (current.myMap("stringValue") = "Some String")
  (current.myMapCopy(1) = 10)
  (current.myMapCopy("stringValue") = "Some String")

The value 50 for index 1 for myMapCopy was retracted an the new value 10 was asserted and a new belief for index "stringValue" wit value "Some String" was asserted for myMapCopy. Note that since we didn' specify belief or fact certainties both were defaulted to 100% and therefore also facts were asserted for the myMapCopy index/value pairs.

Clearing Maps

A consequence is also used to clear a map of all of it index/value pairs. This is done by concluding the value unknown for the ma attribute without specifying an index.

conclude((current.myMap = unknown));

This retracts all index/value pair beliefs and facts for myMap and asserts the new belief/fact:

(current.myMap = unknown)

When a ne index/value pair for this cleared map is concluded then first the unknow belief/fact for that map is retracted then followed by the assertion of the one index/value pair.

Communicating Maps/Map Values

Using broadcast and communicate activities it i possible to communicate beliefs from one agent to another. Since index/valu pairs for maps are represented as beliefs they are communicated in the same way.

In the transfer definitions of the broadcast an communicate activities either single map values can be communicated or an entire map.

communicate communicateMapValues(string key, SomeGroup agt) {
    ...
    about:
      send(current.myMap(1) = unknown),
      send(current.myMap("intValue") = unknown),
      send(current.myMap(key) = unknown),
      send(current.myMap = unknown),
      receive(agt.otherMap(1) = unknown),
      receive(agt.otherMap("intValue" = unknown)),
      receive(agt.otherMap(key) = unknown),
      receive(agt.otherMap = unknown);
  } // communicateMapValues

When an index is specified only the belief matching th OA(index) will be sent/received. The index can be specified using a paramete declared for the activity. If no index is specified for the map all belief about the map will be sent/received. This makes it easy to send/receive th entire contents of a map.

Detecting Map Values

Map values can also be detected in detectables and ca be used to trigger detectable actions. They operate in a similar way as i preconditions. For detection of facts on the left hand side of the detectabl condition is relevant. On that left hand side can be specified whether a singl map value is to be detected by specifying the index for the map value to b detected or whether all map values need to be detected.

  detect((current.myMap(1) = unknown));
  detect((current.myMap("intValue") = unknown));
  detect((current.myMap(someVariable) = unknown));
  detect((current.myMap = unknown));

The first three detectable conditions detect a singl value, with the third one using a variable to specify the index to be detected That variable must have been bound in the preconditions. The last detectabl condition detects all map values for myMap.

For triggers the right hand side value must match wit the detected belief or belief matching the left hand side. The right hand sid of the detectable can also specify a reference to a map value. The following ar all valid detectable/trigger conditions.

  detect((current.myMap(1) = current.myMap("intValue")));
  detect((current.numEmployees = current.myMap(1)));
  detect((current manages current.myMap("agentReference")));

In the last two conditions there is a potential for type mismatch. For the condition using an attribute on the left hand side no warning or errors are generated if there is a type mismatch. The virtual machine jus compares the right hand side value of the belief matching (current.numEmployee = ?) with the right hand side value of the belief (current.myMap(1) = ?). I they match the detectable action is triggered, if not the action is not performed. For the condition using a relation a warning is generated if the map value is not type compatible with the relation due to the fact that relation are handled differently then attributes by the virtual machine. The detectable action is not triggered in that case, only when the resulting reference matches that of the right hand side reference of the belief (current manages ?).

List of Keywords

This is an overview of all the keywords defined for the Brahms language. None of these keywords can be used as identifiers when building models.

ActiveClassdeletemod
ActiveConceptdestinationmove
ActiveInstancedetectname
Agentdetectablenowork
Areadetectablesnot
AreaDefdetectArrivalInobject
ClassdetectArrivalInSubAreaspackage
ConceptdetectDepartureInpartof
ConceptualClassdetectDepartureInSubAreaspath
ConceptualConceptdisplayprimitive_activity
ConceptualObjectdistancepriority
GeographyConceptdivprivate
Groupdoprotected
Objectdoublepublic
abortend_activityput
aboutend_conditionquantity
actionextendsrandom
activitiesfactframereceive
agentfalserelation
andfcrelations
areaforeachrepeat
area1foroneresource
area2gestureresources
areadefgetsend
assignedgroupsource
attributesimpassestring
bcimportsuper
booleaniconsymbol
broadcastinhabitantsthen
classinitial_beliefsthoughtframe
collectallinitial_factsthoughtframes
communicateinstanceoftime_unit
completeintto
composite_activityistoSubAreas
conceptual_classjavatrue
conceptual_objectjimporttype
concludeknownunassigned
continueknownvalunknown
costlistofvariables
create_agentlocationwith
create_arealongwhen
create_objectmapwhenever
currentmax_durationworkframe
dataframememberofworkframes
dcmin_duration 

Versions

See version history here.