nb.syn(5) | NodeBrain Administrator Guide
Version 0.9.03 - December 2014 |
nb.syn(5) |
NAME | SYNOPSIS | DESCRIPTION | PURPOSE | COMMANDS | CELLS | SKILL METHODS | ASSERTIONS | RULES | CONTEXT | INCLUDES | BUGS | AUTHOR | DOCUMENTATION | SEE ALSO
nb.syn - NodeBrain Syntax |
command ::= [context. ] verb body [;]
verb ::= declare | define | assert | alert | source | ... declare term decType declaration decType ::= identity | module | skill | calendar define term defType definition defType ::= node | cell | on | if | when | macro | ... define term node [nodeSpecification] define term cell [formula] define term (on|when|if)(formula) action (assert|alert) term=formula[, ... ] |
This manual page introduces the syntax and structure of the NodeBrain language used in configuration files and event streams. From this, you should be able to read a configuration file or event stream and get a general idea of the information it conveys to NodeBrain. However, if you need to create or maintain complicated rule sets, you will need to reference the documents available at http://nodebrain.org. Here we will try not to be rigorous, relying mostly on examples to give you the general idea. |
NodeBrain is a declarative language, in contrast to a procedural language like most programming languages you know. This means you would not want to use NodeBrain for most tasks you can perform easily with your favorite scripting language. For example, you would not use NodeBrain to read a file, extract information, and produce a report. Instead, the NodeBrain language is intended simply to provide rules, assertions, and alerts to the NodeBrain Rule Engine, which is intended for state and event monitoring applications. |
To some degree, it is helpful to think of NodeBrain commands as transactions, because commands
may come from multiple sources (peers, queues, FIFO's, scripts, etc.) as individual units of work.
The interpreter processes commands
in whatever order they arrive from these command streams.
Rules may respond to ASSERT and ALERT commands by triggering other commands
internally.
The SOURCE command provides a way for a single command to
directly trigger the execution of a sequence of commands from a file.
All commands are processed as a single line of text. Files of commands may specify single line commands over multiple lines by ending a line with an escape "\", but these lines are assembled into a single string of text, a single command, before they are passed to the interpreter. |
NodeBrain has cells like a spreadsheet. Each cell has a formula
and a value. The major difference between NodeBrain and a spreadsheet is the way in which cells are referenced.
In a spreadsheet, cells are referenced by absolute or relative row and column.
In NodeBrain, a cell is referenced by a formula, which can be as simple as a constant (number or string),
a variable (term), or a more complicated expression of operators and operands (references to other cells).
A term is defined by a reference to another cell, whose value it adopts, and whose formula becomes the term's definition.
A term effectively acts like an alias for the value and formula of the referenced cell.
Because the defining reference can be changed, a term is like a variable in other languages.
The following example uses 11 cells: a, 1, b, 2, c, 3, x, b*c, a+b*c, y, and b*c+3. It is important to understand there is only one b*c cell, and there are two cells that reference it: a+b*c and b*c+3.
define b cell 2; define c cell 3; define x cell a+b*c; define y cell b*c+3; When the value of a cell changes, the new value is "published" to the referencing cells that have "subscribed" to its value. Let's look at what happens when we assert a new value for c.
If we assume all terms have subscribed to the values of their defining formulas (not always the case), then the value of x and y automatically change from 7 and 9 respectively to 9 and 11 respectively. There is an intermediate step where the value of the cell b*c changes from 6 to 8. This should give you an idea of how NodeBrain cells are defined by formulas, and how they respond to changes. This is important because the whole goal of NodeBrain is to be able to respond appropriately to new information given a set of existing knowledge. We used an arithmetic example above, but NodeBrain is perhaps more interested in logical expressions.
define b cell !; # b=! false define c cell a and b; # c=! false define d cell a or b; # d=!! true define e cell !a; # e=!! true Parentheses are used to control operator order of precedence. It is best to use them when it may be unclear which operation will be performed first.
The value of a cell may be a real number (e.g. 1, 1.78), a string (e.g. "abc", "this is fun"), unknown (?), false (!), or true (!!). In all cases, a cell has a logical value, because all numbers and strings are interpreted as true by logical operators (e.g. AND and OR). Logical operators recognize three states: true, false, and unknown. Here are some examples.
There are three things worth noting as deviations from most programming languages: 1) logical operators understand a third state of unknown, 2) logical operators treat 0 as true, and 3) logical operators produce special values of true (!!) and false (!) that are treated by numerical operators as 1 and 0 respectively. NodeBrain also has time formulas "~(...)" that evaluate to true or false at any given second in time based on the system clock. This is based on standard notions of a calendar, periods, time intervals, and a kind of algebra for manipulation of sets of line segments representing a schedule. The following examples illustrate the general idea.
A cell function call is a type of formula that operates on argument cells whenever their values change. A cell function call is a function name and argument list following a backtick.
A node function call is another type of formula that executes whenever one of the argument cells changes.
define r1 on(x=40 and mystuff(a,b,c+7)) a=b+2; The way in which mystuff(a,b,c+7) is evaluated is determined by the evaluation method of the tree skill associated with the mystuff node. This skill is provided by a module (NodeBrain plug-in). Modules can provide additional methods for a skill that can handle assertions and commands using the same node function call syntax within the context of an assertion or command verb. |
A node module implements one or more skills. For each skill, it implements methods defined by the NodeBrain C API.
Each line in the command examples below illustrates a reference to a different skill method.
declare nickname skill names.nick(...):... # initialize skill define mynicks node nickname("builtin"); # construct node assert mynicks("RyRy","Ryan"),mynicks("TayTay","Taylor"); # assert information define isnick cell mynicks(name); # evaluate formula show mynicks; # display knowledge associated with mynick mynicks(2,a+5); # process node command We know from the syntax what method within the node module is invoked in each reference to the node "mynicks", but we would need documentation on the node module names and its skill nick to know how the arguments are processed. The arguments can be any formula in general, but the domain of valid values may be restricted by the node module. The DECLARE commands shown above are normally not required when using installed node modules with default options. Here's an example using the Tree module.
assert mynicks("RyRy")="Ryan",mynicks("TayTay")="Taylor"; # assert information to tree define isnick cell mynicks(name); # evaluate tree formula show mynicks; # display information in tree |
An assertion is used to convey new information to the rule engine.
Simple assertions are like assignment statements with a term on the left and a formula
on the right.
When the value of a term changes as a result of the assertion, the rule engine reacts to the change by re-evaluating cells that reference the modified cell. We say the cell "publishes" changes to the "subscriber" cells. When re-evaluation of subscriber cells change their value, they in turn publish their changes to subscriber cells. This can percolate all the way up the subscriber hierarchy as long as re-evaluation produces a change. To understand the response to an assertion in the following example, one must understand that, within the context of a numerical operation, true (!!) has a value of 1, and false (!) has a value of 0, even though ! and 0 are not the same in a logical context.
define y cell a>b; # true (!!) if a greater than b, false (!) otherwise define z cell x+y; define r on(z>20):-echo hello assert a=13,b=7; # this triggers rule r because z=21 assert a=12,b=8; # this causes re-evaluation of x and y assert a=2; # this causes re-evaluation of x, y, z, and r Notice the difference in our comments for the last two assertions above? The reason the last assertion caused re-evaluation of z is because x and/or y changed. Then r was re-evaluated because z changed. The second assertion did not cause r to fire because the rule condition remained true. We can assert values using "=" or definitions using "==". The following examples give the same definition to a cell named x.
assert x==a+b; # define x as a+b The DEFINE command in this example defines a new cell named x. The ASSERT command with "==" is the same if x is not already defined. If x is already defined, the DEFINE command will fail while the ASSERT command with redefine x. In the ASSERT command it is also possible for x to be in a parent context (explained later).
assert x==a*b; # redefine x define x cell a+b; # fails because x is already defined. redefine x cell a+b; # works because intention is clear An ALERT command is just like an ASSERT command, with two exceptions: 1) it enables IF rules as you will see in the next section, and 2) assertions to terms within the context node (assume this is true in examples for now) are transient---meaning they will revert to unknown (?) on a subsequent ALERT that does not include them in the assertion.
alert a=4; # assert a=4 and b=? with IF rules enabled. |
To respond to specific conditions or events, NodeBrain needs rules that tell it what to watch for
and what action to take if the condition is true.
define r2 if(a=b):-ps -ef | grep nb define r3 when(a=b):-echo hello An ON rule fires whenever the condition transitions from false or unknown to true.
assert a=7,b=7; # r1 fires assert a=2; # r1 transitions to false assert a=7; # r1 fires assert a=5,b=5; # r1 remains true and does not fire assert b=?; # r1 transitions to Unknown assert ?b; # an easier way to assert that b has an unknown value alert a=2,b=2; # r1 fires - ON rules respond to ALERT just like ASSERT An IF rule fires when true after an ALERT command. Notice we didn't say "transitions to true." It will fire on an ALERT even when the condition remains true.
assert a=7,b=7; # r2 is true, but does not fire on ASSERT alert a=2,b=2; # r2 fires alert a=2,b=2; # r2 fires, even though there was no state change - new event alert a=1,b=1; # r2 fires alert a=0,b=4; # r2 does not fire because the condition is false alert b=0; # r2 does not fire because a=? now - condition is ? alert c=5; # r2 does not fire because a=? and b=? now - condition is ? The ON rule is used for state monitoring and responds to both the ASSERT and ALERT commands. Although it can be used for state monitoring and event monitoring it only responds to state changes. The IF rule is used for event monitoring and responds only to ALERT commands directed to the node in which the rule is defined. (See CONTEXT below.) It treats every ALERT command as an event, where the terms are event attributes. An ALERT with the same parameters as the previous ALERT is recognized by the IF rule as a new event. The ON rule sees alerts as non-events when they don't change the monitored state. The last rule we want to talk about here is the WHEN rule. It is identical to the ON rule, except it only fires one time and undefines itself. The WHEN rule applies equally to the ASSERT and ALERT commands, so it can be used for both state and event monitoring. |
NodeBrain commands are interpreted within the context of a node, which has a set of terms,
which may include rules.
A term may have a different meaning in a different context. In the following example we define
a node, "connie", and define three terms within the associated context.
connie. define a cell 1; connie. define b cell a+5; connie. define hi on(a+b>3):-echo hello The context prefix "connie." (the period is important) on the DEFINE commands tells the interpreter how to interpret the commands. This same example, without the context prefix would look like this.
define connie.a cell 1; define connie.b cell connie.a+5; define connie.hi on(connie.a+connie.b>3):-echo hello Referenced terms may be resolved at a higher level context if not defined in the target context.
connie. define tex node; connie. define a cell 1; connie.tex. define b cell a+5; # "a" is connie.a because there is no connie.tex.a # but "b" is connie.tex.b because we are defining it in connie.tex Undefined terms that are referenced in a formula are implicitly defined in the target context.
connie. define b cell a+5; # connie.a is implicitly defined The next example shows the equivalent explicit definition of "a".
connie. define a cell; # connie.a is a cell with an unknown value (?) connie. define b cell a+5; You can reference an undefined term in the target context when there is a defined term in a parent context. This is done by putting a period (".") in front of the term.
connie. define tex node; connie. define a cell 1 connie.tex. define b cell .a+5; # ".a" is connie.tex.a, not connie.a # The implicit definition is "define connie.txt.a cell ?;" An ALERT command only triggers IF rules defined in the target context.
connie. define r if(a) x=2; alert a=1; # connie.r does NOT fire - wrong context and connie.a=? alert connie.a=1; # connie.r does NOT fire - true condition, wrong context connie. alert a=1; # connie.r DOES fire - right context and right a |
The %INCLUDE directive and
SOURCE command are important to understand because they are frequently used in one
file to include commands from another---like the source command in a
shell script or an include directive in a C program.
%include myExtraFules.nb,a=2,context="abc"; - or - source myExtraFules.nb,a=2,context="abc"; There is no difference between the %INCLUDE directive and SOURCE command. The %INCLUDE directive may seem more appropriate within a rule file, while the SOURCE command may seem more appropriate in interactive mode or as a transaction to an agent. The parameters a=2 and context="abc" are available within myExtraRules.nb for controlling conditional processing and symbolic substitution.
%if(a>1); % %{context}. define r0 on(x>21):-mail fred@flintstone.com < myap.log %endif; % %{context}. define r1 on(x=17) m=0; Again, we've only provided enough information here to help you read NodeBrain rule files, not enough to prepare you to write them. Refer to the online documentation for more information. |
See nb(1). Please report bugs to <bugs@nodebrain.org> or enter a bug report at http://nodebrain.org. |
Ed Trettevik <eat@nodebrain.org> |
Online documentation is available at http://nodebrain.org. Manuals are also available in Texinfo format in the git repository. These documents are also included in source distribution files. |
nodebrain(7), nb(1), nb.cfg(5), nb.mod(7), nb.lib(3) nbkit(1), nbkit.caboodle(7) |
NodeBrain 0.9.03 | December 2014 | nb.syn(5) |