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


NAME

  nb.syn - NodeBrain Syntax

SYNOPSIS

  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[, ... ]

DESCRIPTION

  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.

PURPOSE

  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.

COMMANDS

  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.

CELLS

  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 a cell 1;
    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.

    assert c=4;

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 a cell !!; # a=!! true
    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.

    define x cell (((a+b)*c)>5 or a*b>20) and d;

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.

   

Expression      Value   
1 and !   =   !   
1 and 1   =   !!   
1 and 0   =   !! (0 is true)   
1 and "abc"   =   !!   
! and 1.3   =   !   
1 and ?   =   ?   
! and ?   =   !   
1 or !   =   !!   
! or 33.2   =   !!   
! or "abc"   =   !!   
1 or ?   =   !!   
! or ?   =   ?   

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.

   

Expression   True during (False otherwise)   
~(mo,we)   Monday or Wednesday   
~(fr.d(1))   Fridays falling on the first day of a month   
~(h(14).su)   Hour 14 (14:00) on Sunday   
~(h(8).fr.d(15))   Hour 8 (08:00) of Fridays falling on the 15th   
~(mo[1]month)   First Monday of a month   
~(tu[-2]month)   Second to last Tuesday of a month   

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.

    define x cell a*b+`math.sqrt(c);

A node function call is another type of formula that executes whenever one of the argument cells changes.

    define mystuff node tree; # create node with skill provided by the Tree module
    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.

SKILL METHODS

  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 names module {"."}names;
    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.

    define mynicks node tree; # construct tree
    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

ASSERTIONS

  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.

    assert x=a*b+c,y=a+b*c;

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 x cell a+b;
    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.

    define x cell a+b; # define x as a+b

    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; # define x

    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=13,b=7; # assert a=13 and b=7 with IF rules enabled.

    alert a=4; # assert a=4 and b=? with IF rules enabled.

RULES

  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 r1 on(a=b) x=2;

    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.

    define r1 on(a=b) x=2;

    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.

    define r2 if(a=b):-ps -ef | grep nb

    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.

CONTEXT

  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.

    define connie node;

    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 node;

    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.

    define connie node;

    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.

    define connie node;

    connie. define b cell a+5; # connie.a is implicitly defined

The next example shows the equivalent explicit definition of "a".

    define connie node;

    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.

    define connie node;

    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.

    define connie node;

    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


INCLUDES

  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 commands from myExtraRules.nb

    %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.

    % define %{context} node;

    %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.

BUGS

  See nb(1). Please report bugs to <bugs@nodebrain.org> or enter a bug report at http://nodebrain.org.

AUTHOR

  Ed Trettevik <eat@nodebrain.org>

DOCUMENTATION

  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.

SEE ALSO

  nodebrain(7), nb(1), nb.cfg(5), nb.mod(7), nb.lib(3) nbkit(1), nbkit.caboodle(7)

NodeBrain 0.9.03December 2014nb.syn(5)