QSMM Programmer Manual

This manual documents QSMM, an adaptive state model development framework.

This edition of the manual was updated 2 February 2026 and corresponds to release 1.19.1 of the framework.

You can find more information about QSMM on the project homepage, http://qsmm.org.

Please submit bugs in this manual to a mailing list for QSMM users. Posting messages to the mailing list requires prior subscription to it. The mailing list information page is available at https://lists.sourceforge.net/lists/listinfo/qsmm-users.

Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2025 Oleg Volkov.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being just “GNU General Public License”, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

Table of Contents


Acknowledgements

The author of this manual expresses thanks to the following people who helped improve its quality:


1 Introduction

The project name “QSMM” is the recursive acronym for “QSMM State Machine Model.” State machine is a general concept applicable to many fields of knowledge. A state machine has a set of possible states, where one of them is a current machine’s state changed according to state transition rules. The author believes that the concept of state machine is fundamental to our experience of conciousness connected with our intelligent behavior.

A set of possible states of a state machine and a specification of possible transitions between them are part of a state model. A state machine executes a state model—performs actual transitions between states and keeps a current machine’s state. Actual state transitions affect how the machine is communicating with an environment, whereas possible state transitions are part of a framework for this communication.

An adaptive state model is a state model that allows a state machine to exhibit adaptive behavior. In QSMM, adaptive behavior means that rules for performing actual state transitions are adaptive ones with the goal to achieve a desired result.

To develop a system, a programmer needs to code its state model for execution by a computer. To facilitate development, the programmer can use various function libraries and frameworks. QSMM is a C function and macro library with the rudiments of a toolchain for adaptive state model development. By author’s belief, QSMM could advance the development of systems with intelligent behavior.

The QSMM package source code is distributed under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. See GNU General Public License, for the text of the License.

This manual specifically is covered by the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation. See GNU Free Documentation License, for the text of the License.

Software described in this manual is without any warranty. The software is provided “as is,” in the hope that it will be useful. See the GNU General Public License, for more details.


1.1 What Is Intelligence?

There are many definitions for intelligence as well as types of intelligence. Most definitions include lists of activities inherent to humans, such as reasoning, planning, solving problems, thinking abstractly, comprehending complex ideas, learning from experience, and adapting effectively to the environment. When attempting to develop intelligent machines, researchers try to make them perform a subset of activities inherent to humans with as high a level of plausibility as possible. However, from the standpoint of knowledge formalization and for a more precise formulation of research goals, it would be useful to point out the smallest subset of the activities to establish that an animate being or inanimate machine performing them is intelligent enough.

First, it is necessary to mention that intelligence implies a goal (in the “Handbook of Human Intelligence” Sternberg and Salter defined intelligence as “goal-directed adaptive behavior”). In the case of animate being, the goal could be surviving, and in the case of a machine created by humans, the goal could be solving tasks assigned by humans. Animals show their basic intelligence, for example, when they adapt to the environment, seek for food, and build nests. One can say today’s machines show their intelligence by effectively performing tasks people created the machines to perform. This is not a too distorted interpretation of intelligence if we review the book “Symbolic Logic and Intelligent Machines” of Edmund C. Berkeley published in 1959, where the author called intelligent machines electromechanical arrangements capable of solving problems that involved logic.

As animals are capable of satisfying their basic needs for living, let us assume they possess a basic level of intelligence. To better satisfy needs for living, an advanced level of intelligence would be the production and use of work tools. As it turned out, the production and use of work tools is specific not only to humans but also to chimpanzees and to a number of other animals. For example, chimpanzees are able to find stones of appropriate weights and sizes and crack nuts using them. Chimpanzees are also able to find long and thin sticks and use them to kill small rodents living in trunks of a certain species of trees and extract killed rodents for food. It is important to mention that chimpanzees not only find ready-to-use work tools in nature but can also produce them. For example, chimpanzees can construct arrangements consisting of small tree branches and put them into termite mounds to eat termites crawled on them. Another example is an experiment conducted on a pygmy chimpanzee when experimenters successfully trained him to manufacture a sharp stone tool for cutting a string to open the door of a chamber with sweets.

In a digital world supported by computers, work tools are computer programs helping solve various tasks. In a computer environment, the aforementioned advanced level of intelligence is the capability to synthesize and use computer programs and algorithms. A machine with an advanced level of intelligence should be capable of automated synthesis of algorithms in some form or fashion. Such an algorithm might have a form of an ordinary computer program, possibly containing a set of subroutines.

There does exist a higher level of intelligence—we shall call it an expert level of intelligence,—specific only to humans and not to chimpanzees. Indeed, what is an essential difference between humans’ and chimpanzees’ intelligence if they both produce and use work tools?

In the book “The Complete Idiot’s Guide to Human Prehistory,” its author Robert J. Meier briefly noted an important fact about the production and use of burins1. Such specially sharpened stones archaeologists find during excavations corresponding to the time when, tentatively speaking, we can call creatures that have been living on Earth humans. Burins are tools created for manufacturing other tools. Chimpanzees do not make tools for making other tools. That is, an expert level of intelligence peculiar to humans is the ability to organize processing chains where one kind of work tools takes part in the production of other kinds of work tools. The established concept for this is production of the means of production.

For the computer environment, programmers develop such tools as compilers, various operating, execution, and development environments to simplify developing other computer programs. A machine with an expert level of intelligence would be capable of the automated synthesis of algorithms that the machine would execute to synthesize other algorithms to solve problems assigned by humans more efficiently. The creation of such a machine is a quite specific goal researchers could try to achieve.


1.2 Spur-Driven Behavior

A basic problem one needs to solve when creating an intelligent machine that performs automated synthesis of algorithms is discovering a way or manner in which a job is assigned to the machine. There are sophisticated approaches to solving the problem, for example, by creating specifications consisting of rules and constraints. A simpler approach is reducing an algorithm synthesis task to an optimization task. In this approach, a task resolution assessment unit evaluates a result of execution of a version of a synthesized algorithm; the machine makes changes to the version to hopefully produce a version with a better assessment score. A classical approach to solving optimization tasks of this kind is genetic algorithms. A genetic algorithm would evolve a resulting algorithm by trial and error in multiple iterations to maximize the value of a fitness function.

Another approach to solving an algorithm synthesis task as an optimization task is an approach used in QSMM where the machine synthesizes an algorithm simultaneously with its execution. The algorithm being executed can interact with an environment. The task resolution assessment unit provides continuous feedback on the results of execution of the algorithm, and the machine continuously attempts to improve it. A behavior exhibited by the machine is reinforcement learning. QSMM provides means for representing a synthesized algorithm as a finite automaton.

Historically, a numerical quantity specifying a component of an algorithm fitness value is called spur in QSMM; the type of the component is called spur type. QSMM supports multiple spur types, although it is better to use a smaller number of spur types for a more efficient optimization. For example, a spur value can be the logarithm of a probability to maximize, an energy value to minimize, or the sum of rewards or incentives given to a machine when a partially synthesized algorithm reaches some points in solving a task. For time-dependent feedback on changes to fitness value of an algorithm being synthesized, QSMM supports the optimization goal “maximize spur increment velocities”.

QSMM since version 1.17 proposes a higher-level approach to represent a synthesized algorithm as a PCFG (Probabilistic Context-Free Grammar). As a direct consequence of this, the main component of an algorithm fitness value becomes the probability of a PCFG.

In general, a programmer should provide a spur evaluation method that allows a machine to better understand a correlation between changes made to an algorithm being synthesized and observed changes to its behavior. Developing a proper spur evaluation method can be one of the most complex tasks to solve when creating an intelligent machine using QSMM.


1.3 Building Blocks for Intelligent Machines

Consider an artificial neuron with one input and many outputs. Activation of the input leads to activation of one of the outputs where the choice of an activated output is probabilistic. A set of such neurons is a probabilistic mapping—a function that ambiguously maps an argument from a set of possible arguments to a result from a set of possible outcomes. Such function, when invoked one time, can return one result, and when invoked another time, can return yet another result for the same argument.

If every argument of a probabilistic mapping has a corresponding set of possible outcomes with fixed probabilities, we call the probabilistic mapping a fixed probabilistic mapping.

An important concept related to the possibility of using a result of a probabilistic mapping (directly or after transforming) as an argument (or as its part) of the probabilistic mapping is state—a variable that changes its value based on its previous value.

A fixed probabilistic mapping can model a probabilistic finite automaton. An argument of this probabilistic mapping is a superposition of the previous automaton state and an input signal received. A result of the probabilistic mapping is the next automaton state (or a superposition of the next automaton state and an output signal emitted).

To establish a uniform state transition model, it is tempting to treat a set of possible states of a probabilistic mapping as a Cartesian product of sets of possible sub-states making up a full state. In this sometimes useful approach, a resulting set of states can be very large. As sub-states from different sets usually interrelate with each other, the actual number of possible states is often much smaller. They resemble perceived states—mental model states a researcher realizes when learning or programming the behavior of an entity. When using QSMM, we will tend to work with such perceived states.

A probabilistic finite automaton can have a representation in the form of a probabilistic program. In particular, such probabilistic program may be a probabilistic assembler program—an assembler program containing probabilistic jump instructions. If there are no probabilistic jump instructions in an assembler program, the finite automaton and the assembler program are deterministic.

The instruction set of a probabilistic assembler program may consist of:

  1. Custom instructions for performing effective work. Every such instruction can return an outcome from a set of possible outcomes.
  2. The probabilistic jump instruction. It transfers control to a custom instruction at a specific location in the program with a given probability.
  3. The conditional jump instruction. It transfers control to a custom or probabilistic jump instruction at a specific location in the program on the basis of an outcome returned by a previously invoked custom instruction.
  4. The simple jump instruction. It transfers control to a custom instruction at a specific location in the program unconditionally.

Locations of custom instructions in the assembler program represent the states of the probabilistic finite automaton. An argument of a fixed probabilistic mapping backing up the finite automaton is a superposition of a location of a custom instruction invoked and an outcome returned by the custom instruction. An outcome of the fixed probabilistic mapping is the location of the next custom instruction to invoke. Simple jump instructions, conditional jump instructions, and probabilistic jump instructions in the assembler program map a particular argument of the probabilistic mapping to a set of possible outcomes with fixed probabilities.

A program usually contains a set of subroutines. A probabilistic assembler program may contain custom instructions for calling subroutines and custom instructions for returning control back. A probabilistic finite automaton may represent a subroutine. Calling a subroutine means pushing a reference to a current probabilistic finite automaton and its current state to a stack and transferring control to the initial state of another probabilistic finite automaton. Returning control from the subroutine means popping the reference to the current automaton and its current state from the stack and transferring control to that state.

We can implement modulating the behavior of a probabilistic mapping by spur. Supposing a result returned by a probabilistic mapping for its specific argument somehow affects the spur, a desired behavior of the probabilistic mapping for this argument would be returning more often an outcome that leads to a greater absolute spur value (a positive value if the goal is to maximize the spur, or a negative value if the goal is to minimize the spur) or a greater spur increment or decrement velocity. We call a probabilistic mapping with this behavior an adaptive probabilistic mapping. An adaptive probabilistic mapping helps produce goal-directed adaptive behavior: return more often outcomes that bring a machine closer to a goal where the spur measures a proximity to the goal.

In QSMM, actor is an adaptive probabilistic mapping working similarly to a fixed probabilistic mapping, but instead of fixed outcome probabilities, it uses probabilities adjusted adaptively. An actor is a generic block for building intelligent machines.

If a fixed probabilistic mapping that backs up a probabilistic finite automaton becomes an adaptive probabilistic mapping, the automaton becomes an adaptive probabilistic finite automaton. Consequently, a probabilistic assembler program the automaton represents becomes an adaptive probabilistic assembler program.

Using QSMM, a researcher can develop adaptive probabilistic assembler programs producing goal-directed behavior. They are a basis for automated synthesis of algorithms.

An assembler program represents a state model, and a subroutine of an assembler program represents a state sub-model. In QSMM, node means a callable state sub-model. If a state model contains multiple nodes, we call it multinode model. A node is a probabilistic finite automaton lying behind a probabilistic assembler program. Node execution is the operation of the probabilistic finite automaton where it exhibits adaptive behavior.


1.4 Animate Machines

Can an intelligent machine be conscious? This section explains a point of view where an adaptive probabilistic mapping within an intelligent machine can induce a rudiment of consciousness.

How to implement a probabilistic mapping? For its particular argument, a machine could generate probabilities of all possible outcomes. Then, the machine would randomly select a particular outcome according to the probabilities, for example, using a random number generator.

How can the machine perform this selection? Suppose, the random number generator can return two numbers, 0 or 1, with equal probabilities. A straightforward approach to utilizing that random number generator is performing a fixed number of calls to the generator to obtain a binary fractional number in the range 0 to 1. Non-overlapping segments on a line of length 1 can represent all possible outcomes, where the length of every segment is equal to the probability of a corresponding outcome. To determine an outcome, the machine finds a segment containing a point on the line at a distance equal to the binary fractional number measured from the line beginning.

For example, if three calls to the random number generator returned numbers 1, 0, and 1, the binary fractional number is 0.101. In decimal notation, it is equal to 1*2-1+0*2-2+1*2-3=2-1+2-3=0.5+0.125=0.625. If four possible outcomes have probabilities 0.125, 0.5, 0.125, and 0.25, then the segments end at distances 0.125, 0.625, 0.75, and 1 from the beginning of the line. Assuming that points at the ends of the segments do not belong to them, number 0.625 falls in the third segment, that is, the probabilistic mapping returns the third outcome.

QSMM can use this approach to select an outcome of a probabilistic mapping according to probabilities of all possible outcomes. However, the approach has a drawback: it is hard to evaluate how much information from the random number generator the machine uses to select a particular outcome, as there can be loss of information received from the random number generator.

The following example demonstrates loss of information. If the random number generator returned numbers 1, 1, and 0, the decimal fractional number is 2-1+2-2=0.75. If the random number generator returned numbers 1, 1, and 1, the decimal fractional number is 2-1+2-2+2-3=0.875. Both fractional numbers fall in the fourth segment, so the third number produced by the random number generator in both cases does not make any difference.

Another approach is putting more load on the random number generator to select a less probable outcome and putting less load on the random number generator to select a more probable outcome. In the extreme case, when an outcome has probability 1, and all other outcomes have probability 0, the machine selects the outcome without calling the random number generator at all.

In this approach, the machine builds a binary Huffman tree for a list of probabilities of all outcomes and then traverses the nodes of the Huffman tree from the root node to a leaf node representing a selected outcome by calling the random number generator at each traversed non-leaf node to select one of its two child nodes. This approach, however, implies rounding outcome probabilities to 2-k, where k is the depth of a leaf node, and works better for a sufficiently large number of possible outcomes.

Generally, the greater is the probability of a leaf node, the shorter is a path to it from the root node, and, therefore, a lesser number of calls to the random number generator is necessary to select the leaf node. Thus, it is easier to select a more probable outcome, because this selection requires a lesser number of actions to perform.

Conversely, the lesser is the probability of a leaf node, the greater number of calls to the random number generator is necessary to select the leaf node. It looks like this principle is relevant to the physical environment—for a less probable event to occur, more random events have to happen.

For our example with outcome probabilities 0.125, 0.5, 0.125, and 0.25, the Huffman tree is:

Huffman tree for probabilities 0.125, 0.5, 0.125, and 0.25

Figure 1.1: Huffman tree for probabilities 0.125, 0.5, 0.125, and 0.25

For the above Huffman tree, the machine selects the most probable second outcome with probability 0.5 if a call to the random number generator returns 1. The machine selects the least probable first or third outcome with probability 0.125 if three calls to the random number generator return the sequence 0, 1, 0 or 0, 1, 1 respectively. The average number of calls to the random number generator for the Huffman tree is equal to 0.125*3+0.5*1+0.125*3+0.25*2=1.75.

For four equal outcome probabilities 0.25, the Huffman tree is:

Huffman tree for four probabilities 0.25

Figure 1.2: Huffman tree for four probabilities 0.25

For the above Huffman tree, the number of calls to the random number generator to select any outcome is 2. On average, this Huffman tree puts more load on the random number generator to select an outcome compared to the Huffman tree in Figure 1.1.

To conclude, the average number of calls to the random number generator depends on a degree of difference between outcome probabilities—if some probabilities are much greater than others, the number of calls is less, and, if all probabilities are more or less equal, the number of calls is greater.

Supposing all calls to the random number generator have the same choice complexity, selecting a particular outcome of a probabilistic mapping would have a choice complexity value equal to a constant choice complexity value multiplied by the number of calls to the random number generator required to perform the selection. An average choice complexity value would be equal to a constant choice complexity value multiplied by the average number of calls to the random number generator required to select an outcome.

However, calls to the random number generator might not have equal choice complexity. Choice complexity for a stochastic act of selecting number 0 or 1 by the random number generator might depend on the number of distinguished outcomes the act has. If the outcomes are similar, the number of distinguished outcomes may be less than 2.

The distinguishability of outcomes might depend on a way how the stochastic act affects the entropy of nature. For example, when water is boiling in a kettle, water molecules move rapidly, and a possible location of a water molecule after a fixed period of time varies greatly. However, locations of water molecules in the kettle probably do not affect much—a usable outcome would be hot water in the kettle to make tea. In this case, the complexity of choice associated with a water molecule might be low. On the other hand, if the next location of a molecule were affecting a resolution of a stochastic optimization task where to search planets in space for colonization, the complexity of choice associated with the molecule could be high.

If nature is a self-sustaining environment, one can interpret the complexity of choice as the amount of change necessary to perform to sustain the environment as a result of various outcomes of a stochastic act. Supposing time is closed like space might be, sustaining the environment requires continuous effort throughout all time-space continuum.

Let us consider an adaptive probabilistic mapping. If an outcome positively correlates with a desired change in spur, and all other outcomes have a lesser correlation, the outcome has a greater probability compared to all other outcomes. If an outcome always led to a desired change in spur, and all other outcomes never led to the change, the outcome would have probability 1, and all other outcomes would have probability 0—the choice of a result of the probabilistic mapping for a specific argument would be deterministic. On the other hand, if all outcomes equally lead to a desired change in spur, they all have equal probabilities (that sum up to 1).

Suppose a machine is solving an optimization task consisting in the maximization of spur increment velocity, and the machine has learned how to achieve a constant increase in the velocity. The adaptive probabilistic mapping would have an argument where one of its corresponding outcomes has a significantly greater probability compared to probabilities of all other outcomes for the argument. This outcome would take part in reinforcing a behavior to constantly increase spur increment velocity. The machine puts a little load on the random number generator to produce a result of the adaptive probabilistic mapping for the argument, because the outcome with a significantly greater probability becomes the result most of the times.

Consider a situation that, at a particular point of time, the increment velocity has gone down, so the machine needs to change its own behavior to increase the increment velocity even more. The outcome with a significantly greater probability has now a lesser probability approximately equal to probabilities of some other outcomes for the argument. Probabilities of outcomes for other arguments may also change in a similar way. The machine engages the random number generator in a greater extent for selecting outcomes with less differing probabilities.

In other words, the machine is now in a difficult situation that means an increase of average complexity of choices the machine has to perform to increase the increment velocity. Would the machine feel the difficulty? (To answer this question, one can consider the amount of energy supplied to the random number generator.) The author considers the awareness of difficulty a rudiment of consciousness.

A computer running a pseudo-random number generator can simulate the behavior of a probabilistic mapping. Running a pseudo-random number generator is a deterministic process—the way today’s computers operate. A computer could use a random number generator implemented as a physical unit running a stochastic physical process. We could consider the unit as an interface to a (probabilistic) mapping provided by nature. A stochastic act would then be calling the mapping to obtain a result for a particular argument.

One could relate the abstract idea of good and bad to the concept of choice complexity. The good would support a certain level of choice complexity. The survival of an animate being would be preserving its ability to perform choices with a sufficient degree of complexity.


1.5 QSMM Components

The QSMM library consists of the following main components:

  • Actor implementation. Actor is an adaptive probabilistic mapping. An actor has a number of adjustable modes and parameters and supports limited customization of its algorithms. The Actor API makes it possible to create and destroy actors and perform various operations on them. The main operation is obtaining an outcome for a particular argument. Supplying the spur to an actor modulates causal relationships between the arguments and outcomes.
  • Multinode model engine. It is an engine for running adaptive (“intelligent”) state models. The engine relies on actors to achieve adaptive behavior. A node, a state sub-model represented by a probabilistic finite automaton, interacts with an environment by means of executing assembler instructions. A developer provides a set of assembler instructions and provides their implementations as callback functions. By default, every node is a probabilistic finite automaton of uniform structure—it has all states connected in all possible ways with equal probabilities.
  • Assembler. Parses a probabilistic assembler program and converts it to a probabilistic finite automaton. The assembler program defines probabilities of transitions between automaton states. The probabilities specify soft and hard constraints on automaton behavior.
  • Disassembler. Converts a probabilistic finite automaton with state transition probabilities adjusted by spur modulation back to a probabilistic assembler program.

The QSMM library also includes a C implementation of functionality of STL map and multimap templates. A developer can use it to create ordered tree mapping objects in C programs without the need to rewrite them in C++.

The QSMM package includes the following main tools:

  • Adaptive top-down parser. Adaptively parses a terminal symbol sequence in the top-down direction according to a template grammar specified as a set of nonterminal symbols with associated regular expressions. The parser learns a restricted (more precise) grammar by iteratively determinizing the template grammar while parsing the terminal symbol sequence multiple times.
  • Adaptive bottom-up parser. Adaptively parses a list of terminal symbol sequences in the bottom-up direction by utilizing a top-down template grammar containing references to the productions of a context-free grammar inferred from a bottom-up template grammar. Both the top-down template grammar and bottom-up template grammar are sets of nonterminal symbols with associated regular expressions, where the former grammar is a transformation of the latter grammar. While parsing the list of terminal symbol sequences multiple times, the parser learns a more precise top-down grammar and, consequently, learns a PCFG (Probabilistic Context-Free Grammar) by restricting the context-free grammar inferred from the bottom-up template grammar.
  • Bottom-up to top-down grammar converter. Converts a template grammar intended for parsing input terminal symbol sequences in the bottom-up direction to a template grammar intended for parsing input terminal symbol sequences in the top-down direction. The latter (top-down) template grammar can contain references to the productions of a context-free grammar inferred from the former (bottom-up) template grammar.
  • Converter to a factored PCFG. Converts a template grammar specified as a set of nonterminal symbols with associated regular expressions to a PCFG for parsing terminal symbol sequences up to specified length in Viterbi style. Every nonterminal symbol of the PCFG has exact length of a terminal symbol sequence the nonterminal symbol consumes. The PCFG has multiple start nonterminal symbols for various lengths of input parse units.

1.6 Obtaining QSMM

The official homepage of QSMM project:

The package distribution is available on the project files page provided by SourceForge.net:


1.7 Reporting Bugs and Getting Help

The QSMM users mailing list is a place for discussing all things QSMM. To subscribe to the mailing list, unsubscribe from the list, view list archives, and perform other actions, use its information page:

The following types of feedback should go to the mailing list:

  • Bugs. Please report bugs in QSMM and its documentation for quicker fixing them.
  • New feature requests. If you would like to see a new feature in QSMM (e.g. a new API function to make it possible or simpler to write some kind of applications), then please submit a feature description.
  • Questions and technical support. Because of experimental nature of this software, answers to some questions might not be as useful as one would expect.

Do not be embarrassed by a small number of messages in the list archives—be the first to report a bug, submit a feature request, or ask a question!


1.8 System Requirements

System requirements include:

  • operating system requirements;
  • requirements to a software environment for building package programs, running tests, and building the documentation;
  • a reference hardware environment.

This section does not mention usual programs and libraries for building and running programs written in C, nor it does mention standard programs commonly used in bash scripts.

Operating System—GNU/Linux

QSMM version 1.19.1 supports building and using on a GNU/Linux system. The author has not tested building this package version in other environments.

Building Package Programs

The author was building package programs by gcc version 13.3.

Optional but default library dependencies are gsl (GNU Scientific Library) and ncurses (console display library). The author was using the following library versions:

  • gsl 2.7
  • ncurses 6.5

Running Tests

The test suite supports running package programs under Valgrind (open-source memory debugger for GNU/Linux). The author was using valgrind version 3.20.

Building the Documentation

Building the package documentation in various formats requires the presence of additional packages in the system. Below is their list along with versions used by the author:

  • asymptote 3.05
  • dvipsk 2024.03.11
  • imagemagick 7.1.2
  • ghostscript 10.06
  • texinfo 7.2
  • texlive 2024

Reference Hardware Environment

The author was building the package and running its programs in the following hardware environment:

  • Intel® Celeron® CPU @ 2.1 GHz, 1 core
  • 1G RAM

1.9 Installation

For package installation instructions, refer to the file INSTALL located in the root of the package distribution. This manual does not include them to avoid duplication. The instructions also describe building documentation files, including this manual, and running the test suite.


1.10 API Basics

A C program that uses QSMM includes one or more its header files. The main header file is qsmm.h. The #include <qsmm/qsmm.h> directive includes that file in the C program.

The header file qsmm.h includes a number of other header files. The C program can include them individually. For example, the header file sig.h defines datatypes and macros for signals.

Object handles reference objects of various types. For example, an object handle of qsmm_actor_t type references an adaptive probabilistic mapping.

All API functions report errors in a unified manner—via a result of int type, where negative results are error codes. A multinode model supports assigning an error handler to it for simpler error checking.

The API has a function for retrieving the version of a QSMM library.


1.10.1 Header Files

The configure script sets the root directory for installing C header files. By default, it is the directory /usr/local/include/. The command make install installs public QSMM header files to the subdirectory qsmm. Therefore, after an invocation of configure script with default parameters, the command make install installs public QSMM header files to the directory /usr/local/include/qsmm/. Using a command line option of configure script, you can specify a different root directory for installing C header files. See the file INSTALL in the root of the package distribution for more information.

Below is the list of public header files installed:

qsmm.h

This is the main header file of QSMM framework. It contains most of datatype, function, and macro definitions a developer may need.

err.h

[New in QSMM 1.17] This header file contains declarations of error codes, the prototype of qsmm_err_str function for obtaining the description of an error code, and declarations necessary for using an error handler function with a multinode model. The error handler function processes errors detected by API functions taking a multinode model handle. See Error Handling, for basic information on handling errors. The header file qsmm.h includes this header file.

sig.h

[New in QSMM 1.17] This header file contains declarations of qsmm_sig_t and qsmm_ssig_t datatypes and definitions of QSMM_SIG_INVALID, QSMM_SIG_MAX, QSMM_FMT_PRI_SIG, QSMM_FMT_PRI_SSIG, and QSMM_FMT_SCN_SIG macros. See Basic Datatypes and Macros, for more information about the aforementioned datatypes and macros. The header files qsmm.h and err.h include this header file.

handle.h

[New in QSMM 1.17] This header file contains declarations of incomplete types for object handles. See Object Handles, for more information on them. Along with the incomplete types for object handles, the header file declares the enumeration qsmm_handle_e for possible object handle types, the union qsmm_handle_u representing any object handle, and the structure qsmm_handle_s consisting of an object handle type and object handle value. The header file qsmm.h includes this header file.

refe.h

[New in QSMM 1.17] This header file contains datatypes for entity references. They identify entities related to error conditions for a multinode model. An error handler function assigned to a multinode model can receive entity references as part of an argument. Additionally, entity references identify entities in a multinode model when enumerating them. See Entity References, for more information. The header files qsmm.h and err.h include this header file.

side.h

A self-contained header file for the Side API. That simple API provides means for exchanging data packets, especially signals, between threads in a multithreaded program. In some cases, program structure with a number of interacting sides executing in separate threads and exchanging data packets can increase performance, simplify program development, or simplify experimenting. See Exchanging Data Packets in a Multithreaded Program [Experimental], for more information about the Side API.

The command make install installs this header file when the configure script has configured the package to use the POSIX threads API (see the file INSTALL in the root of the package distribution for information on package configuring).

map.h

A self-contained header file for the C implementation of functionality of STL map and multimap templates. See The Implementation of Functionality of STL map Template, for more information.

version.h

A header file with the macro QSMM_HEADERS_VERSION defined to package version. A developer can use that macro to check if versions of the headers and the library conform. The command make generates the content of version.h using the template qsmm/version.h.in. The header file qsmm.h includes this header file.

To include the aforementioned header files in a C program by a preprocessor #include directive, a developer should specify the directory prefix qsmm. For example, to include the header file qsmm.h, a developer should use the directive:

#include <qsmm/qsmm.h>

The extern "C" declarations wrap C functions declared in the header files. When a C++ source file includes the header files, the declarations provide correct linkage with functions contained in the QSMM library.


1.10.2 Basic Datatypes and Macros

A basic notion used in QSMM is signal. Signals are parts of an argument of a probabilistic mapping. A result of a probabilistic mapping is also a signal. Signals are carriers of actions. In QSMM, non-negative integer numbers identify signals. The header file sig.h included in qsmm.h and err.h defines datatypes for signal identifiers.

Data type: qsmm_sig_t

This is an unsigned integer datatype for storing signal identifiers and numbers of signals. The set of allowed values for the datatype is the range 0 to QSMM_SIG_MAX+1 and the special value QSMM_SIG_INVALID. The current implementation defines the datatype as unsigned int.

In principle, a developer can define the datatype as a different unsigned integer type. Corresponding modification of definitions of qsmm_ssig_t datatype and QSMM_SIG_MAX, QSMM_SIG_INVALID, QSMM_FMT_PRI_SIG, QSMM_FMT_PRI_SSIG, and QSMM_FMT_SCN_SIG macros (see below) may be necessary. The values QSMM_SIG_MAX+1 and QSMM_SIG_INVALID must lie in the range of allowed values of size_t type. This restriction means that the condition “sizeof(qsmm_sig_t)<=sizeof(size_t)” holds true.

Data type: qsmm_ssig_t

[New in QSMM 1.17] This is a signed integer datatype for storing signal identifiers and numbers of signals. The set of allowed values for the datatype is the range -(qsmm_ssig_t) QSMM_SIG_MAX-1 to QSMM_SIG_MAX+1 and the special value QSMM_SIG_INVALID. The current implementation defines the datatype as int. Specifics of defining the datatype as a different signed integer type are the same as for the datatype qsmm_sig_t. The condition “sizeof(qsmm_ssig_t)==sizeof(qsmm_sig_t)” must hold true.

Signal identifiers specify not only signals themselves but also other entities internally represented by signals. For example, identifiers of nodes of a multinode model and identifiers of their states are signal identifiers.

The following macros can be helpful when working with signal identifiers.

Macro: QSMM_SIG_INVALID

Represents an invalid signal identifier. Use it as a substitute for the NULL signal identifier value because identifier 0 is valid one. The macro expands to an unsigned integer value. In QSMM version 1.19.1, the macro expands to ((1 << (sizeof(qsmm_sig_t)*8-1))-0U).

Macro: QSMM_SIG_MAX

This is an unsigned integer value equal to the maximum allowed value of a signal identifier.

Consider two statements:

  1. When an array contains information on signals with identifiers in the range 0 to QSMM_SIG_MAX, the number of elements in the array is equal to QSMM_SIG_MAX+1.
  2. When the upper bound of a range of signal identifiers is not inclusive, the range x to QSMM_SIG_MAX has upper bound QSMM_SIG_MAX+1.

To make it possible to use the datatypes qsmm_sig_t and qsmm_ssig_t for specifying numbers of signals in the first case and signal ranges with not inclusive upper bounds in the second case, the mentioned datatypes additionally support storing value QSMM_SIG_MAX+1. The datatype qsmm_ssig_t additionally supports storing value -(qsmm_ssig_t) QSMM_SIG_MAX-1. In QSMM version 1.19.1, the macro expands to ((1 << (sizeof(qsmm_sig_t)*8-1))-2U).

Macro: QSMM_FMT_PRI_SIG

[New in QSMM 1.17] An optional length modifier and a conversion specifier in format strings for functions similar to printf for printing values of qsmm_sig_t type. The macro expands to ‘u’.

Macro: QSMM_FMT_PRI_SSIG

[New in QSMM 1.17] An optional length modifier and a conversion specifier in format strings for functions similar to printf for printing values of qsmm_ssig_t type. The macro expands to ‘d’.

Macro: QSMM_FMT_SCN_SIG

[New in QSMM 1.17] An optional length modifier and a conversion specifier in format strings for functions similar to scanf for parsing values of qsmm_sig_t type. The macro expands to ‘u’.

Below there is an example of using the datatype qsmm_sig_t and the macro QSMM_FMT_PRI_SIG. The function print_sig_array prints an array of signal identifiers specified by a pointer to the array and the number of its elements.

#include <stdio.h>
#include <qsmm/qsmm.h>

void
print_sig_array(
    const qsmm_sig_t *sigp,
    qsmm_sig_t nsig
) {
    putchar('[');
    for (qsmm_sig_t idx=0; idx<nsig; idx++) {
        if (idx) fputs(", ",stdout);
        printf("%" QSMM_FMT_PRI_SIG,sigp[idx]);
    }
    puts("]");
}

1.10.3 Object Handles

Object handles reference various objects created by the QSMM library. A handle is a typed pointer to a QSMM internal structure. The type of a handle corresponds to the type of an object referenced by the handle. Except for handles of qsmm_mehcall_t type, a program that uses the QSMM library cannot examine or change the content of the internal structure by methods other than calling API functions taking a handle of the corresponding type as an argument. Except for handles of qsmm_mehcall_t type, dereferencing handles does not make sense, as they have incomplete types. Because a handle is a pointer, it can have the NULL value.

The table below lists handle types used in QSMM. For each handle type, the table indicates a corresponding object type and a reference to a manual section with an object description.

Handle TypeObject TypeReference to a Section in This Manual
qsmm_tmultinode modelCreating a Multinode Model
qsmm_actor_tactorCreating an Actor
qsmm_actpair_tactor pairCreating the Model Instance
qsmm_instr_tassembler instructionBasic Datatypes
qsmm_iter_tmap iteratorPart of C implementation of functionality of STL map and multimap templates. See Creating Maps and Iterators.
qsmm_map_tmapPart of C implementation of functionality of STL map and multimap templates. See Creating Maps and Iterators.
qsmm_mehcall_tmodel event handler callEvent Handler Call Parameters
qsmm_msg_tmessageCreating Messages
qsmm_msglist_tmessage listCreating a Message List
qsmm_prg_tassembler programBasic Datatypes
qsmm_rng_trandom number generatorCreating a Random Number Generator
qsmm_side_tinteraction sidePart of Side API. See Registering Interaction Sides.
qsmm_storage_tstatistics storageStorage Handle
qsmm_vec_tvectorOrdinary and Sparse Vectors

Note: it is generally acceptable to call API functions for different handles in different threads of a multithreaded program concurrently on condition that the handles do not reference interrelated objects (e.g. when an object is a component of another object). However, calling API functions for the same handle is not thread safe except for the Side API intended for communication between threads.

The following enumeration specifies possible handle types.

Enumeration: qsmm_handle_e

This enumeration lists supported types of object handles. The enumeration contains the following elements.

QSMM_HANDLE_INVALID

The special value denoting an invalid, unknown, or NULL object handle type.

QSMM_HANDLE_MODEL

A multinode model handle. It has the type qsmm_t.

QSMM_HANDLE_ACTOR

An actor handle. It has the type qsmm_actor_t.

QSMM_HANDLE_ACTPAIR

An actor pair handle. It has the type qsmm_actpair_t.

QSMM_HANDLE_INSTR

An assembler instruction handle. It has the type qsmm_instr_t.

QSMM_HANDLE_ITER

A key-value map iterator handle. It has the type qsmm_iter_t.

QSMM_HANDLE_MAP

A key-value map handle. It has the type qsmm_map_t.

QSMM_HANDLE_MEHCALL

The handle of a model event handler call. The handle has the type qsmm_mehcall_t.

QSMM_HANDLE_MSG

The handle of an error, warning, note, or uncategorized message. The handle has the type qsmm_msg_t.

QSMM_HANDLE_MSGLIST

The handle of a list of error, warning, note, or uncategorized messages. The handle has the type qsmm_msglist_t.

QSMM_HANDLE_PRG

An assembler program handle. It has the type qsmm_prg_t.

QSMM_HANDLE_RNG

A random number generator handle. It has the type qsmm_rng_t.

QSMM_HANDLE_SIDE

An interaction side handle. It has the type qsmm_side_t.

QSMM_HANDLE_STORAGE

A statistics storage instance handle. It has the type qsmm_storage_t.

QSMM_HANDLE_VEC

The handle of an ordinary or sparse vector. The handle has the type qsmm_vec_t.

QSMM_HANDLE_COUNT

The number of elements in the enumeration excluding this element.

The following union represents a handle of a specific or generic type.

Union: qsmm_handle_u

This union represents one of typed object handles or an untyped object handle. The union contains the following fields.

Field: qsmm_t qsmm

A multinode model handle.

Field: qsmm_actor_t actor

An actor handle.

Field: qsmm_actpair_t actpair

An actor pair handle.

Field: qsmm_instr_t instr

An assembler instruction handle.

Field: qsmm_iter_t iter

A key-value map iterator handle.

Field: qsmm_map_t map

A key-value map handle.

Field: qsmm_mehcall_t mehcall

The handle of a model event handler call.

Field: qsmm_msg_t msg

The handle of an error, warning, note, or uncategorized message.

Field: qsmm_msglist_t msglist

The handle of a list of error, warning, note, or uncategorized messages.

Field: qsmm_prg_t prg

An assembler program handle.

Field: qsmm_rng_t rng

A random number generator handle.

Field: qsmm_side_t side

An interaction side handle.

Field: qsmm_storage_t storage

A statistics storage instance handle.

Field: qsmm_vec_t vec

The handle of an ordinary or sparse vector.

Field: void * raw_p

An untyped object handle.

The following structure holds the type of a handle along with its value.

Structure: qsmm_handle_s

This structure holds the type of an object handle and its value. The structure contains the following fields.

Field: enum qsmm_handle_e type

An object handle type.

Field: union qsmm_handle_u val

An object handle value corresponding to an object handle type in the field type.


1.10.4 Error Handling

If an API function returns a value of int type, a negative return value is an error code. A non-negative return value can hand over additional information regarding successful completion of a function call.

If an API function does not return a value of int type, the function does not support returning an error code, because error condition cannot arise within the function, or because there was such assumption when the function first appeared in the API.

If not otherwise noted in the description of an error code of an API function, returning the error code means retaining the state of QSMM library equivalent to omitting a call to the function.

Use the following API function from the header file err.h (included in qsmm.h) to get the text description of an error code.

Function: const char * qsmm_err_str (int err)

This function returns the text description of API error code err. For invalid error codes, the function returns ‘?’.

You can associate an error handler with a multinode model. The error handler receives extended information about errors in API functions that have an argument of qsmm_t type. By using the error handler, it is possible to get rid of adding extra code for checking return values of function calls to detect if they failed. See Error Handling for a Multinode Model, for information on using error handlers.


1.10.5 Getting Library Version

Currently, the version of a QSMM library has major.minor format. In the future, a QSMM library with a greater major version may have considerable backward-incompatible changes to the API. That is, upgrading existing applications to support versions with a greater major number may require considerable changes to source code of the applications.

Use the following API function from the header file qsmm.h to get string representation of library version:

Function: const char * qsmm_version ()

This function returns the version of a QSMM library as a string in major.minor format (e.g. ‘1.19.1’).

Use the following macro from the header file version.h (included in qsmm.h) to get string representation of the version of library header files:

Macro: QSMM_HEADERS_VERSION

This macro expands to string representation of the version of installed header files of a QSMM library in major.minor format (e.g. to ‘1.19.1’).


1.11 Linking with the Library

The QSMM library may have dependencies on other libraries. The configure script executed at the package configuring phase defined the dependencies. For a shared version of QSMM library, the shared library file embeds references to the dependencies, so you do not need to specify them in a link command:

gcc example.o -L/usr/local/lib -lqsmm

(If the library resides in the directory /usr/local/lib/, and that directory is not on the standard linker search path, use the option -L/usr/local/lib.)

To link with a static version of QSMM library, you need to specify libraries it depends on in a link command. For this, use linker options -l, such as -lgsl and -lm, for example:

gcc example.o -lqsmm -lgsl -lm

Alternatively, you can link using the libtool program. It uses the file libqsmm.la copied to the library directory when installing the package. That file describes all dependencies required to produce an executable linked against the QSMM library. The libtool program simplifies static linking.


1.12 Conventions for Datatypes

Names of all datatypes declared in public header files of QSMM library and declared in its source code are in lowercase. Suffixes of the names correspond to C language keywords used for datatype declarations:

typedef

The ‘_t’ suffix. All names of datatypes for function pointers have the ‘_func_t’ suffix.

enum

The ‘_e’ suffix.

struct

The ‘_s’ suffix.

union

The ‘_u’ suffix.

Names of all datatypes declared in public header files of QSMM library have the ‘qsmm_’ prefix.

QSMM has conventions for the use of basic C language types and the types qsmm_sig_t and qsmm_ssig_t in various situations. The API and the package source code itself follow the conventions. C programs that use the QSMM library can also follow them.

The primary conventions are that if a datatype holds signal identifiers or numbers of signals, and such values

  • never lie outside the range 0 to 32767, then you can use the type qsmm_sig_t;
  • may be negative but never lie outside the range −32768 to 32767, then you can use the type qsmm_ssig_t;
  • are non-negative and may exceed 32767, then you should use the type qsmm_sig_t;
  • may be negative and may lie outside the range −32768 to 32767, then you should use the type qsmm_ssig_t.

For other situations, including ones when you chose not to use the type qsmm_sig_t or qsmm_ssig_t according to the first two items of primary conventions stated above, the rules are:

  1. For boolean flags, use the type char or int or use specific bits in values of other numeric types.
  2. For integer quantities that never lie outside the range 0 to 127, use the type char or int.
  3. For integer quantities that may be negative but never lie outside the range −128 to 127, use the type signed char or int.
  4. For non-negative integer quantities that may exceed 127 but never exceed 255, use the type unsigned char or int.
  5. For integer quantities that may be less than −128 but never lie outside the range −32768 to 32767, use the type int.
  6. For integer quantities that may exceed 255 but never lie outside the range −32768 to 32767, use the type int.
  7. For non-negative integer quantities that may exceed 32767 but never exceed 65535, use the type unsigned int.
  8. For non-negative integer quantities that may exceed 65535 but do not have the restriction that they must be at least 64-bit, use the type long or unsigned long.
  9. For integer quantities that may be less than −32768 and may be greater than 32767 but do not have the restriction that they must be at least 64-bit, use the type long.
  10. For integer quantities that must be at least 64-bit, use the type long long or unsigned long long.

For example, in QSMM:

  • the type char holds unpacked boolean flags;
  • the type int holds error codes and indices of spur types;
  • the type long holds frequencies and the moments of discrete time.

The set of datatypes declared in the API with the ‘_t’ suffix in their names includes the datatypes qsmm_sig_t and qsmm_ssig_t, datatypes for function pointers with the ‘_func_t’ suffix, and datatypes for object handles (see Object Handles, for more information).

Datatypes declared in the API with the ‘_e’ suffix in their names are enumerations. Elements of enumerations are in uppercase.

Datatypes with the suffixes ‘_s’ and ‘_u’ are structures and unions respectively. The order of their fields depends on field datatypes and is the following:

  1. Fields of basic types. The type order is the following: char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double.
  2. Fields of types defined in QSMM with the ‘_t’ suffix in their names.
  3. Fields of the other types except for pointers of void * type and except for types defined using the keywords ‘enum’, ‘struct’, and ‘union’.
  4. Fields of types defined using the keyword ‘enum’. Enumerations defined in QSMM go first.
  5. Fields of types defined using the keyword ‘struct’. Structures defined in QSMM go first.
  6. Fields of types defined using the keyword ‘union’. Unions defined in QSMM go first.
  7. Fields holding pointers of void * type.

For every type name within each type category listed above, the type order is the following:

  1. Non-pointer and non-array types (not applicable to the void type).
  2. Arrays (but not pointers to arrays), including arrays of pointers.
  3. Pointer types (except for arrays of pointers) with full names beginning with the const qualifier in the order of increasing the number of asterisks.
  4. Pointer types (except for arrays of pointers) with full names that do not begin with the const qualifier in the order of increasing the number of asterisks.

2 Adaptive Probabilistic Mapping

An implementation of adaptive probabilistic mapping is actor. An actor interacts with an application program or environment by means of exchanging signals. Specific arguments of an adaptive probabilistic mapping correspond to input signals of an actor. Specific outcomes of an adaptive probabilistic mapping correspond to output signals of an actor. Input signals of an actor can be its transformed output signals similarly to the case when the arguments of an adaptive probabilistic mapping are its transformed outcomes.

An actor usually receives input signals, spur (see Spur-Driven Behavior) increments, and time increments and emits output signals with the goal to maximize spur increment velocity. To achieve that goal, the actor performs basic forecasting of spur increments resulting from emitting various output signals. The author believes that by combining multiple actors or applying other approaches it is possible to amplify this forecasting capability to create a system intelligently interacting with an environment of real-world complexity.


2.1 Event History

Occurrences of input and output signals of an actor with particular moments of time when the occurrences took place is an actor’s event history.

An example event history along with changed spur values represented as a two-dimensional chart is in Figure 2.1.

an event history example as a two-dimensional chart

Figure 2.1: an event history example as a two-dimensional chart

In the chart, filled dots denote the events of receiving input signals, and unfilled dots denote the events of emitting output signals. Every such event is on a horizontal line denoting a particular input or output signal with an identifier printed after the line end. Every input signal and its corresponding output signal connected by an arrow are on the same vertical line, as the API does not specify time between receiving an input signal and emitting an output signal by an actor. A plot of single spur value changing over time is above the event history.

A fragment of this two-dimensional chart in gray represented as a one-dimensional plot is in Figure 2.2.

an event history fragment as a one-dimensional plot

Figure 2.2: an event history fragment as a one-dimensional plot

We can consider that every event of receiving an input signal encodes an event of receiving a tuple of signals. Identifiers assigned to unique tuples will be input signal identifiers.

For example, we can replace every input signal with a triple of signals. The above event history fragment changed to show input signals replaced with signal triples is in Figure 2.3.

tuples of signals as input signals

Figure 2.3: tuples of signals as input signals

In this figure, input signal 3 has encoded the triple <3, 0, 4>, input signal 5 has encoded the triple <1, 2, 5>, and input signal 0 has encoded the triple <5, 3, 4>.

In this way, by setting one-to-one correspondence between single-value arguments of a probabilistic mapping and n-value tuples, we convert the mapping to an n-ary probabilistic mapping.

By including the previous outcome of a probabilistic mapping in its next n-ary argument, we convert a stateless probabilistic mapping to stateful one—an outcome of a probabilistic mapping becomes its state. Using this approach, a probabilistic mapping can model a finite automaton. After the conversion, input signal 5 encodes the quadruple <5, 1, 2, 5>, and input signal 0 encodes the quadruple <3, 5, 3, 4>, where the first 5 in the first quadruple is a previous state of the probabilistic mapping, and the first 3 in the second quadruple is the next state.

An n-ary argument of an adaptive probabilistic mapping is an action choice state of an actor. An action choice state is an input list of events an actor shall respond to by choosing an action—emitting an output signal. An action choice state might be a known or guessed current system or environment state that requires generating an adaptive action.

In the past, action choice states were meant to be n-grams of events from an event history. The current view is that action choice states are not necessarily n-grams, but the terminology remains the same for compatibility. An action choice state n-gram is a signal identifier list encoding an action choice state. The tuples <3, 0, 4>, <1, 2, 5>, <5, 3, 4>, <5, 1, 2, 5>, and <3, 5, 3, 4> are action choice state n-grams used to select output signals 5, 3, and 1.


2.2 Output Signal Selection

An actor emits output signals stochastically according to their probabilities the actor calculates. It collects statistics on observed consequences of emitting various output signals in various action choice states. The actor treats the observed consequences as dependent only on a specific action choice state and a specific output signal emitted in the action choice state. An event history segment for observing the consequences is a cycle—a segment between an occurrence of the action choice state in the event history and the next occurrence of the action choice state in the event history. The actor uses the collected statistics to calculate the probabilities of emitting output signals allowed in a current action choice state.

For every occurrence of an action choice state in the event history, the actor updates statistics on a cycle type—a pair comprised of the action choice state and an output signal emitted at the previous occurrence of the action choice state in the event history. The actor updates the statistics with the following parameters:

  • spur increment between the previous occurrence of an action choice state and its current occurrence;
  • time increment between the previous occurrence of an action choice state and its current occurrence;
  • number of output signals emitted between the previous occurrence of an action choice state and its current occurrence;
  • number of times the actor emitted the output signal in the action choice state.

The actor calculates probabilities of output signals to emit in a current action choice state using statistics collected for pairs comprised of the action choice state and each allowed output signal. This statistics includes the following parameters for event history segments between an occurrence of the action choice state with emitting the output signal and the next occurrence of the action choice state:

  • sum of spur increments over the segments;
  • total time length of the segments;
  • mean number of output signals emitted in the segments.

Using the sum of spur increments over the segments and the total time length of the segments, the actor can calculate the mean velocity of spur increment over the segments. The higher the mean spur increment velocity is for segments specified by the pair comprised of an action choice state and output signal (i.e. specified by a cycle type), the greater the probability of emitting the output signal in the action choice state can be.

Let us consider a simplistic example. Suppose, an actor has recorded that emitting output signal 18 in an action choice state concluded with spur increment +7 over a period of 40 time units until the action choice state occurred the next time in the event history. Suppose, the actor has also recorded that emitting output signal 19 at another occurrence of the action choice state concluded with spur increment +6 over a period of 30 time units until the action choice state occurred again in the event history. Therefore, when emitting next output signal in the action choice state, the actor will select signal 19 with higher probability than signal 18 because spur increment velocity 6/30 for signal 19 is greater than spur increment velocity 7/40 for signal 18. When an actor emits the same output signal in the same action choice state more than once, the actor accumulates the statistics and uses mean spur increment velocity to calculate the probability of emitting an output signal.

In QSMM, the actor uses a more complex method of selecting an output signal, so the above example is a simplification that does not fully agree with practice. See Customizing the Relative Probability Function, for more information about available and user-defined functions utilizing various kinds of statistics to calculate the probability of emitting an output signal.

To improve reaction to latest tendencies in the event history, the actor may memorize statistics for time periods shorter than the entire event history.


2.3 Small and Large Actors

The most time-consuming operation frequently performed by an actor is adaptive emitting an output signal. The only actor type implemented before QSMM 1.15 was small actor. A small actor performs the operation of adaptive emitting an output signal in the following steps:

  1. The actor calculates relative probabilities of all output signals.
  2. The actor stochastically selects an output signal according to the relative probabilities using a random number generator.

From the standpoint of computer implementation, the most time-consuming is the first step when the actor calculates relative probabilities of all output signals. For example, to adaptively select an output signal from a set of 16 output signals, a small actor has to perform 16 evaluations of a relative probability function. Figure 2.4 illustrates this situation.

emitting an output signal in an action choice state of a small actor

Figure 2.4: emitting an output signal in an action choice state of a small actor

Time necessary for sequential execution of this calculation process is the sum of time periods consumed by the calculation of a relative probability function value for every output signal. While calculating every value can be time expensive on its own on account of performing many arithmetic operations, fetching their input values from statistics storage can add significant time overhead to the calculation process.

To speed up selecting output signals by an actor, QSMM 1.15 introduced the concept of large actor. If the weights (or relative profile probabilities) of output signals of a large actor are equal, the number of relative probability function evaluations performed by the large actor is approximately equal to the product of a logarithm of the number of output signals and a logarithm base. Large actors provide fast selection of an output signal when the number of output signals is large or even huge; the only limitation is the amount of memory available for storing the control structures of a large actor.

The adaptivity of behavior of an actor depends on a relative probability function used, that is, on a function that returns the relative probability of selecting a signal. The default function used by a large actor can provide moderate efficiency in solving certain kinds of problems, for example, the identification of a current environment state. Developers unsatisfied with results produced using that function can provide a custom function via corresponding API calls.

A large actor performs fast stochastic selection of output signals by using output signal choice trees containing nodes controlled by a small actor. The following entities correspond to every tree node:

  1. An action choice state: either root one or intermediate one. The root action choice state is current action choice state of the large actor selecting an output signal for that state.
  2. An array of relative probabilities of output signals typically containing a few elements. The output signals are are either the output signals of the large actor or intermediate output signals. To every intermediate output signal there corresponds an intermediate action choice state located at a deeper hierarchy level.

Figure 2.5 illustrates this tree structure. Indexed letters “s” denote intermediate action choice states, and indexed letters “a” denote intermediate output signals.

emitting an output signal in an action choice state of a large actor

Figure 2.5: emitting an output signal in an action choice state of a large actor

A large actor performs the operation of adaptive emitting an output signal by the following algorithm:

  1. Set the current intermediate action choice state equal to current action choice state of the large actor.
  2. Adaptively generate an output signal for the current intermediate action choice state by a small actor associated with the large actor. This operation requires calculating relative probabilities of all output signals (typically a few ones) for the current intermediate action choice state.
  3. An output signal generated in step 2 can be either an intermediate output signal or an output signal of the large actor. If the output signal is the one of the large actor, then finish.
  4. Change the current intermediate action choice state to an intermediate action choice state corresponding to the intermediate output signal and go to step 2.

Thus, using a tree represented in Figure 2.5, adaptive selection of an output signal from a set of 16 output signals requires only 8 evaluations of a function returning the relative probability of a signal. A taller binary tree would provide adaptive selection of an output signal from a set of 256 output signals using 16 evaluations of the function.

Tree structure affects weights of output signals of a large actor and the speed of emitting the output signals by the large actor. The weights might be coarsely granular, as the weight of an output signal is inversely proportional to tree arity raised to power equal to the depth of a leaf node for the output signal.

Before QSMM 1.19, large actors always used n-ary Huffman trees to adaptively generate output signals. Using a Huffman tree built for a specific list of output signal weights, emitting output signals with greater weights requires the same or a smaller number of relative probability function evaluations compared to emitting output signals with lesser weights.

QSMM 1.19 has ability to control the granularity of output signal weights to satisfy a specified tolerance. On passing a positive tolerance, a large actor rearranges a Huffman tree built for a list of output signal weights by splitting leaf nodes to make the absolute value of difference between supplied weight of each output signal and its weight determined by the depth of a leaf node for the output signal less than the tolerance. In a rearranged Huffman tree multiple leaf nodes may correspond to the same output signal.

Although having much the same API, small and large actors are not fully interchangeable. There are specifics of using actors of every type.


2.4 Creating an Actor

An actor handle refers to a small or large actor.

Data type: qsmm_actor_t

This is a type for an actor handle. It is a pointer, so variables of this type can be NULL. The function qsmm_actor_create creates a new actor and returns its handle. The function qsmm_actor_destroy destroys an existing actor addressed by a handle. You can pass an actor handle to API functions taking an argument of qsmm_actor_t type after the creation of an actor and until its destruction.

Use the following functions to create and destroy an actor.

Function: int qsmm_actor_create (const struct qsmm_actor_desc_s *desc_p, qsmm_actor_t *actor_p)

This function creates an actor using parameters in *desc_p and stores an actor handle in *actor_p.

If actor_p is NULL, the function only validates parameters in *desc_p.

The function returns a non-negative value on success or a negative error code on failure in creating an actor. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

Parameters in *desc_p are invalid.

QSMM_ERR_NOMEM

There was not enough memory to create an actor.

Function: void qsmm_actor_destroy (qsmm_actor_t actor)

This function destroys an actor specified by handle actor. You must not use the actor handle after actor destruction. If actor is NULL, the function has no effect.

Below there are the description of a structure passed in *desc_p to the function qsmm_actor_create and the description of enclosed structures.

Structure: qsmm_actor_desc_s

This structure describes parameters for creating an actor by the function qsmm_actor_create. The structure contains the following fields.

Field: int nspur

A non-negative number of spur types the actor will use. If the actor is the large one, a small actor associated with it will use the same number of spur types.

Field: int ntime

[New in QSMM 1.19] A non-negative number of continuous time types the actor will use. If the actor is the large one, a small actor associated with it will use the same number of continuous time types. The function qsmm_set_actor_spur_time sets up a correspondence between spur types and time types.

Field: int ngram_sz

The length of a list of signal identifiers encoding an action choice state. That length must be greater than 0.

Field: int compat

The compatibility of algorithms used by the actor: 0, 1, 2, or 3. Value 0 means to use original algorithms implemented before QSMM 1.15. Value 1 supported since QSMM 1.15 means to use enhanced algorithms:

  • use a simpler formula for automatic spur increment;
  • in formulas for computing the relative probability of an output signal, additionally multiply mean discrete cycle period by a ratio for converting discrete time to the number of output signals emitted and, if the relative probability function type is QSMM_RELPROB_BUILTIN1, by 2.

[New in QSMM 1.17] Value 2 further improves the algorithms:

  • calculate output signal probabilities of QSMM_PROB_FQ type by the function qsmm_actor_calc_action_prob based on exact (not sometimes decremented by 1) frequencies of output signals in the event history;
  • for a small actor, make the function qsmm_get_actor_sig_action select a signal without using a random number generator (i.e. deterministically) if the signal is the only one signal with a positive relative probability.

[New in QSMM 1.19] Value 3 means:

  • actor supports multiple continuous time types; the field ntime of qsmm_actor_desc_s structure specifies their number when creating the actor by the function qsmm_actor_create; the actor does not use the field period_sum_c of qsmm_cycle_s structure and the field tmc0 of qsmm_state_s structure;
  • function qsmm_actor_create called for a small actor initializes to 1 (instead of 0.5) the multiplier for converting discrete time to the number of output signals emitted.

Creating a large actor requires setting this field to 3. The function qsmm_actor_create sets the field compat of qsmm_desc_s structure to 3 when creating a multinode model for a large actor.

Set this field to 3 in your new programs. This manual does not include outdated details about old algorithms.

Field: qsmm_sig_t nsig_in

The number of input signals. Input signal identifiers are in the range 0 (inclusive) to that number (exclusive). This field must be greater than 0.

Field: qsmm_sig_t nsig_out

Initial number of output signals. Output signal identifiers are in the range 0 (inclusive) to that number (exclusive). This field must be greater than 1. See Number of Output Signals, for how to obtain the current number of output signals of an actor or increase that number.

Field: qsmm_rng_t rng

The handle of a random number generator the actor will use. See Random Number Generators, for how to create and destroy random number generators and perform other operations on them. If this field is NULL, the function qsmm_actor_create creates an instance of default random number generator for use by the actor until its destruction.

Field: struct qsmm_pair_sig_s * range_sig_p

Ranges of signal identifiers in a list encoding an action choice state. The field ngram_sz of this structure specifies the length of the list. The actor uses the ranges to check the validity of a list of signal identifiers encoding a current action choice state in various API functions.

If the field range_sig_p is not NULL, then this field must be the pointer to an array of ngram_sz elements, where each element is a pair. The elements correspond to positions of signal identifiers in a list encoding an action choice state. The fields first and second of each pair define the minimum value and the maximum value of a corresponding signal identifier. The value of first must be less than or equal to the value of second. The value of second must be less than the number of input signals of the actor specified in the field nsig_in of this structure. If range_sig_p is NULL, this condition means that every signal in the list lies in the range 0 (inclusive) to the number (exclusive) of input signals of the actor.

Field: struct qsmm_actor_large_desc_s * large_desc_p

The parameters of a large actor. A non-NULL value of this field means to create a large actor. This mode requires setting the field compat to 3.

To improve compatibility with future versions of QSMM library, zero by the function memset an instance of qsmm_actor_desc_s structure before setting its fields.

Structure: qsmm_pair_sig_s

This structure holds a pair of signals, for example, a signal range. The structure contains the following fields.

Field: qsmm_sig_t first

The first element of the pair. If the pair represents a signal range, the minimum value of a signal identifier.

Field: qsmm_sig_t second

The second element of the pair. If the pair represents a signal range, the maximum value of a signal identifier.

Structure: qsmm_actor_large_desc_s

This structure specifies the parameters of a large actor.

Field: int tree_arity

The maximum number of child nodes of every node of output signal choice trees for adaptive selection of output signals by the large actor. That number must be greater than 1. You can use value 2 in most cases. It is better to use the number of output signals of a large actor equal to a positive integer power of the value of this field.

Field: double profile_tol

[New in QSMM 1.19] An upper bound on absolute value of difference between the profile probability of each output signal and its probability determined by the structure of an output signal choice tree. The large actor rearranges a Huffman tree built for an action choice state by splitting leaf nodes and making multiple leaf nodes correspond to the same output signals until the absolute value becomes less than the upper bound. The field must be 0 or lie in the range FLT_EPSILON to 1. If the field is 0, the actor does not rearrange Huffman trees built for action choice states.

To improve compatibility with future versions of QSMM library, zero by the function memset an instance of qsmm_actor_large_desc_s structure before setting its fields.

Below there is sample source code for creating a small actor.

struct qsmm_actor_desc_s actor_desc;
memset(&actor_desc,0,sizeof(actor_desc));
actor_desc.nspur=1;
actor_desc.ntime=1;
actor_desc.ngram_sz=3;
actor_desc.compat=3;
actor_desc.nsig_in=6;
actor_desc.nsig_out=4;
qsmm_actor_t actor=0;
const int rc=qsmm_actor_create(&actor_desc,&actor);
if (rc<0) fprintf(stderr,"qsmm_actor_create: %s\n",qsmm_err_str(rc));

Below there is sample source code for creating a large actor.

struct qsmm_actor_desc_s actor_desc;
memset(&actor_desc,0,sizeof(actor_desc));
actor_desc.nspur=1;
actor_desc.ntime=1;
actor_desc.ngram_sz=3;
actor_desc.compat=3;
actor_desc.nsig_in=6;
actor_desc.nsig_out=4096;
struct qsmm_actor_large_desc_s large_desc;
memset(&large_desc,0,sizeof(large_desc));
large_desc.tree_arity=2;
large_desc.profile_tol=0.005;
actor_desc.large_desc_p=&large_desc;
qsmm_actor_t actor=0;
const int rc=qsmm_actor_create(&actor_desc,&actor);
if (rc<0) fprintf(stderr,"qsmm_actor_create: %s\n",qsmm_err_str(rc));

You can obtain some parameters specified when creating an actor by the following functions.

Function: int qsmm_get_actor_nspur (qsmm_actor_t actor)

This function returns a non-negative integer equal to the number of spur types used by actor. The field nspur of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies that number.

Function: int qsmm_get_actor_ntime (qsmm_actor_t actor)

This function returns a non-negative integer equal to the number of continuous time types used by actor. The field ntime of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies that number.

Function: int qsmm_get_actor_ngram_sz (qsmm_actor_t actor)

This function returns a positive integer number equal to the length of a list of signal identifiers encoding an action choice state of actor. The field ngram_sz of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies that length.

Function: int qsmm_get_actor_compat (qsmm_actor_t actor)

This function returns a non-negative integer number indicating the compatibility of algorithms used by actor. The field compat of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies the number.

Function: qsmm_sig_t qsmm_get_actor_nsig_in (qsmm_actor_t actor)

This function returns the number of input signals of actor. The field nsig_in of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies that number.

Function: const struct qsmm_pair_sig_s * qsmm_get_actor_range_sig (qsmm_actor_t actor)

This function returns the pointer to an array in an internal structure of an actor describing allowed ranges of signal identifiers in lists encoding its action choice states. The field range_sig_p of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies the content of the array. The number of elements in the array is equal to the length of a list of signal identifiers encoding an action choice state. The function qsmm_get_actor_ngram_sz returns that length. The function qsmm_get_actor_range_sig never returns NULL.

A datatype for the handle of statistics storage is qsmm_storage_t. See Statistics Storage, for more information. You can obtain the handle of statistics storage of an actor by the following function.

Function: qsmm_storage_t qsmm_get_actor_storage (qsmm_actor_t actor)

This function returns the handle of storage used by actor for collecting statistics on the event history. If the actor is the large one, the storage contains only part of the statistics. Output signal choice trees within the multinode model of the large actor hold the other part of the statistics. The function never returns NULL.

A datatype for the multinode model of a large actor is qsmm_t. You can obtain the handle of the multinode model of an actor by the following function.

Function: qsmm_t qsmm_get_actor_large_model (qsmm_actor_t actor)

This function returns the handle of a multinode model used by a large actor to adaptively emit output signals. If actor is a large actor, the function returns a non-NULL handle. If actor is a small actor, the function returns NULL. You can use this function to determine whether an actor is large or small one.


2.5 Repeated Sequence of Operations

After the creation of an actor and until its destruction, the actor usually performs a repeated sequence of operations—receiving a tuple of input signals followed by emitting an output signal. Any number of spur and time increments can precede or follow the two aforementioned operations.


2.5.1 Receiving Input Signals

An actor has a buffer containing an array of signal identifiers encoding a current action choice state. The field ngram_sz of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies the number of elements in the array. The function qsmm_get_actor_ngram_sz returns that number for a created actor.

The function qsmm_actor_create initializes the array elements to minimum allowed signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure passed to that function.

Use the following function to obtain direct access to the buffer.

Function: qsmm_sig_t * qsmm_get_actor_sig_ngram (qsmm_actor_t actor)

This function returns the pointer to the buffer in actor containing an array of signal identifiers encoding a current action choice state. The number of elements in the array is equal to the field ngram_sz of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor; the function qsmm_get_actor_ngram_sz returns that number for an actor. The function qsmm_get_actor_sig_ngram never returns NULL.

Use the following function to register a current action choice state encoded by an array of signal identifiers contained in the buffer and update statistics on the current action choice state using information recorded when the action choice state occurred the previous time in the event history.

Function: int qsmm_actor_reg_ngram_in (qsmm_actor_t actor)

This function increments by 1 discrete time tracked by an actor and processes an array of signal identifiers encoding a current action choice state contained in a buffer returned by the function qsmm_get_actor_sig_ngram.

If the action choice state did not occur earlier in the event history, the function finishes execution and reports success. If the action choice state occurred earlier in the event history, the function processes a cycle between the previous and current occurrence of the action choice state by updating statistics on its cycle type. A cycle type is the pair comprised of an action choice state and an output signal emitted when the action choice state occurred the previous time in the event history (we refer to that time as the time of cycle start). The output signal emitted is the cycle direction.

If the incremented discrete time is less than or equal to the discrete time of cycle start, the function finishes execution and reports success. Otherwise, the function updates statistics on the cycle type in the following way:

  • increments by 1 the number of occurrences of the cycle type;
  • increments the sum of discrete time periods for the cycle type by the difference between current discrete time and the discrete time of cycle start (we refer to that difference as discrete cycle period);
  • for every continuous time type, the function increments the sum of continuous time periods for the cycle type by the difference between current continuous time and the continuous time of cycle start (we refer to that difference as continuous cycle period);
  • for every spur type, the function increases the sum of spur increments for the cycle type by the difference between a current spur value and a spur value at the cycle start.

If the actor uses automatic spur, the function increments it by the logarithm of observed probability of the cycle type in the event history (see Automatic Spur, for additional information).

To be able to query mean discrete cycle period by the function qsmm_get_actor_discrete_cycle_period_mean, the function qsmm_actor_reg_ngram_in increments by 1 the total number of cycles processed and increments the total sum of discrete cycle periods.

The function qsmm_actor_reg_ngram_in returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NGRAM

A buffer returnable by the function qsmm_get_actor_sig_ngram does not contain a valid array of signal identifiers encoding an action choice state. To determine array validity, the function qsmm_actor_reg_ngram_in checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_INFIN

The operation of computing the increment of automatic spur or the operation of increasing the sum of spur or continuous time increments for the cycle type returned an infinite result.

QSMM_ERR_STORAGE

Statistics storage failure. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

A statistics storage access function generated an error message but could not convert it to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

A statistics storage access function reported out of memory error.

Using the following functions, you can obtain the discrete cycle period of last cycle registered by the function qsmm_actor_reg_ngram_in and the mean discrete cycle period of all cycles registered by that function since creating an actor. You can use this information in a custom function for computing the relative probability of an output signal.

Function: long qsmm_get_actor_discrete_cycle_period_last (qsmm_actor_t actor)

This function returns the discrete cycle period of last cycle registered for actor by the function qsmm_actor_reg_ngram_in. A returned value is always non-negative.

If there was no call to qsmm_actor_reg_ngram_in yet, or at the last call that function did not register a cycle, qsmm_get_actor_discrete_cycle_period_last returns 0.

Function: double qsmm_get_actor_discrete_cycle_period_mean (qsmm_actor_t actor)

This function returns the mean discrete cycle period of all cycles registered for an actor by the function qsmm_actor_reg_ngram_in since creating the actor.

If qsmm_actor_reg_ngram_in did not register any cycle yet, qsmm_get_actor_discrete_cycle_period_mean returns 0. This function returns only finite and non-negative values.


2.5.2 Emitting an Output Signal

Emitting an output signal includes the following steps:

  1. Calculate by the function qsmm_actor_calc_action_prob probabilities of output signals for a current action choice state. This step is only necessary for a small actor.
  2. Select by the function qsmm_get_actor_sig_action an output signal to emit. For a small actor, that function uses output signal probabilities calculated in the previous step. For a large actor, that function uses an output signal choice tree for the current action choice state.
  3. Register the output signal by the function qsmm_actor_reg_sig_out. That function records the following information for the current action choice state: current discrete time, current continuous time for each continuous time type, current spur value for each spur type, and the output signal emitted.

Types of probabilities of output signals are the following.

Enumeration: qsmm_prob_e

This enumeration specifies a type of probabilities. The enumeration contains the following elements.

QSMM_PROB_AGGR

Aggregate probabilities based on learned and profile probabilities.

For a small actor, to calculate probabilities QSMM_PROB_AGGR, the function qsmm_actor_calc_action_prob calculates probabilities QSMM_PROB_LEARNED and QSMM_PROB_PROFILE (see below), multiplies each learned probability by a corresponding profile probability, and normalizes a resulting array. For a large actor, qsmm_actor_calc_action_prob called for an associated small actor performs this operation for the nodes of an output signal choice tree to obtain aggregate probabilities of tree leaves.

For a small actor, if you do not use profile probabilities, it is faster to calculate probabilities QSMM_PROB_LEARNED—they are equal to probabilities QSMM_PROB_AGGR in this case.

QSMM_PROB_LEARNED

For a small actor, learned probabilities for producing adaptive actions. For a large actor, probabilities QSMM_PROB_AGGR.

QSMM_PROB_PROFILE

For a small actor, profile probabilities specified a priori in statistics storage (see Structures for Accessing Storage, for how to pass profile probabilities to storage access functions to write them to storage). For a large actor, profile probabilities following from a subordination relationship of nodes of an output signal choice tree and from probabilities of edges connecting parent tree nodes with their child nodes.

QSMM_PROB_FQ

Probabilities proportional to observed frequencies of output signals registered by the function qsmm_actor_reg_sig_out. For a large actor, calculating probabilities of this type is faster compared to the other types.

QSMM_PROB_COUNT

The last element of this enumeration equal to the number of supported probability types.

Use the following function to calculate probabilities of output signals for a current action choice state.

Function: int qsmm_actor_calc_action_prob (qsmm_actor_t actor, int rez1, qsmm_sig_t sig_beg, qsmm_sig_t sig_end, enum qsmm_prob_e prob_type)

This function fills an internal array of actor with probabilities prob_type calculated for an array of signal identifiers encoding a current action choice state. The function qsmm_get_actor_sig_ngram returns the pointer to a buffer containing the latter array. The argument rez1 is for future use and must be equal to 0.

For a small actor, the function qsmm_get_actor_sig_action stochastically selects an output signal according to probabilities in the internal array. The function qsmm_actor_calc_action_prob is much slower for a large actor compared to a small actor; you should call this function for a large actor only to obtain explicit probability values, as large actors support calling qsmm_get_actor_sig_action without prior calling qsmm_actor_calc_action_prob.

The arguments sig_beg and sig_end specify the identifiers of the first output signal (inclusive) and last output signal (exclusive) of a signal segment for calculating the probabilities. Offsets of output signal probabilities in the internal array are equal to output signal identifiers. If sig_end is 0, the function uses the total number of output signals for the identifier of last signal. The function operates faster when the signal segment is shorter, so specify the segment as precisely as possible.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The value of sig_beg is greater than or equal to the identifier of last signal of the signal segment, or sig_end is too large, or prob_type is invalid.

QSMM_ERR_NGRAM

A buffer returnable by the function qsmm_get_actor_sig_ngram does not contain a valid array of signal identifiers encoding an action choice state. To determine array validity, the function qsmm_actor_calc_action_prob checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_CALLBACK

A helper function QSMM_RELPROB_USER1 or QSMM_RELPROB_USER2 for calculating the relative probability of an output signal reported an error by returning NaN.

QSMM_ERR_STORAGE

Statistics storage failure. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

A generated error message is not convertible to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave a large actor in inconsistent state. If a large actor is in inconsistent state, then, if after removing a reason of an error a repeated call to this function succeeds, the actor’s state becomes consistent.

Use the following function to obtain a pointer to the internal array containing probabilities of output signals calculated by the function qsmm_actor_calc_action_prob.

Function: double * qsmm_get_actor_choice_sig_prob (qsmm_actor_t actor)

This function returns a pointer to internal array of actor holding relative probabilities of output signals. The function never returns NULL. The number of elements in the array is equal to the number of output signals returned by the function qsmm_get_actor_nsig_out. The function qsmm_actor_calc_action_prob fills the array with probabilities of a requested type.

For a small actor, the function qsmm_get_actor_sig_action stochastically selects an output signal according to probabilities in the array. A program can modify the array to affect this stochastic selection. The function qsmm_get_actor_sig_action handles the situation when the array contains elements equal to positive infinity or values that do not sum up to 1. Conversely, modifying the array does not affect the behavior of qsmm_get_actor_sig_action for a large actor.

The function qsmm_get_actor_choice_sig_prob locks the internal array: if a sparse vector backs up the internal array, this function converts the sparse vector to an ordinary vector. After this conversion, the actor keeps the internal array as an ordinary vector until the function qsmm_actor_choice_sig_prob_release releases the internal array. Forgetting to call qsmm_actor_choice_sig_prob_release after a call to qsmm_get_actor_choice_sig_prob may dramatically decrease actor performance.

Use the following function to release a locked internal array.

Function: void qsmm_actor_choice_sig_prob_release (qsmm_actor_t actor)

This function releases the internal array of actor locked by the function qsmm_get_actor_choice_sig_prob. That internal array holds relative probabilities of output signals. If qsmm_get_actor_choice_sig_prob has not locked the internal array, qsmm_actor_choice_sig_prob_release is no-op. You must not use a pointer obtained by qsmm_get_actor_choice_sig_prob after releasing the array.

After locking the internal array by the function qsmm_get_actor_choice_sig_prob and subsequent calling the function qsmm_actor_calc_action_prob or when calling it for a large actor, qsmm_actor_calc_action_prob uses an ordinary vector for storing probabilities of output signals, and you can access its elements via a pointer returned by qsmm_get_actor_choice_sig_prob. When the internal array is in released state, qsmm_actor_calc_action_prob called for a small actor uses a sparse vector for storing probabilities of output signals, and you should use functions described in Ordinary and Sparse Vectors to read vector elements.

Regardless whether the vector is ordinary or sparse, you can obtain its handle and use functions described in Ordinary and Sparse Vectors to access vector elements in read-only mode. Obtaining the handle of an ordinary or sparse vector holding relative probabilities of output signals is a cheap operation that does not perform locking or converting a sparse vector to an ordinary vector.

Function: qsmm_vec_t qsmm_get_actor_choice_sig_prob_vec (qsmm_actor_t actor)

This function returns the handle of an ordinary or sparse vector of actor holding relative probabilities of output signals. The function never returns NULL. The function qsmm_actor_calc_action_prob fills the vector with probabilities of a requested type. For a small actor, the function qsmm_get_actor_sig_action stochastically selects an output signal according to probabilities in the vector.

Use the following function to stochastically select an output signal.

Function: int qsmm_get_actor_sig_action (qsmm_actor_t actor, int rez1, qsmm_sig_t sig_beg, qsmm_sig_t sig_end, qsmm_sig_t *sig_out_p)

If actor is a small one, this function stochastically selects an output signal according to relative probabilities stored in the internal array of relative probabilities of output signals. Offsets of output signal probabilities in the internal array are equal to output signal identifiers. The function qsmm_actor_calc_action_prob fills the internal array with probabilities of a requested type. The function qsmm_get_actor_choice_sig_prob returns a pointer to array content. The function qsmm_get_actor_choice_sig_prob_vec returns a read-only array view for speeding up accessing array content if it is sparse.

If actor is a large one, qsmm_get_actor_sig_action uses the output signal choice tree of a current action choice state to make a fast choice of an output signal according to probabilities QSMM_PROB_AGGR; for faster operation, you should omit a preceding call to qsmm_actor_calc_action_prob, as qsmm_get_actor_sig_action does not use the aforementioned internal array. The function qsmm_get_actor_sig_ngram returns the pointer to a buffer containing an array of signal identifiers encoding the current action choice state.

The function qsmm_get_actor_sig_action stores a selected output signal in *sig_out_p if sig_out_p is not NULL. The argument rez1 is for future use and must be equal to 0.

The arguments sig_beg and sig_end specify the identifiers of the first signal (inclusive) and last signal (exclusive) of a segment for selecting an output signal. For a small actor, specify the segment as precisely as possible, because the function operates faster when the signal segment is shorter. For a large actor, the signal segment must include all output signals of the actor; see Specifying Output Signal Weights, for how to adaptively select an output signal from various subsets of output signals of a large actor. If sig_end is 0, the function uses the total number of output signals for the identifier of last signal. For a small actor, if at least one relative probability in the internal array within the signal segment is positive infinity, the function selects an output signal as a uniformly distributed random element from a set of all signals (within the signal segment) with relative probabilities equal to positive infinity.

To stochastically select an output signal, the function uses either a random number generator provided via the field rng of qsmm_actor_desc_s structure when creating the actor by the function qsmm_actor_create or an instance of default random number generator allocated automatically if that field was NULL. Call the function qsmm_get_actor_rng to obtain the handle of a random number generator used by an actor, for example, to seed the generator.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • sig_beg is greater than or equal to the identifier of last signal of the signal segment;
  • sig_end is too large;
  • sig_beg is positive for a large actor;
  • sig_end is positive and less than or equal to highest output signal identifier of a large actor.
QSMM_ERR_WEIGHT

For a small actor, the internal array contains (within the signal segment) a negative element or a non-finite element different from positive infinity.

QSMM_ERR_INFIN

For a small actor, the internal array does not contain elements (within the signal segment) equal to positive infinity, but the sum of array elements is positive infinity. For a large actor, the function qsmm_get_actor_sig_action or qsmm_actor_reg_ngram_in called for an associated small actor when traversing an output signal choice tree from its root node to a leaf node reported QSMM_ERR_INFIN. This error can leave a large actor in inconsistent state.

QSMM_ERR_NOCHOICE

For a small actor, the internal array does not contain at least one positive element (within the signal segment). For a large actor, weights of output signals of an associated small actor are unexpectedly zero, or an output signal choice tree does not represent a consistent probability profile.

QSMM_ERR_NGRAM

For a large actor, a buffer returnable by the function qsmm_get_actor_sig_ngram does not contain a valid array of signal identifiers encoding an action choice state. To determine array validity, the function qsmm_get_actor_sig_action checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_CALLBACK

For a large actor, a helper function QSMM_RELPROB_USER1 or QSMM_RELPROB_USER2 for calculating the relative probability of an output signal reported an error by returning NaN. The function qsmm_actor_calc_action_prob called for an associated small actor when traversing an output signal choice tree from its root node to a leaf node calls the helper function. This error can leave a large actor in inconsistent state.

QSMM_ERR_STORAGE

A failure of statistics storage of a large actor. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure. This error can leave a large actor in inconsistent state.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected for a large actor. This error can leave a large actor in inconsistent state.

QSMM_ERR_ILSEQ

For a large actor, a generated error message is not convertible to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ. This error can leave a large actor in inconsistent state.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation by a large actor. This error can leave a large actor in inconsistent state.

Use the following function to register a selected output signal.

Function: int qsmm_actor_reg_sig_out (qsmm_actor_t actor, qsmm_sig_t sig)

This function registers sig as an output signal of actor emitted in a current action choice state. The function qsmm_get_actor_sig_ngram returns the pointer to a buffer containing an array of signal identifiers encoding the current action choice state.

The function records the following information for the action choice state:

  • discrete time of last occurrence of the action choice state in the event history equal to current discrete time tracked by the actor;
  • for every continuous time type, continuous time of last occurrence of the action choice state in the event history equal to current continuous time tracked by the actor;
  • current spur value for every spur type;
  • the output signal emitted in the action choice state.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

Signal sig is greater than or equal to the number of output signals of the actor.

QSMM_ERR_NGRAM

The buffer does not contain a valid array of signal identifiers encoding an action choice state. To determine array validity, the function checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_STORAGE

Statistics storage failure. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

A statistics storage access function generated an error message but could not convert it to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

A statistics storage access function reported out of memory error.

For a small actor, use the following sequence of function calls to adaptively emit an output signal:

int rc;
if ((rc=
     qsmm_actor_calc_action_prob(actor,0,0,NSIG_OUT,QSMM_PROB_LEARNED))<0)
    REPORT_ERROR(rc);
qsmm_sig_t sig_out=QSMM_SIG_INVALID;
if ((rc=qsmm_get_actor_sig_action(actor,0,0,NSIG_OUT,&sig_out))<0)
    REPORT_ERROR(rc);
if ((rc=qsmm_actor_reg_sig_out(actor,sig_out))<0) REPORT_ERROR(rc);

For a large actor, a call to qsmm_actor_calc_action_prob is redundant and decreases performance. The sequence of function calls looks like this:

int rc;
qsmm_sig_t sig_out=QSMM_SIG_INVALID;
if ((rc=qsmm_get_actor_sig_action(actor,0,0,NSIG_OUT,&sig_out))<0)
    REPORT_ERROR(rc);
if ((rc=qsmm_actor_reg_sig_out(actor,sig_out))<0) REPORT_ERROR(rc);

For a small actor, you can override an output signal selected by the function qsmm_get_actor_sig_action or omit calling that function. That is, you can pass to the function qsmm_actor_reg_sig_out an output signal not obtained by qsmm_get_actor_sig_action. This is not possible for a large actor—it is incorrect to omit a call to qsmm_get_actor_sig_action before calling qsmm_actor_reg_sig_out or to pass to the latter function a signal different from a signal returned by a preceding call to qsmm_get_actor_sig_action.

Note: you should not call the functions qsmm_actor_spur_delta (see Incrementing Spur) and qsmm_actor_time_delta (see Incrementing Time) between a call to qsmm_actor_reg_sig_in and a subsequent call to qsmm_actor_reg_sig_action.

In QSMM 1.16 there appeared a function returning the probability of last output signal selected. You can use this function to implement timed emitting output signals, for example, according to the exponential probability distribution.

Function: double qsmm_get_actor_prob_action (qsmm_actor_t actor)

This function returns the probability of last output signal selected by the function qsmm_get_actor_sig_action for an actor. For a small actor, it is a probability corresponding to an element in the internal array with relative probabilities of output signals. For a large actor, it is the probability of a path in an output signal choice tree from its root node to a leaf node for the output signal. A returned value is always in the range 0 to 1 (inclusive). If there was no call to qsmm_get_actor_sig_action yet, qsmm_get_actor_prob_action returns 0.


2.5.3 Incrementing Spur

An actor emits output signals adaptively according to input signals, spur increments, and time increments supplied to it. Spur increments are probabilistic indicators of efficiency of output signal selection. An arbitrary number of emitted output signals might cause an arbitrary number of spur increments followed in arbitrary delays when an actor was emitting other output signals.

An actor supports multiple spur types. See Spur-Driven Behavior, for the definition of spur type. The field nspur of qsmm_actor_desc_s structure passed to the function qsmm_actor_create sets the number of spur types of an actor. The function qsmm_get_actor_nspur returns that number for a created actor. A spur increment is an increment of spur with a particular type.

To a spur type there correspond the following parameters: a type of time for computing spur increment velocity, spur weight, and a way of spur perception. A list of spur types with the aforementioned parameters and rules for performing spur increments specify the spur scheme of an actor.

Use the following function to increment the value of spur with a specific type.

Function: int qsmm_actor_spur_delta (qsmm_actor_t actor, int spur_type, double spur_delta)

This function increments by spur_delta the value of spur with type spur_type an actor is accumulating. Spur types have zero-based indices. The value of spur_delta can be negative.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • spur_type is negative;
  • spur_type is too large;
  • spur_delta is non-finite.
QSMM_ERR_INFIN

An incremented spur value would be infinite.

Use the following function to get the current value of spur with a specific type.

Function: int qsmm_get_actor_spur (qsmm_actor_t actor, int spur_type, double *spur_p)

This function sets *spur_p equal to the current value of spur with type spur_type an actor is accumulating. Spur types have zero-based indices. If spur_p is NULL, the function does not set *spur_p. Otherwise, *spur_p is finite.

On success, the function returns a non-negative value. If spur_type is negative or too large, the function returns negative error code QSMM_ERR_INVAL.


2.5.4 Incrementing Time

An actor tracks discrete time and supports tracking multiple types of continuous time.

In QSMM 1.19, discrete time is normally equal to the number of action choice states registered by the function qsmm_actor_reg_ngram_in. As every call to qsmm_actor_reg_ngram_in precedes a call to the function qsmm_actor_reg_sig_out for registering an emitted output signal, the number of registered action choice states is equal to the number of emitted output signals.

An actor can track continuous time equal to a logical period of time the event history occupies from the beginning. There can be multiple types of continuous time tracked by an actor with various logic behind them. The field ntime of qsmm_actor_desc_s structure passed to the function qsmm_actor_create sets the number of continuous time types of an actor. The function qsmm_get_actor_ntime returns that number for a created actor.

Use the function described below to convey to an actor information about passing a period of continuous time with a specific type. The actor should not receive input signals during this period. If there are input signals to receive, split the period into segments containing no input signals to receive and call the function for each segment in consecutive order. Between the calls, call appropriate API functions to convey input signals to the actor and emit output signals.

Function: int qsmm_actor_time_delta_v2 (qsmm_actor_t actor, int time_type, int rez1, double time_delta)

This function increments by time_delta continuous time with type time_type tracked by an actor. Continuous time types have zero-based indices. The argument rez1 must be 0.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • time_type is negative;
  • time_type is too large;
  • time_delta is non-finite.
QSMM_ERR_INFIN

Incremented continuous time would be infinite.

Use the following function to get the current value of continuous time associated with an actor.

Function: int qsmm_get_actor_time (qsmm_actor_t actor, int time_type, double *time_p)

If time_type is non-negative, this function sets *time_p equal to the current value of continuous time with type time_type tracked by an actor. If time_type is −1, the function returns the current value of discrete time (without fractional part) tracked by the actor. If time_p is NULL, the function does not set *time_p. Otherwise, *time_p is finite.

On success, the function returns a non-negative value. If time_type is less than −1 or too large, the function returns negative error code QSMM_ERR_INVAL.

Use the following functions to get the value of discrete time associated with an actor or set discrete time to an arbitrary value.

Function: long qsmm_get_actor_discrete_time (qsmm_actor_t actor)

This function returns the value of discrete time associated with an actor.

Function: void qsmm_set_actor_discrete_time (qsmm_actor_t actor, long tmd)

This function sets to tmd the value of discrete time associated with an actor.

An actor uses discrete or continuous time to compute spur increment velocity for calculating output signal probabilities. Spur increment velocity is equal to a spur value divided by a time value. As an actor supports multiple spur types and time types, there can be various combinations of a spur type and time type for computing spur increment velocity.

If the field ntime of qsmm_actor_desc_s structure passed to the function qsmm_actor_create was zero, the actor uses discrete time for calculating spur increment velocities. If that field was positive, the actor uses continuous time with type 0 for calculating spur increment velocities by default.

Use the following functions to query or set the type of time for calculating increment velocity of spur with a particular type by an actor.

Function: int qsmm_get_actor_spur_time (qsmm_actor_t actor, int spur_type, int *time_type_p)

If time_type_p is not NULL, this function sets *time_type_p equal to the type of time for calculating increment velocity of spur with type spur_type by an actor. Spur types have zero-based indices. If time_type_p is NULL, the function does not set *time_type_p. If the actor is a large actor, the function retrieves the type of time for a small actor associated with the large actor.

A value returned in *time_type_p can be −1 or non-negative. If *time_type_p is −1, the actor uses discrete time to calculate increment velocity for the spur type. If *time_type_p is non-negative, the actor uses continuous time with type *time_type_p to calculate increment velocity for the spur type.

On success, the function returns a non-negative value. If spur_type is negative or greater than or equal to the number of spur types specified in the field nspur of qsmm_actor_desc_s structure when creating the actor, the function returns negative error code QSMM_ERR_INVAL.

Function: int qsmm_set_actor_spur_time (qsmm_actor_t actor, int spur_type, int time_type)

This function sets to time_type the type of time for calculating increment velocity of spur with type spur_type by an actor. Spur types have zero-based indices. If the actor is a large actor, the function sets the type of time for a small actor associated with the large actor.

If time_type is −1, the actor uses discrete time to calculate increment velocity for the spur type. If time_type is non-negative, the actor uses continuous time with type time_type to calculate increment velocity for the spur type.

On success, the function returns a non-negative value. If spur_type is negative or too large, or time_type is less than −1 or too large, the function returns negative error code QSMM_ERR_INVAL.


2.6 Customizing the Relative Probability Function

The efficiency of operation of a small or large actor, that is, the optimality of output signals an actor adaptively emits, depends on the form of a function returning the relative probability of an output signal. It may well be true that, for different kinds of applications, different functions are more suitable. QSMM provides a few built-in functions a developer may select for use by an actor. Unfortunately, the author of QSMM experiences problems with: (1) providing a sound theoretical basis for using the provided built-in functions in QSMM (the basis might not exist for some functions); (2) devising functions giving better efficiency than the built-in functions currently provided in QSMM. The author’s own experimenting had shown that, for some special cases, there do exist more efficient functions, but he did fail to find general forms for the functions making it possible to utilize them for wider ranges of values of actor parameters. To provide a way to solve the mentioned problems by developers, QSMM starting from version 1.15 supports specifying a custom relative probability function.

The main parameter of a relative probability function is its type. If the type specifies a custom form for the function, the developer shall provide a helper function for this form. Common relative probability function forms depend on the number of output signals and a type of time for computing spur increment velocity, spur weight, and a way of spur perception for every spur type. All relative probability function forms depend on actor temperature.


2.6.1 Relative Probability Function Types

Use the following functions to query or set the type of a relative probability function used by an actor.

Function: enum qsmm_relprob_e qsmm_get_actor_relprob_type (qsmm_actor_t actor)

This function returns the type of a function used by an actor to calculate the relative probability of an output signal. If the actor is the large one, qsmm_get_actor_relprob_type returns the type of a function used by a small actor associated with the large actor.

Function: void qsmm_set_actor_relprob_type (qsmm_actor_t actor, enum qsmm_relprob_e relprob_type)

This function sets to relprob_type the type of a function used by an actor to calculate the relative probability of an output signal. If the actor is the large one, qsmm_set_actor_relprob_type sets the type of a function used by a small actor associated with the large actor. The values of relprob_type not matching to the elements of qsmm_relprob_e enumeration lead to undefined actor behavior.

Below there is a description of an enumeration specifying supported relative probability function types.

Enumeration: qsmm_relprob_e

This enumeration specifies supported types of a function used by an actor to calculate the relative probability of an output signal.

Descriptions of enumeration elements use the following notations.

h

An action choice state.

z

An output signal.

ne

The number of spur types.

nout

The mean number of output signals of the actor (see Number of Output Signals, for more information on computing this number).

T

Actor temperature multiplied by some constant.

L

Mean discrete cycle period—mean discrete time period between every occurrence of action choice state h with emitting output signal z and a subsequent occurrence of h multiplied by a value returned by the function qsmm_get_actor_naction_per_evt. By default, mean discrete cycle period is equal to the mean number of action choice states registered between every occurrence of action choice state h with emitting output signal z and a subsequent occurrence of h.

F(h,z)

The relative probability of emitting output signal z in action choice state h.

W[i]

Spur weight for spur type i.

C(h,z,i)

The ratio of spur increment velocities computed depending on the way of spur perception (see Spur Perception) for spur type i.

The enumeration contains the following elements.

QSMM_RELPROB_BUILTIN1

The relative probability function has the formula

relprob_builtin1.formula

where κ=2L

QSMM_RELPROB_BUILTIN2

The relative probability function has the formula

relprob_builtin2.formula

The author empirically found this formula when developing QSMM 1.15 and making an actor emit output signals with frequencies proportional to output signal probabilities specified a priori. A spur increment supplied to the actor just after emitting an output signal was equal to the logarithm of its probability.

QSMM_RELPROB_BUILTIN3

The relative probability function has the formula

relprob_builtin3.formula

This formula is a simplification of QSMM_RELPROB_BUILTIN2 and is for developers who prefer beauty and/or simplicity.

QSMM_RELPROB_USER1

The relative probability function has the formula

relprob_user1.formula

where f(L) is a function of qsmm_relprob_user1_func_t type provided by a developer via a call to qsmm_set_actor_relprob_helper (see Helper Relative Probability Functions). If the developer has not provided the function f(L), that function is equal to 1 by default.

QSMM_RELPROB_USER2

The relative probability function has the formula

relprob_user2.formula

where g is a function of qsmm_relprob_user2_func_t type provided by a developer via a call to qsmm_set_actor_relprob_helper (see Helper Relative Probability Functions). The function g receives the value of z and statistics associated with h and z. The arguments of g make it possible to devise a sophisticated relative probability function.

When creating a small actor, the function qsmm_actor_create initializes the type of relative probability function of the small actor to QSMM_RELPROB_BUILTIN1. When creating a large actor, qsmm_actor_create initializes the type of relative probability function of a small actor associated with the large actor to QSMM_RELPROB_BUILTIN3.


2.6.2 Helper Relative Probability Functions

Below there are descriptions of types for functions f(L) and g.

Data type: qsmm_relprob_user1_func_t

This is a type for the pointer to a helper function provided by the developer for relative probability function type QSMM_RELPROB_USER1. The following declaration corresponds to the type:

typedef double
(*qsmm_relprob_user1_func_t)(
    qsmm_actor_t actor,
    double cycle_period,
    void *paramp
);

The argument actor specifies an actor calling the helper function. The argument cycle_period holds the value of L. The argument paramp is a user parameter specified when setting the helper function for the actor.

On success, the helper function should return the value of f(L). On failure, the helper function should return NaN; in this case, the function qsmm_actor_calc_action_prob returns QSMM_ERR_CALLBACK.

Data type: qsmm_relprob_user2_func_t

This is a type for the pointer to a helper function provided by the developer for relative probability function type QSMM_RELPROB_USER2. The following declaration corresponds to the type:

typedef double
(*qsmm_relprob_user2_func_t)(
    qsmm_actor_t actor,
    qsmm_sig_t sig_cycle,
    const struct qsmm_state_s *state_p,
    const struct qsmm_cycle_s *cycle_p,
    const struct qsmm_sspval_s *sspval_p,
    const struct qsmm_cspval_s *cspval_p,
    void *paramp
);

The argument actor specifies an actor calling the helper function. The argument sig_cycle holds the value of z. The arguments state_p, cycle_p, sspval_p, and cspval_p hold statistics associated with h and z. See Structures for Accessing Storage, for descriptions of corresponding structures. The arguments sspval_p and cspval_p are arrays with the number of elements equal to qsmm_get_actor_nspur(actor)+qsmm_get_actor_ntime(actor). The argument paramp is a user parameter specified when setting the helper function for the actor.

On success, the helper function should return the value of g. On failure, the helper function should return NaN; in this case, the function qsmm_actor_calc_action_prob returns QSMM_ERR_CALLBACK.

To obtain working parameters of an actor, you may call such functions as qsmm_get_actor_nsig_ctrl and qsmm_get_actor_discrete_cycle_period_mean in a helper function. Call the function qsmm_get_actor_sig_ngram to obtain an array of signal identifiers encoding action choice state h if you need to access application-specific information associated with h.

Use the following functions to retrieve or set a helper function for an actor.

Function: void qsmm_get_actor_relprob_helper (qsmm_actor_t actor, void **helper_func_pp, void **helper_func_param_pp)

This function retrieves information on a helper function used by an actor when calculating relative probabilities of output signals. If there is such helper function set for the actor, and helper_func_pp is not NULL, qsmm_get_actor_relprob_helper sets *helper_func_pp equal to the pointer to the helper function. If there is no such helper function set for the actor, and helper_func_pp is not NULL, qsmm_get_actor_relprob_helper sets *helper_func_pp to NULL. If helper_func_param_pp is not NULL, this function sets *helper_func_param_pp equal to the user parameter of the helper function specified when setting it for the actor. If the actor is the large one, qsmm_get_actor_relprob_helper retrieves information on a helper function used by a small actor associated with the large actor. A particular interpretation of a pointer stored in *helper_func_pp depends on a relative probability function type set for the actor by a call to the function qsmm_set_actor_relprob_type.

Function: void qsmm_set_actor_relprob_helper (qsmm_actor_t actor, void *helper_func_p, void *helper_func_param_p)

This function sets the pointer to a helper function used by an actor when calculating relative probabilities of output signals. The argument helper_func_p specifies that pointer. Additionally, qsmm_set_actor_relprob_helper sets the user parameter of the helper function to helper_func_param_p. If the actor is the large one, qsmm_set_actor_relprob_helper sets the helper function for a small actor associated with the large actor.

A particular interpretation of a helper_func_p pointer depends on a relative probability function type set for the actor by a call to the function qsmm_set_actor_relprob_type. Passing a pointer that does not conform with the relative probability function type leads to undefined behavior.

The value of helper_func_p can be NULL. This NULL value means the absence of a helper function for the actor. Setting the NULL value makes a certain sense when the relative probability function type is QSMM_RELPROB_USER1.

To provide an example of using the functions qsmm_set_actor_relprob_type and qsmm_set_actor_relprob_helper, let us suppose a developer has proved that it is mathematically correct to use a function for calculating the relative probability of an output signal similar to the function QSMM_RELPROB_BUILTIN2 but with the following one difference: the numerator of the exponent contains the expression L instead of L+1. To make an actor calculate the relative probability of an output signal by this function, the developer may define the helper function as:

#include <math.h>

static double
get_relprob_exp_mlt(
    qsmm_actor_t actor,
    double cycle_period,
    void *paramp
) {
    return log(qsmm_get_actor_nsig_ctrl(actor))*cycle_period/2;
}

To set this helper function for an actor, the developer may add the function calls:

qsmm_set_actor_relprob_type(actor,QSMM_RELPROB_USER1);
qsmm_set_actor_relprob_helper(actor,&get_relprob_exp_mlt,0);

Alternatively, the developer may add the function calls shown below. See Actor Temperature, for a description of qsmm_set_actor_ktemperature function.

qsmm_set_actor_relprob_type(actor,QSMM_RELPROB_BUILTIN3);
qsmm_set_actor_ktemperature(actor,2);

2.6.3 Spur Weight

Use the following functions to query or set spur weight denoted by W[i] in relative probability function formulas mentioned in Relative Probability Function Types.

Function: int qsmm_get_actor_spur_weight (qsmm_actor_t actor, int spur_type, double *weight_p)
Function: int qsmm_set_actor_spur_weight (qsmm_actor_t actor, int spur_type, double weight)

If weight_p is not NULL, qsmm_get_actor_spur_weight sets *weight_p equal to weight for a spur_type of an actor. The value of *weight_p obtained in this way is always finite. The function qsmm_set_actor_spur_weight sets weight for a spur_type of an actor to weight. Spur types have zero-based indices. If the actor is the large one, the functions query or set weight for a spur_type of a small actor associated with the large actor.

On success, the functions return a non-negative value. If weight is not finite (applicable only to qsmm_set_actor_spur_weight), or spur_type is negative or greater than or equal to the number of spur types specified in the field nspur of qsmm_actor_desc_s structure when creating the actor, the functions return negative error code QSMM_ERR_INVAL.

On creating a small actor, the function qsmm_actor_create initializes weights for all spur types of the small actor to 1. On creating a large actor, qsmm_actor_create initializes weights for all spur types of an associated small actor to 1 divided by the number of spur types specified in the field nspur of qsmm_actor_desc_s structure passed to qsmm_actor_create.


2.6.4 Spur Perception

Most of relative probability function formulas in Relative Probability Function Types contain the function C(h,z,i) equal to ratio between spur increment velocity and mean spur increment velocity. The method of computing C(h,z,i) depends on the way of spur perception for spur type i. The way of spur perception determines whether the ratio will be generally positive or negative for generally positive or negative spur increments supplied to the actor. There are two ways of spur perception: normal and inverse. The normal way of spur perception provides generally positive ratio for generally positive spur increments and generally negative ratio for generally negative spur increments. The inverse way of spur perception provides generally negative ratio for generally positive spur increments and generally positive ratio for generally negative spur increments.

The following enumeration specifies the way of perception of spur of a particular type.

Enumeration: qsmm_spur_perception_e

This enumeration specifies the way of spur perception for a spur type.

Below there are notations used in descriptions of enumeration elements. In descriptions of notations, a cycle of type <h,z> is the event history segment between an occurrence of action choice state h with emitting output signal z and a subsequent occurrence of h.

t[i]

Discrete time or continuous time with a particular type for spur type i.

E[i]

The value of spur of i type.

H(h,z)[i]

The sum of increments of spur of i type over cycles of <h,z> type.

ω(h,z)[i] 

The sum of cycle periods for cycles of <h,z> type in discrete time or continuous time with a particular type for spur type i.

The enumeration contains the following elements.

QSMM_SPUR_PERCEPTION_NORMAL

The value of C(h,z,i) is the ratio of spur increment velocity to the absolute value of mean spur increment velocity for a cycle type:

percept_normal.formula

When spur increments over the event history are non-negative, C(h,z,i) increases as spur increment velocity increases. If spur increment velocity for a cycle type is positive and equal to mean spur increment velocity, C(h,z,i) is equal to 1.

QSMM_SPUR_PERCEPTION_INVERSE

The value of C(h,z,i) is the negative ratio of the absolute value of mean spur increment velocity to spur increment velocity for a cycle type:

percept_inverse.formula

When spur increments over the event history are negative, C(h,z,i) increases as spur increment velocity increases. If spur increment velocity for a cycle type is negative and equal to mean spur increment velocity, C(h,z,i) is equal to 1.

The function qsmm_set_actor_spur_time selects discrete time or continuous time with a particular type for computing increment velocity of spur with a specific type. A time type selected for spur type i affects values t[i] and ω(h,z)[i].

Use the following functions to query or set the way of spur perception for a spur type.

Function: int qsmm_get_actor_spur_perception (qsmm_actor_t actor, int spur_type, enum qsmm_spur_perception_e *spur_perception_p)
Function: int qsmm_set_actor_spur_perception (qsmm_actor_t actor, int spur_type, enum qsmm_spur_perception_e spur_perception)

If spur_perception_p is not NULL, the function qsmm_get_actor_spur_perception sets *spur_perception_p equal to the way of spur perception for a spur_type by an actor. The function qsmm_set_actor_spur_perception sets to spur_perception the way of spur perception for a spur_type by an actor. The values of spur_perception not matching to the elements of qsmm_spur_perception_e enumeration lead to undefined actor behavior.

Spur types have zero-based indices. If the actor is the large one, the functions query or set the way of spur perception for a spur_type of a small actor associated with the large actor.

On success, the functions return a non-negative value. If spur_type is negative or greater than or equal to the number of spur types specified in the field nspur of qsmm_actor_desc_s structure when creating the actor, the functions return negative error code QSMM_ERR_INVAL.

The function qsmm_actor_create initializes the way of spur perception for all spur types of a newly created actor to QSMM_SPUR_PERCEPTION_NORMAL.


2.6.5 Number of Output Signals

Use the following function to get the number of output signals of an actor.

Function: qsmm_sig_t qsmm_get_actor_nsig_out (qsmm_actor_t actor)

This function returns the number of output signals of an actor. That number is either the number of output signals specified in the field nsig_out of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor, or the number of output signals previously set by the function qsmm_set_actor_nsig_out.

Since QSMM 1.19, actors support increasing the number of output signals. Use the following function to increase the number of output signals of an actor after creating it.

Function: int qsmm_set_actor_nsig_out (qsmm_actor_t actor, qsmm_sig_t nsig_out)

This function increases the number of output signals of an actor and makes that number equal to nsig_out. For a large actor, this operation is possible when the actor has not created a default output signal choice tree yet. A large actor creates a default output signal choice tree when:

  • generating an output signal for an action choice state with unset probability profile by the function qsmm_get_actor_sig_action;
  • calculating probabilities of output signals for an action choice state with unset probability profile by the function qsmm_actor_calc_action_prob;
  • obtaining the node of a default output signal choice tree by calling the function qsmm_get_actor_large_osct_node for probabilities list index (size_t) -1.

For a small actor, qsmm_set_actor_nsig_out sets weights of added output signals to 1.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument nsig_out is less than the current number of output signals returned by the function qsmm_get_actor_nsig_out or greater than QSMM_SIG_MAX+1.

QSMM_ERR_UNTIMELY

The actor is the large one, and it has created a default output signal choice tree.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

A function returning the relative probability of an output signal typically uses a parameter equal to the number of output signals of an actor to perform the calculation. The function qsmm_actor_create creates an actor with a particular number of output signals increasable by the function qsmm_set_actor_nsig_out. The function qsmm_set_actor_sig_weight can change output signal weights for a small actor, or the function qsmm_set_actor_ngram_profile can assign preloaded probability profiles to action choice states, and output signal weights may define a lesser number of output signals. For example, if the actor had four output signals, and qsmm_set_actor_sig_weight has set the weight of one of them to zero, the nominal number of output signals is three. The same applies to a probability profile for an action choice state (set in the statistics storage of a small actor or by qsmm_set_actor_ngram_profile for a large actor): if the profile probability of an output signal is zero, the nominal number of output signals is less than the number of output signals defined when creating the actor.

However, the concept of the nominal number of output signals is weak. The weakness shows up when positive weights (or profile probabilities) of output signals are different. In this case, the nominal number of output signals might not be simply the number of output signals with positive weights (or profile probabilities). For example, if four signals have weights <0.33, 0.33, 0.33, 0.01>, the nominal number of output signals is rather three than four.

Large actors can avoid the weak concept of the nominal number of output signals if large actors use output signal choice trees with arity 2. In this case, small actors associated with the large actors use equal profile probabilities of output signals. In QSMM 1.19, the developer can create a large actor with setting the new field profile_tol of qsmm_actor_large_desc_s structure to a positive value for rearranging a Huffman tree generated for a list of output signal weights (e.g. specified for an action choice state by qsmm_set_actor_ngram_profile) to achieve a desired precision of output signal weights following from tree structure.

Tip: when specifying custom output signal weights, use a large actor with tree arity 2 instead of a small actor to make actor’s behavior well defined.

When using a small actor and loading an assembler program into a node or changing values of controlled probability variables of a node, QSMM uses the following algorithm for approximate calculation of the nominal number of output signals for a list of weights:

  1. Zero c, the resulting nominal number of output signals.
  2. Calculate a, the arithmetic mean of all positive weights of output signals.
  3. For every output signal weight b, if b>a, then add 1 to c, otherwise add b/a to c.

Different action choice states in the event history can have different nominal numbers of output signals. If a function returning the relative probability of an output signal depends on the number of output signals, the function can use the mean nominal number of output signals for this parameter. An actor can compute the mean nominal number of output signals based on nominal numbers of output signals calculated for profile probabilities of output signals of action choice states occurring in the event history. The mean nominal number of output signals might be the arithmetic or geometric mean of nominal numbers of output signals. The concept of the mean nominal number of output signals is weaker than the concept of the nominal number of output signals.

You can retrieve or set the mean nominal number of output signals by the following functions.

Function: double qsmm_get_actor_nsig_ctrl (qsmm_actor_t actor)

This function returns the mean nominal number of output signals of an actor. That number is either the number of output signals specified in the field nsig_out of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor, or the number of output signals previously set by the function qsmm_set_actor_nsig_ctrl. You can call qsmm_get_actor_nsig_ctrl from a helper function for computing the relative probability of an output signal if the helper function depends on the number of output signals. A value returned by qsmm_get_actor_nsig_ctrl is always finite and greater than or equal to 2.

Function: int qsmm_set_actor_nsig_ctrl (qsmm_actor_t actor, double val)

This function sets the mean nominal number of output signals of an actor to val. Built-in functions returning the relative probability of an output signal use that number. A helper function for computing the relative probability of an output signal provided by the developer can also use that number.

On success, the function returns a non-negative value. If val is not a finite number or is a number less than 2, the function returns negative error code QSMM_ERR_INVAL.


2.6.6 Actor Temperature

In all relative probability function formulas mentioned in Relative Probability Function Types, T denotes actor temperature multiplied by some constant. Actor temperature is a concept following from the use of exponential forms for the relative probability function resembling formulas related to the Boltzmann distribution. In most relative probability function formulas, actor temperature is a divisor of every spur weight.

The perfect relative probability function is the one that makes it possible for an actor to produce the most optimal behavior without the need to tune up actor temperature by hand. That is, you would always use default temperature equal to 1 for the function. If a relative probability function is imperfect, its application is not intended one, or when applying the simulated annealing approach for solving a problem, use the following API functions to adjust the temperature of an actor for producing more optimal behavior.

Function: double qsmm_get_actor_ktemperature (qsmm_actor_t actor)

This function returns the temperature (multiplied by some constant) of an actor. If the actor is the large one, the function returns the temperature of a small actor associated with the large actor. A returned value is always finite and positive.

Function: int qsmm_set_actor_ktemperature (qsmm_actor_t actor, double val)

This function sets the temperature (multiplied by some constant) of an actor to val. If the actor is the large one, the function sets the temperature of a small actor associated with the large actor.

On success, the function returns a non-negative value. If val is not a finite or positive number, the function returns negative error code QSMM_ERR_INVAL.

The function qsmm_actor_create initializes the temperature (multiplied by some constant) of a newly created actor to 1.


2.7 Specifying Output Signal Weights

The weight of an output signal of an actor is a coefficient for multiplying the probability of selecting the output signal by the actor. The coefficient is a hint—it increases or decreases that probability. To disable emitting an output signal, set its weight equal to 0.

In the simplest case, an actor uses the weight of an output signal when selecting the output signal in all action choice states. On binding the weight to a specific action choice state, the actor uses that weight when selecting the output signal in the action choice state only.

Large actors do not support setting the weight of an output signal for all action choice states at once. However, all actors support binding output signal weights to specific action choice states.

A preloaded probability profile is a list of output signal weights loaded into an actor. You can assign a preloaded probability profile to specific action choice states for setting their output signal weights.

For a small actor, you can also bind output signal weights to an action choice state by specifying a probability profile for the action choice state held in statistics storage of the small actor. See Structures for Accessing Storage, for how to pass profile probabilities to storage access functions to write them to statistics storage.

It is essential to note that by reasons described in Number of Output Signals, changing default weights of output signals of a small actor makes its behavior ill-defined in general. Therefore, you should avoid doing this. Changing the weights seems to be a correct procedure for a large actor only, because the procedure does not alter the number of choice alternatives at decision points along the pathways to output signals.


2.7.1 Setting a Weight for an Output Signal

Small actors support setting the weight of an output signal for all possible action choice states at once. The functions qsmm_get_actor_sig_weight and qsmm_set_actor_sig_weight described below make it possible to inspect or modify the array of output signal weights of a small actor. A large actor does not support setting the weight of an output signal for all possible action choice states at once and does not use that array.

The function qsmm_actor_create initializes to 1 weights of all output signals of a newly created small actor in the array. The function qsmm_set_actor_nsig_out initializes to 1 weights of output signals added to a small actor. If an output signal of a small actor has a profile probability specified for an action choice state in statistics storage, the overall output signal weight is the product of a corresponding weight in the array and the profile probability.

The function qsmm_actor_calc_action_prob applies weights contained in the array to computed relative probabilities regardless of a requested type of probabilities to calculate. After multiplying computed relative probabilities by corresponding weights, qsmm_actor_calc_action_prob normalizes a resulting array to obtain probabilities that sum up to 1.

Function: int qsmm_get_actor_sig_weight (qsmm_actor_t actor, qsmm_sig_t sig, double *weight_p)

This function sets *weight_p to the weight of output signal sig of an actor. If weight_p is NULL, the function does not set *weight_p. Otherwise, *weight_p is a finite and non-negative number.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

Signal sig is not an output signal of the actor.

QSMM_ERR_NOTSUP

The actor is the large one.

Function: int qsmm_set_actor_sig_weight (qsmm_actor_t actor, qsmm_sig_t sig, double weight)

This function sets the weight of output signal sig of an actor to weight.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

Signal sig is not an output signal of the actor, or weight is not a finite number or is a negative number.

QSMM_ERR_NOTSUP

The actor is the large one.


2.7.2 Preloading a Probability Profile

A list of probabilities in normal form and a one-to-one correspondence between the elements of the list and identifiers of output signals define a preloaded probability profile for an action choice state. The one-to-one correspondence is a permutation of output signals. Output signals that do not take part in the permutation have profile probability 0. The purpose of splitting a preloaded probability profile into a probabilities list in normal form and a permutation of output signals is to reduce memory footprint of an actor, especially of large one.

For a small actor, the normal form of a list of probabilities is a sorted list of positive probabilities. For a large actor, the normal form of a source list of probabilities is a resulting list of probabilities following from the structure of an output signal choice tree created for a sorted source list. Resulting probabilities following from the structure of an output signal choice tree may differ from source probabilities for creating the output signal choice tree.

If the field profile_tol of qsmm_actor_large_desc_s structure specified when creating a large actor is positive, an extra normal form of a list of probabilities is a sorted list of positive probabilities. Using the extra normal form makes it possible to skip building and restructuring a Huffman tree for the same sorted list of positive probabilities, as this operation can be slow.

An actor has a pool of unique probabilities lists in normal form. The actor does not support removing elements from the pool, except by destroying the actor using the function qsmm_actor_destroy. The following function returns current pool size.

Function: size_t qsmm_get_actor_profile_pool_sz (qsmm_actor_t actor)

This function returns the number of elements in the pool of probabilities lists in normal form of actor. Every element is a unique list of probabilities in normal form.

An actor has also a pool of permutations of output signals. The pool contains unique permutations. The actor does not support removing permutations of output signals from the pool, except by destroying the actor using qsmm_actor_destroy.

Use the following function to split a list of weights of output signals of an actor into a probabilities list in normal form and a permutation of output signals.

Function: int qsmm_actor_profile_add_v2 (qsmm_actor_t actor, int rez1, qsmm_sig_t sig_beg, qsmm_sig_t sig_end, const double *weight_p, size_t *profile_p, size_t *permut_p)

This function preloads a list of weights of output signals into an actor. The array weight_p contains the weights. If weight_p is NULL, the function interprets this condition as if the array weight_p contains all weights equal to 1.

The arguments sig_beg and sig_end specify the identifiers of the first output signal (inclusive) and last output signal (exclusive) for the list of weights. The array weight_p begins with the weight of the first output signal and has length sig_end-sig_beg.

For a large actor, if the field profile_tol of qsmm_actor_large_desc_s structure passed when creating the large actor was positive, the function first looks for an extra probabilities list in normal form containing normalized and sorted positive weights to speed up processing the same normalized and sorted list of positive weights. If the extra probabilities list in normal form exists, the function returns its index in *profile_p if it is not NULL. If the extra probabilities list does not exist, the function adds it to the pool and continues working with a main probabilities list in normal form following from the structure of a rearranged Huffman tree.

If profile_p is not NULL, the function sets *profile_p equal to the index of a unique probabilities list in normal form for the list of weights. The index identifies either a unique probabilities list in normal form just added to the pool of probabilities lists in normal form or such a list already contained in the pool. The length of the unique probabilities list in normal form is equal to the number of positive elements in the array weight_p.

If permut_p is not NULL, the function sets *permut_p equal to the index of a unique permutation of output signals for the list of weights. The index identifies either a unique permutation of output signals just added to the pool of permutations of output signals or such a permutation already contained in the pool. The length of the unique permutation of output signals is equal to the length of the unique probabilities list in normal form.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument sig_beg is greater than or equal to the argument sig_end, or sig_end is greater than the number of input signals and greater than the number of output signals.

QSMM_ERR_WEIGHT

The array weight_p contains a negative or non-finite element.

QSMM_ERR_INFIN

The array weight_p contains only finite elements, but the sum of elements is infinite.

QSMM_ERR_NOCHOICE

The array weight_p does not contain at least one positive element.

QSMM_ERR_STORAGE

Failure of statistics storage of a large actor. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected for a large actor.

QSMM_ERR_ILSEQ

For a large actor, a generated error message is not convertible to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Since QSMM 1.19, large actors support the following function for obtaining a model node containing an output signal choice tree for a probabilities list in normal form. See the program tools/osct.c (see osct) for an example on how to print an output signal choice tree created for a supplied list of weights.

Function: int qsmm_get_actor_large_osct_node (qsmm_actor_t actor, size_t profile, qsmm_sig_t *node_p)

This function sets *node_p equal to the index of a node in a multinode model of a large actor containing an output signal choice tree for a probabilities list in normal form identified by profile. If node_p is NULL, the function does not set the node index.

The function qsmm_get_actor_large_model returns the handle of the multinode model. The argument profile can be equal to the index of a probabilities list in normal form returned by the function qsmm_actor_profile_add_v2. If profile is equal to special value (size_t) -1, it identifies a default probabilities list in normal form containing equal probabilities for all output signals of the large actor. In this case, qsmm_get_actor_large_osct_node returns the index of a node containing a default output signal choice tree. If the default tree does not yet exist, the function creates it.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument profile is not (size_t) -1 but greater than or equal to the number of unique probabilities lists in normal form returnable by the function qsmm_get_actor_profile_pool_sz.

QSMM_ERR_NOTSUP

The actor is the small one.

QSMM_ERR_STORAGE

Statistics storage failure. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

A generated error message is not convertible to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The function qsmm_actor_profile_add_v2 may operate slowly, especially when building an output signal choice tree for a large actor. To speed up preloading a number of probability profiles for the same sorted list of output signal weights, you can perform the following procedure.

  1. Preload the first probability profile by the function qsmm_actor_profile_add_v2 returning the index of a probabilities list in normal form and the index of a permutation of output signals identifying the preloaded profile.
  2. For every other probability profile, sort its list of output signal weights (all profiles have the same sorted list, as stated above) to obtain a permutation of output signals. Actually, it is necessary to sort a list of pairs comprised of a weight and output signal identifier in ascending order of weights.
  3. Register every such permutation of output signals by the function qsmm_actor_permut_add_v2 described below to obtain the index of a unique permutation of output signals. You can use that index along with the index of a probabilities list in normal form obtained in step 1 to identify a preloaded probability profile other than the first one.
Function: int qsmm_actor_permut_add_v2 (qsmm_actor_t actor, int rez1, qsmm_sig_t sz, const qsmm_sig_t *sig_p, size_t *permut_p)

This function adds a permutation of output signals of an actor to its pool of permutations of output signals if the pool does not contain the permutation. The array sig_p containing sz elements specifies the permutation. If permut_p is not NULL, the function returns in *permut_p the index of an added permutation or a permutation already existing in the pool.

On success, the function returns a non-negative value. If the pool did not contain the permutation, the function returns a positive value. If the pool already contained the permutation, the function returns 0. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument sz is 0, or the array sig_p contains duplicate elements or an element greater than or equal to the number of output signals of the actor.

QSMM_ERR_NOMEM

There was not enough memory to add the permutation of output signals to the pool.


2.7.3 Assigning a Preloaded Probability Profile

You can assign a preloaded probability profile to a number of action choice states. Output signals emittable in the action choice states will have weights defined by the preloaded probability profile.

If a current action choice state is an action choice state with the preloaded probability profile assigned, the function qsmm_actor_calc_action_prob called for a small actor applies the weights by copying them from the preloaded probability profile to the array of output signal weights accessible by the functions qsmm_get_actor_sig_weight and qsmm_set_actor_sig_weight.

For a large actor, the function qsmm_get_actor_sig_action uses an output signal choice tree defined by the preloaded probability profile to select an output signal in an action choice state with the preloaded probability profile assigned.

The purpose of the following functions is to retrieve or set up a correspondence between an action choice state and a preloaded probability profile.

Function: int qsmm_get_actor_ngram_profile (qsmm_actor_t actor, unsigned int flags, size_t *profile_p, size_t *permut_p, const qsmm_sig_t *sig_ngram_p)

This function retrieves a correspondence between an action choice state of an actor and a preloaded probability profile. A probabilities list in normal form and a permutation of output signals define the preloaded probability profile. The array sig_ngram_p with length specified in the field ngram_sz of qsmm_actor_desc_s structure when creating the actor encodes the action choice state. The argument flags must be equal to QSMM_MODE_2.

If profile_p is not NULL, the function sets *profile_p equal to the index of a probabilities list in normal form for the preloaded probability profile. If permut_p is not NULL, the function sets *permut_p equal to the index of a permutation of output signals for the preloaded probability profile. If the function sets *profile_p and *permut_p equal to (size_t) -1, this means that the action choice state has default output signal weights. For a small actor, default output signal weights are all equal. For a large actor, default output signal weights following from the structure of a default output signal choice tree are equal if the number of output signals is a positive integer power of tree arity.

On success, the function returns a non-negative value. If the array sig_ngram_p does not contain a valid array of signal identifiers encoding an action choice state, the function returns negative error code QSMM_ERR_NGRAM.

Function: int qsmm_set_actor_ngram_profile (qsmm_actor_t actor, int rez1, size_t profile, size_t permut, const qsmm_sig_t *sig_ngram_p)

This function sets up a correspondence between an action choice state of an actor and a preloaded probability profile. A probabilities list in normal form and a permutation of output signals define the preloaded probability profile. The argument profile specifies the index of the probabilities list in normal form. The argument permut specifies the index of the permutation of output signals. The array sig_ngram_p with length specified in the field ngram_sz of qsmm_actor_desc_s structure when creating the actor encodes the action choice state. The argument rez1 is for future use and must be equal to 0.

A special combination of profile and permut both equal to (size_t) -1 is the indication to assign default output signal weights to the action choice state. For a small actor, default output signal weights are all equal. For a large actor, default output signal weights following from the structure of a default output signal choice tree are equal if the number of output signals is a positive integer power of tree arity.

The function keeps intact statistics collected for the action choice state and held in statistics storage with a handle retrievable by the function qsmm_get_actor_storage for the actor. However, for a large actor, the function qsmm_set_actor_ngram_profile destroys the old output signal choice tree of the action choice state. The output signal choice tree holds the other part of statistics collected for the action choice state.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument profile is not a valid index of a probabilities list in normal form, or the argument permut is not a valid index of a permutation of output signals, and, at the same time, profile and permut are not both equal to (size_t) -1, or the length of a probabilities list in normal form specified by profile is not equal to the length of a permutation of output signals specified by permut.

QSMM_ERR_NGRAM

The array sig_ngram_p is not a valid array of signal identifiers encoding an action choice state. To determine array validity, the function checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_STORAGE

Statistics storage failure. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

A generated error message is not convertible to a wide string according to a current locale, or a storage redirection function reported QSMM_ERR_ILSEQ.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation. This error can leave a large actor in inconsistent state. If after removing a reason of this error a repeated call to this function succeeds, the actor’s state becomes consistent.


2.8 Automatic Spur

Automatic spur is a means for implementing the idea that an intrinsic feature of an intelligent system is adherence to the principle of minimum energy (or maximum probability). The use of automatic spur may substantially increase the optimality of output signals an actor emits. The automatic spur also makes it possible to use an actor in cases when it does not receive explicit spur increments.

Automatic spur can be useful when an actor models a finite automaton. In this case, the output signals of the actor represent the states of the finite automaton, and each action choice state is a superposition of a previous finite automaton state and an input signal received when the finite automaton was in the previous state. The automatic spur is a measure of adequacy of a model of finite automaton states to a sequence of input signals received.

In QSMM, a common approach to building a model of internal states of an entity to solve a problem is the use of a spur scheme with two spur types for inhibitory (negative) spur and excitatory (positive) spur countervailing each other. The inhibitory spur is the automatic spur with normal way of perception. The excitatory spur is specific to the problem.

If an actor uses automatic spur, it is equal to the sum of automatic spur increments calculated by the function qsmm_actor_reg_ngram_in for action choice states that have prior occurrences in the event history. For such an action choice state, qsmm_actor_reg_ngram_in knows an output signal emitted at the previous occurrence of the action choice state. Note that for the last occurrence, an output signal emitted in the action choice state is not yet known in qsmm_actor_reg_ngram_in.

The actor calculates an automatic spur increment for a pair representing the logical consequence h → z and consisting of an action choice state h and an output signal z emitted in the action choice state. The automatic spur increment is equal to the natural logarithm of the observed probability of occurrence of the pair in the event history:

auto_spur_incr.formula

This formula uses the following notations:

v(h,z)

The number of occurrences of the pair in the event history.

t0

The discrete time of the previous occurrence of the pair in the event history. The function qsmm_actor_reg_sig_out records that time.

If an actor uses a single spur type, and it corresponds to automatic spur, it is better to set the type of a relative probability function for the actor to QSMM_RELPROB_BUILTIN2 or QSMM_RELPROB_BUILTIN3. It is also better to use automatic spur in conjunction with the other countervailing spur that evaluates progress in solving a problem in some other way.

Use functions described below to query or set a spur type for automatic spur. By default, an actor created by the function qsmm_actor_create does not use automatic spur.

Function: int qsmm_get_actor_auto_spur_type (qsmm_actor_t actor)

This function returns non-negative index of a spur type for automatic spur used by an actor or negative error code QSMM_ERR_NOTFOUND if the actor does not use automatic spur.

Function: int qsmm_set_actor_auto_spur_type (qsmm_actor_t actor, int spur_type)

This function sets to spur_type the spur type for automatic spur of an actor. Spur types have zero-based indices. If spur_type is equal to −1, the actor does not use the automatic spur; this condition does not affect the use of automatic spur by a small actor associated with the large actor.

On success, the function returns a non-negative value. If spur_type is less than −1 or is greater than or equal to the number of spur types specified in the field nspur of qsmm_actor_desc_s structure when creating the actor, the function returns negative error code QSMM_ERR_INVAL.

A small actor can use at most one spur type for automatic spur. The functions qsmm_get_actor_auto_spur_type and qsmm_set_actor_auto_spur_type called for a small actor query and set the index of a spur type for the automatic spur.

A large actor can use at most two spur types for automatic spur. A small actor associated with a large actor can use the aforementioned automatic spur—increment it for action choice states occurring in the event history of the small actor. The action choice states represent nodes of output signal choice trees traversed to generate output signals by the large actor. A large actor itself can use another automatic spur—increment it for action choice states occurring in the event history of the large actor. The functions qsmm_get_actor_auto_spur_type and qsmm_set_actor_auto_spur_type called for a large actor query and set the index of a spur type for the latter automatic spur.


2.9 Switching Adaptive or Random Behavior

An actor uses a random number generator to select a signal from a set of possible signals according to their relative probabilities. The function qsmm_get_actor_sig_action performs this selection. An actor does not use a random number generator if there is only one signal with a positive relative probability—the actor simply selects the signal.

For a small actor, qsmm_get_actor_sig_action selects an output signal based on probabilities of output signals previously calculated by the function qsmm_actor_calc_action_prob. When selecting an output signal of a large actor, qsmm_get_actor_sig_action indirectly calls itself a number of times for a small actor associated with the large actor to traverse output signal choice tree of a current action choice state for selecting an output signal corresponding to one of tree leaves.

You can obtain a random number generator used by an actor—either provided when creating the actor or an instance of a default random number generator allocated automatically.

Function: qsmm_rng_t qsmm_get_actor_rng (qsmm_actor_t actor)

This function returns a random number generator used by an actor to select output signals. The function never returns NULL.

You typically use a returned random number generator to seed the generator after creating an actor. See Random Number Generators, for how to seed a random number generator and perform other operations on it.

A useful approach to determine the amount of contribution of an actor to the optimality of behavior of a system is comparing optimality measure for the system with the actor behaving adaptively versus optimality measure for the system with the actor behaving randomly. The greater the difference is between the values the more contribution the actor makes to the overall optimality of system behavior.

Use the following functions to query current mode of behavior of an actor and to switch an actor to random or adaptive (normal) behavior mode.

Function: int qsmm_get_actor_random (qsmm_actor_t actor)

This function returns a positive value if an actor is currently in random behavior mode or 0 if the actor is in adaptive (normal) behavior mode. The function never returns negative values.

Function: void qsmm_set_actor_random (qsmm_actor_t actor, int flag)

This function switches current mode of behavior of an actor to random or adaptive (normal) mode. If flag is non-zero, the function switches the current mode to random mode. If flag is zero, the function switches the current mode to adaptive mode.

For a small actor, random and adaptive behavior modes affect how the function qsmm_actor_calc_action_prob calculates probabilities with the type QSMM_PROB_AGGR or QSMM_PROB_LEARNED.

In random mode, qsmm_actor_calc_action_prob called for a small actor does not calculate relative probabilities of output signals in the normal way but uses output signal weights for the relative probabilities. If the type of probabilities to calculate is QSMM_PROB_AGGR, qsmm_actor_calc_action_prob additionally applies a probability profile to the weights if it exists in statistics storage for a current action choice state. Finally, the function normalizes resulting values.

For a large actor, random and adaptive behavior modes are actually behavior modes of a small actor associated with the large actor.

The function qsmm_actor_create initializes current mode of behavior of a newly created actor to adaptive (normal) mode.


2.10 Revising Action Choice States

Revising action choice states means enumerating or removing them. You may need to enumerate action choice states of an actor to clear or update statistics on them. The following function enumerates action choice states that have the pieces of information stored in actor’s memory.

Function: int qsmm_actor_enum_ngrams_v2 (qsmm_actor_t actor, int ngram_lower_sz, int ngram_upper_sz, int range_sz, int rez1, const qsmm_sig_t *sig_ngram_lower_p, const qsmm_sig_t *sig_ngram_upper_p, const struct qsmm_pair_sig_s *range_sig_p, qsmm_enum_ngram_callback_func_t callback_func, void *paramp)

This function enumerates lists of signal identifiers encoding action choice states that have the pieces of information stored in the memory of an actor. For a small actor, the action choice states have the pieces of information held in statistics storage with a handle retrievable by the function qsmm_get_actor_storage. For a large actor, the action choice states are the union of the following state sets:

  • action choice states with assigned references to output signal choice trees but without model nodes yet created to store tree instances;
  • action choice states with model nodes already created to store instances of output signal choice trees;
  • action choice states that have the pieces of information held in statistics storage with a handle retrievable by qsmm_get_actor_storage for the large actor.

If ngram_lower_sz is positive, it specifies the length of sig_ngram_lower_p array containing a lower bound for the enumerated lists—their prefixes with length ngram_lower_sz must be greater than or equal to the lower bound. If ngram_upper_sz is positive, it specifies the length of sig_ngram_upper_p array containing an upper bound for the enumerated lists—their prefixes with length ngram_upper_sz must be less than the upper bound. If range_sz is positive, it specifies the length of range_sig_p array containing allowed ranges of signal identifiers in prefixes with length range_sz in the enumerated lists—every signal identifier in a prefix must be greater than or equal to the field first of an element of range_sig_p at the same index and must be less than or equal to the field second of the element.

The function qsmm_actor_enum_ngrams_v2 compares two lists of signal identifiers from left to right. If a signal identifier in the first list is less than or greater than a signal identifier in the second list at the same index, the first list is less than or greater than the second list respectively. If the first list is a prefix of the second list, the first list is less than the second list. If the second list is a prefix of the first list, the first list is greater than the second list. If the two lists have the same length and content, the lists are equal.

The process of enumeration is repeated calling a callback function callback_func with passing an array of signal identifiers encoding an enumerated action choice state in ascending order of the arrays. The callback function also receives a user parameter paramp. If the callback function returns a positive value, qsmm_actor_enum_ngrams_v2 continues enumeration. If the callback function returns zero, qsmm_actor_enum_ngrams_v2 terminates enumeration and reports success. If the callback function returns a negative value, qsmm_actor_enum_ngrams_v2 terminates enumeration and reports failure.

The function qsmm_actor_enum_ngrams_v2 does not support recursive calling from the callback function for the same actor.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • ngram_lower_sz is negative;
  • ngram_lower_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • ngram_lower_sz is positive, but sig_ngram_lower_p is NULL;
  • ngram_upper_sz is negative;
  • ngram_upper_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • ngram_upper_sz is positive, but sig_ngram_upper_p is NULL;
  • range_sz is negative;
  • range_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • range_sz is positive, but range_sig_p is NULL;
  • field first in an element of range_sig_p is greater than the field second of the element;
  • field second in an element of range_sig_p is greater than QSMM_SIG_MAX.
QSMM_ERR_CALLBACK

The callback function reported an error.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The type of a pointer to a callback function called for every enumerated action choice state is below.

Data type: qsmm_enum_ngram_callback_func_t

This is a type of a callback function pointer with the following declaration:

typedef int
(*qsmm_enum_ngram_callback_func_t)(
    qsmm_actor_t actor,
    const qsmm_sig_t *sig_ngram_p,
    void *paramp
);

The function qsmm_actor_enum_ngrams_v2 calls the callback function for every enumerated action choice state of an actor. The argument sig_ngram_p specifies an array of signal identifiers encoding an enumerated action choice state. The field ngram_sz of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies the length of the array. The function qsmm_get_actor_ngram_sz returns that length for a created actor. The argument paramp is a user parameter passed to qsmm_actor_enum_ngrams_v2.

The callback function shall return a positive value to continue the process of enumeration, zero to terminate the process of enumeration, or a negative value on error.

Use the following function to remove information on an action choice state from the memory of an actor.

Function: int qsmm_actor_remove_ngram (qsmm_actor_t actor, const qsmm_sig_t *sig_ngram_p)

This function removes information on an action choice state encoded by an array of signal identifiers sig_ngram_p from the memory of an actor. The field ngram_sz of qsmm_actor_desc_s structure passed to the function qsmm_actor_create when creating the actor specifies the length of the array. The function qsmm_get_actor_ngram_sz returns that length for a created actor.

For a small actor, the function removes information on the action choice state held in statistics storage with a handle retrievable by the function qsmm_get_actor_storage. For a large actor, the function removes the following pieces of information if they exist:

  • reference to an output signal choice tree assigned to the action choice state;
  • model node holding an instance of an output signal choice tree assigned to the action choice state;
  • information on the action choice state held in statistics storage with a handle retrievable by the function qsmm_get_actor_storage for the large actor.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NGRAM

The array sig_ngram_p is not a valid array of signal identifiers encoding an action choice state. To determine array validity, the function checks it for accordance with allowed ranges of signal identifiers specified by the field range_sig_p of qsmm_actor_desc_s structure when creating the actor.

QSMM_ERR_NOTFOUND

No information on the action choice state—nothing to remove.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation for a large actor. This error can leave the large actor in inconsistent state. If after removing a reason of this error a repeated call to this function succeeds, or the function reports QSMM_ERR_NOTFOUND, the actor’s state becomes consistent.


2.11 Example of Using the Actor API

In the example of using the Actor API, an agent controlled by a sample program has to find a short path to gold located in a labyrinth and then to an exit from the labyrinth. The source code of the sample program contains a labyrinth picture encoded using a subset of ASCII characters resembling pseudographics. You can change the picture to test agent behavior for various labyrinth configurations.

To find a resulting path, the agent visits the labyrinth the number of times defined by the macro NVISIT. Moving the agent to a cell designated as a labyrinth exit finishes a labyrinth visit. A custom function returning the relative probability of an output signal is the exponent of an expression equal to mean spur increment for a cycle type divided by actor temperature. The sample program uses a simulated annealing approach, where actor temperature gradually decreases with every subsequent labyrinth visit. The macro KT_0 defines initial actor temperature, and the macro KT_1 defines final temperature.

At the last labyrinth visit, the sample program shows a labyrinth picture and agent movements in it, prints an indication whether the agent took the gold, and displays current length of a visiting path. After finishing the last visit, a user can press Q to create the files labyr_0.asy and labyr_1.asy, print the number of labyrinth visits when the agent took the gold, and exit the sample program. The two files correspond to the case before taking the gold by the agent and the case after taking the gold respectively. Each file includes the file labyr.asy and represents a labyrinth picture containing the following information:

  • an upward triangle indicating an entry to the labyrinth;
  • one or more downward triangles indicating exits from the labyrinth;
  • one or more circles indicating the gold;
  • black cells indicating places never visited by the agent;
  • other cells with gray scale backgrounds indicating visited places, where the backgrounds are darker for greater visiting frequencies;
  • for the file labyr_0.asy, indicated by arrows learned gradients of movements to a cell with the gold;
  • for the file labyr_1.asy, indicated by arrows learned gradients of movements to an exit cell after taking the gold;
  • cells on the last visiting path contain thick arrows.

To process both files by Asymptote and produce the image files labyr_0.png and labyr_1.png, use the commands:

asy -f png labyr_0.asy
asy -f png labyr_1.asy

You can specify a random seed by a program argument. If the random seed is non-negative, the actor operates adaptively (normally). If the random seed is negative, the actor operates randomly. You can compare agent behavior and resulting files labyr_0.png and labyr_1.png for the two modes of program execution.

For example, after executing the command

$ qsmm-example-labyr2 1

the file labyr_0.png produced from labyr_0.asy contains the image

image labyr_0.png produced from labyr_0.asy

Figure 2.6: image labyr_0.png produced from labyr_0.asy

and the file labyr_1.png produced from labyr_1.asy contains the image

image labyr_1.png produced from labyr_1.asy

Figure 2.7: image labyr_1.png produced from labyr_1.asy

In the source code of the sample program, each labyrinth cell is a rectangle 4x3 (WxH). The picture of a labyrinth cell is represented in Figure 2.8. Adjacent cells have common border columns or rows. For adjacent cells located vertically, row 2 of an upper cell and row 0 of a lower cell are the same rows. For adjacent cells located horizontally, column 3 of a left cell and column 0 of a right cell are the same columns.

labyrinth cell

Figure 2.8: labyrinth cell

The macros MAX_X and MAX_Y define maximum zero-based coordinates of a labyrinth cell. Thus, the labyrinth has (MAX_X+1)*3+1 character columns in width and (MAX_Y+1)*2+1 character rows in height. The macros ENTRY_X and ENTRY_Y define zero-based coordinates of the entry cell of the labyrinth relative to its upper left corner.

Within a labyrinth cell, space characters denote allowed movement paths, and other characters denote disallowed movement paths. Let us denote a character in column x and row y of a labyrinth cell by <x,y>. If a cell is reachable from a labyrinth entry, then characters <1,1> and <2,1> of the cell must be spaces; small circles denote them in the figure. If the cell allows the agent to move to a left and/or right adjacent cell, then characters <0,1> and/or <3,1> respectively must be spaces; left and right arrows denote them in the figure. If the cell allows the agent to move to an upper adjacent cell, then characters <1,0> and <2,0> must be spaces; up arrows denote them in the figure. If the cell allows the agent to move to a lower adjacent cell, then characters <1,2> and <2,2> must be spaces; down arrows denote them in the figure.

If characters <0,0>, <3,0>, <0,2>, and <3,2> of a cell are the characters ‘*’, the cell contains gold. If there are multiple cells with the gold, visiting any of them means taking the gold. It is in a single copy per labyrinth visit—visiting any cell with the gold implicitly removes it from all other cells until the next labyrinth visit. If characters at the cell corners are the characters ‘#’, the cell is a labyrinth exit. A labyrinth can have more than one exit. When modifying the picture of a labyrinth, ensure proper alignment and connection of its cells and the absence of paths outside the labyrinth. Violating the mentioned rules leads to undefined program behavior.

The file samples/labyr2.c in the package distribution installed to $prefix/share/qsmm/samples/labyr2.c contains the source code of the sample program. Below is a copy of that source code. The command make builds the sample program if the configure script has configured QSMM to use the ncurses library. The command make install installs the binary of the sample program and names the installed binary as ‘qsmm-example-labyr2’ if the configure script has configured QSMM to install example programs. See the file INSTALL in the root of the package distribution for information on the configure script.

#include <config.h>

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#if defined(HAVE_CURSES_H)
#   include <curses.h>
#elif defined(HAVE_NCURSES_CURSES_H)
#   include <ncurses/curses.h>
#endif

#include <qsmm/qsmm.h>

#define NVISIT  200
#define MAX_X   14
#define MAX_Y   14
#define ENTRY_X 0
#define ENTRY_Y 14
#define NSIG_IN (MAX_X+1>MAX_Y+1?MAX_X+1:MAX_Y+1)
#define KT_0    (NVISIT*2)
#define KT_1    (1.0/KT_0)


#define CHK_FAIL(func, ...)                                               \
    do {                                                                  \
        const int rc=func(__VA_ARGS__);                                   \
        if (rc<0) {                                                       \
            fprintf(stderr, #func ": %s\n", qsmm_err_str(rc));            \
            goto Exit;                                                    \
        }                                                                 \
    }                                                                     \
    while (0)


#define ERREXIT(fmt, ...)                                                 \
    do {                                                                  \
        fprintf(stderr,fmt "\n", ## __VA_ARGS__);                         \
        goto Exit;                                                        \
    }                                                                     \
    while (0)


enum direct_e {
    DIRECT_NORTH,  // move one step up
    DIRECT_EAST,   // move one step right
    DIRECT_SOUTH,  // move one step down
    DIRECT_WEST,   // move one step left
    DIRECT_COUNT   // number of movement directions
};


static char last_path[2][MAX_Y+1][MAX_X+1];
static long fq_max[3], state_fq[3][MAX_Y+1][MAX_X+1];
static qsmm_actor_t actor=0;


// Generate an Asymptote file containing a picture of the labyrinth with
// learned movement gradients for the cases when the gold was or was not
// taken.
// Returns: 0 = success;
//         -1 = failure.

static int
create_pic(
    const char **pic_pp,
    char is_gf
) {
    char fln[]="labyr_?.asy";
    int ii, result=-1;
    fln[6]=is_gf?'1':'0';
    FILE *const filep=fopen(fln,"w");
    if (!filep) ERREXIT("%s: failed to open the file for writing",fln);
    fprintf(filep,"import labyr;\n\n");
    fprintf(filep,"set_dims(%d,%d);\n",MAX_X,MAX_Y);
    qsmm_sig_t *const sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    sig_ngram_p[0]=is_gf;
    for (int yy=0; yy<=MAX_Y; yy++)
        for (int xx=0; xx<=MAX_X; xx++) {
            if (state_fq[2][yy][xx]<1) {
                fprintf(filep,"black_box(%d,%d);\n",xx,yy);
                continue;
            }
            fprintf(filep, "fill_box(%d,%d,%.2f);\n",
                    xx, yy, (double) state_fq[(int) is_gf][yy][xx]/
                            fq_max[(int) is_gf]);
            const int row=yy*2, col=xx*3;
            for (const char *ccp="#*"; *ccp; ccp++)
                if (pic_pp[row][col]==*ccp && pic_pp[row][col+3]==*ccp &&
                    pic_pp[row+2][col+3]==*ccp && pic_pp[row+2][col]==*ccp)
                    fprintf(filep, "%s(%d,%d);\n",
                            *ccp=='#'?"exit":"gold", xx, yy);
            sig_ngram_p[1]=xx;
            sig_ngram_p[2]=yy;
            CHK_FAIL(qsmm_actor_calc_action_prob, actor,
                     0, 0, 0, QSMM_PROB_LEARNED);
            const double *const prob_p=
                qsmm_get_actor_choice_sig_prob(actor);
            double prob_max=0, ww[DIRECT_COUNT];
            for (ii=0; ii<DIRECT_COUNT; ii++) {
                const double prob=prob_p[ii];
                if (prob_max<prob) prob_max=prob;
                ww[ii]=prob;
            }
            for (ii=0; ii<DIRECT_COUNT; ii++) ww[ii]/=prob_max;
            fprintf(filep, "arrows(%s,%d,%d,%.2f,%.2f,%.2f,%.2f);\n",
                    last_path[(int) is_gf][yy][xx]?"true":"false",
                    xx, yy, ww[0], ww[1], ww[2], ww[3]);
            qsmm_actor_choice_sig_prob_release(actor);
        }
    fprintf(filep,"entry(%d,%d);\n",ENTRY_X,ENTRY_Y);
    if (ferror(filep)) ERREXIT("%s: failed to write to the file",fln);
    result=0;

Exit:
    if (filep) fclose(filep);
    return result;
}


// Make a movement in the labyrinth in a specified direction possibly
// showing the movement on the screen.
// Returns: 3 = movement resulted in exiting the labyrinth;
//          2 = movement resulted in taking the gold;
//          1 = movement made successfully;
//          0 = cannot make the movement because a new location cell of the
//              agent is not empty.

static int
opaque_maze(
    enum direct_e direct
) {
    static const char *picture[]={
        // 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
        "+--------+-----+--------------------------#..#",
        "|        |     |                             |",  // 0
        "|  *  *  |     |                          #  #",
        "|        |     |                             |",  // 1
        "|  *  *  |     |     +-----+                 |",
        "|        |     |     |     |                 |",  // 2
        "|        |     |     |     |     +-----+     |",
        "|        |     |     |     |     |     |     |",  // 3
        "|        |     |     |     |     |     |     |",
        "|        |     |     |     |     |     |     |",  // 4
        "|        +-----+     |     |     |     |     |",
        "|                    |     |     |     |     |",  // 5
        "|                    |     |     |     |     |",
        "|                    |     |     |     |     |",  // 6
        "|  +-----------+     +-----+     |     |     |",
        "|  |           |                 |     |     |",  // 7
        "|  |           |                 |     |     |",
        "|  |           |                 |     |     |",  // 8
        "|  +-----------+     +-----+     |     |     |",
        "|                    |     |     |     |     |",  // 9
        "|                    |     |     |     |     |",
        "|                    |     |     |     |     |",  // 10
        "+--------------+     |     |     +-----+     |",
        "|              |     |     |                 |",  // 11
        "|              |     |     |                 |",
        "|              |     |     |                 |",  // 12
        "+--------------+     +-----+     +-----+     |",
        "|                                |     |     |",  // 13
        "|                                |     |     |",
        "|                                |     |     |",  // 14
        "+..+-----------------------------+-----+-----+"
    };
    static char is_gf=0;
    static int path_len, visit=0, xx=-1, yy=-1;
    int ii, col, row;
    if (xx<0 || yy<0) {
        if (visit==NVISIT-1) {
            if (!initscr()) exit(2);
            noecho();
            for (row=0; row<(MAX_Y+1)*2+1; row++)
                mvaddstr(row,0,picture[row]);
        }
        xx=ENTRY_X;
        yy=ENTRY_Y;
        path_len=0;
    }
    assert(xx>=0 && xx<=MAX_X);
    assert(yy>=0 && yy<=MAX_Y);
    if (visit==NVISIT-1) last_path[(int) is_gf][yy][xx]=1;
    col=xx*3+1;
    row=yy*2+1;
    assert(picture[row][col]==' ' && picture[row][col+1]==' ');
    assert((picture[row-1][col]==' ' && picture[row-1][col+1]==' ') ||
           (picture[row-1][col]!=' ' && picture[row-1][col+1]!=' '));
    assert((picture[row+1][col]==' ' && picture[row+1][col+1]==' ') ||
           (picture[row+1][col]!=' ' && picture[row+1][col+1]!=' '));
    switch (direct) {
        case DIRECT_NORTH:
            if (picture[row-1][col]!=' ' || picture[row-1][col+1]!=' ')
                return 0;
            yy--;
            break;
        case DIRECT_EAST:
            if (picture[row][col+2]!=' ') return 0;
            xx++;
            break;
        case DIRECT_SOUTH:
            if (picture[row+1][col]!=' ' || picture[row+1][col+1]!=' ')
                return 0;
            yy++;
            break;
        case DIRECT_WEST:
            if (picture[row][col-1]!=' ') return 0;
            xx--;
            break;
        default:
            assert(0);
    }
    path_len++;
    if (visit==NVISIT-1) mvaddstr(row,col,"  ");
    col=xx*3+1;
    row=yy*2+1;
    state_fq[2][yy][xx]++;
    state_fq[(int) is_gf][yy][xx]++;
    for (ii=0; ii<3; ii++)
        if (fq_max[ii]<state_fq[ii][yy][xx])
            fq_max[ii]=state_fq[ii][yy][xx];
    if (visit==NVISIT-1) {
        char ss[64];
        const int picture_w=strlen(picture[0]);
        mvaddstr(row,col,"[]");
        sprintf(ss," Gold found: %d",is_gf);
        mvaddstr(1,picture_w+2,ss);
        sprintf(ss,"Path length: %d",path_len);
        mvaddstr(3,picture_w+2,ss);
        move((MAX_Y+1)*2+3,0);
        refresh();
        usleep(125000);
    }
    int result=1;
    for (const char *ccp="#*"; *ccp; ccp++)
        if (picture[row-1][col-1]==*ccp && picture[row-1][col+2]==*ccp &&
            picture[row+1][col-1]==*ccp && picture[row+1][col+2]==*ccp) {
            if (*ccp=='#') {
                is_gf=0;
                result=3;
                xx=-1;
                yy=-1;
                if (visit==NVISIT-1) {
                    row=(MAX_Y+1)*2+3;
                    mvaddstr(row,0,"Press [Q] to exit");
                    while (1) {
                        int key=getch();
                        if (key=='q' || key=='Q') break;
                    }
                    for (ii=0; ii<2; ii++)
                        if (create_pic(picture,ii)<0) exit(2);
                    endwin();
                }
                else visit++;
            }
            else if (!is_gf) {
                is_gf=1;
                result=2;
            }
            break;
        }
    return result;
}


// Helper function for computing the relative probability of an
// output signal.

static double
relprob_user2(
    qsmm_actor_t actor,
    qsmm_sig_t sig_cycle,
    const struct qsmm_state_s *state_p,
    const struct qsmm_cycle_s *cycle_p,
    const struct qsmm_sspval_s *sspval_p,
    const struct qsmm_cspval_s *cspval_p,
    void *paramp
) {
    const double period_sum_c=cspval_p[1].delta_sum;
    return (period_sum_c?cspval_p[0].delta_sum/period_sum_c:0)/
        qsmm_get_actor_ktemperature(actor);
}


// Find a path to gold in the labyrinth and then to its exit.

int
main(
    int argc,
    char **argv
) {
    int exit_code=1;
    struct qsmm_pair_sig_s range_sig[3];
    memset(range_sig,0,sizeof(range_sig));
    range_sig[0].second=1;
    range_sig[1].second=MAX_X;
    range_sig[2].second=MAX_Y;
    struct qsmm_actor_desc_s actor_desc;
    memset(&actor_desc,0,sizeof(actor_desc));
    actor_desc.nspur=1;
    actor_desc.ntime=1;
    actor_desc.ngram_sz=3;
    actor_desc.compat=3;
    actor_desc.nsig_in=NSIG_IN;
    actor_desc.nsig_out=DIRECT_COUNT;
    actor_desc.range_sig_p=range_sig;
    CHK_FAIL(qsmm_actor_create,&actor_desc,&actor);
    qsmm_set_actor_relprob_type(actor,QSMM_RELPROB_USER2);
    qsmm_set_actor_relprob_helper(actor,&relprob_user2,0);
    const int seed=(argc>1?atoi(argv[1]):0);
    if (seed<0) qsmm_set_actor_random(actor,1);
    qsmm_rng_seed(qsmm_get_actor_rng(actor),abs(seed));
    int n_gold_found=0;
    const double mut=pow(KT_1/KT_0,1.0/NVISIT);
    double ktemperature=KT_0;
    qsmm_sig_t *const sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    for (int visit=0; visit<NVISIT; visit++) {
        char is_gf=0;
        int xx=ENTRY_X, yy=ENTRY_Y;
        qsmm_sig_t sig_action=QSMM_SIG_INVALID;
        CHK_FAIL(qsmm_set_actor_ktemperature,actor,ktemperature);
        while (1) {
            sig_ngram_p[0]=is_gf;
            sig_ngram_p[1]=xx;
            sig_ngram_p[2]=yy;
            CHK_FAIL(qsmm_actor_reg_ngram_in,actor);
            CHK_FAIL(qsmm_actor_calc_action_prob, actor,
                     0, 0, 0, QSMM_PROB_LEARNED);
            CHK_FAIL(qsmm_get_actor_sig_action,actor,0,0,0,&sig_action);
            CHK_FAIL(qsmm_actor_reg_sig_out,actor,sig_action);
            CHK_FAIL(qsmm_actor_time_delta_v2,actor,0,0,1);
            const enum direct_e direct=sig_action;
            const int rc=opaque_maze(direct);
            switch (rc) {
                case 0:
                    continue;
                case 1:
                    break;
                case 2:
                    is_gf=1;
                    n_gold_found++;
                    break;
                case 3:
                    if (is_gf) CHK_FAIL(qsmm_actor_spur_delta,actor,0,1);
                    break;
                default:
                    assert(0);
            }
            if (rc==3) break;
            switch (direct) {
                case DIRECT_NORTH: yy--; break;
                case DIRECT_EAST:  xx++; break;
                case DIRECT_SOUTH: yy++; break;
                case DIRECT_WEST:  xx--; break;
                default: assert(0);
            }
        }
        ktemperature*=mut;
    }
    printf("\nn_gold_found %d\n",n_gold_found);
    exit_code=0;

Exit:
    qsmm_actor_destroy(actor);
    return exit_code;
}

3 Statistics Storage

Statistics storage holds information on action choice states and cycle types registered by an actor. Additionally, statistics storage can hold probability profiles assigned to action choice states.

The function qsmm_actor_create creates statistics storage for an actor. The function qsmm_actor_destroy destroys statistics storage for an actor.

Statistics storage uses a concept of cycle-summed values. They are spur values and continuous time values recordable at a cycle start or summable over cycles with a specific type. The field nspur of qsmm_actor_desc_s structure defines the number of cycle-summed value types for spur. The field ntime of qsmm_actor_desc_s structure defines the number of cycle-summed value types for continuous time.

Storage API functions retrieve or store information on action choice states or cycle types via data structures holding the condition of an action choice state, a cycle-summed value for an action choice state, statistics on a cycle type, and a cycle-summed value for a cycle type. Storage API functions provide means to query the number of cycle-summed value types supported by storage, to retrieve and store the condition of an action choice state and statistics on a cycle type, to remove information on an action choice state from storage, and to enumerate action choice states and cycle types that have information held in storage.

Statistics storage supports setting redirection functions for altering the behavior of storage access operations or intercepting them. Storage redirection functions for obtaining the initial condition of an action choice state, the initial statistics of a cycle type, and the next cycle direction for a cycle type make it possible to generate the probability profile of an action choice state on demand. This approach helps reduce initial memory footprint of a model and speed up its preparation. QSMM uses the redirection functions internally to implement deferred setting a probability profile for a number of nodes of a multinode model.

Specifying a storage redirection function to intercept updating cycle type statistics makes it possible to organize keeping cycle type statistics for the tail of an event history rather than for the entire event history.


3.1 Storage Handle

A storage handle refers to a storage instance.

Data type: qsmm_storage_t

This is a type for a storage handle. It is a pointer, so variables of this type can be NULL. The function qsmm_get_actor_storage returns the storage handle of an actor. You can pass a returned handle to API functions taking an argument of qsmm_storage_t type until destroying the actor.

Use the following function to query the number of cycle-summed value types supported by a storage instance referred to by a storage handle.

Function: int qsmm_get_storage_nspval (qsmm_storage_t storage)

This function returns the number of cycle-summed value types supported by storage. That number is the sum of the number of spur types and the number of continuous time types supported by an actor owning storage. The indices of cycle-summed value types for spur types precede the indices of cycle-summed value types for continuous time types.

The field nspur of qsmm_actor_desc_s structure passed when creating an actor specifies the number of supported spur types. The function qsmm_get_actor_nspur returns that number for a created actor. The field ntime of qsmm_actor_desc_s structure passed when creating an actor specifies the number of supported continuous time types. The function qsmm_get_actor_ntime returns that number for a created actor.

A value returned by the function is always non-negative.


3.2 Structures for Accessing Storage

The following structure holds the condition of an action choice state.

Structure: qsmm_state_s

This structure holds the condition of an action choice state h (see Relative Probability Function Types, for formulas involving h). The structure contains the following fields.

Field: long tmd0

The discrete time of last occurrence of a cycle of <h,z> type in the event history, where the field sig_cycle_next of this structure specifies z. If the field tmd0 is non-negative, and sig_cycle_next is not QSMM_SIG_INVALID, tmd0 indicates the discrete time of last emitting output signal z in action choice state h. The function qsmm_actor_reg_sig_out records that discrete time. The default value of this field is −1.

Field: double nsig_ctrl

The nominal number of output signals for the probability profile of this action choice state. See Number of Output Signals, for the explanation of the concept of the nominal number of output signals for an action choice state.

If nsig_ctrl is positive, it specifies custom nominal number of output signals. If the field nsig_pos of this structure is greater than 1, nsig_ctrl must be greater than 1 and less than or equal to nsig_pos. If nsig_pos is negative, nsig_ctrl must be equal to 1. The field nsig_ctrl must not be positive if nsig_pos is 0.

If nsig_ctrl is 0, this condition means to use implicit nominal number of output signals equal to the number of cycle directions with positive profile probabilities held in nsig_pos.

The default value of this field is 0.

Field: qsmm_sig_t sig_cycle_next

An output signal indicating the direction of last cycle started at this action choice state and not yet processed. If the function qsmm_actor_reg_sig_out did not register a cycle started at this action choice state, or the function qsmm_actor_reg_ngram_in has already processed the cycle, then QSMM_SIG_INVALID. The default value is QSMM_SIG_INVALID.

Field: qsmm_ssig_t nsig_pos

This field contains information on the number of cycle types <h,x> (i.e. starting at this action choice state h) with positive profile probabilities assigned, where x is a possible cycle direction. Meanings of various values of this field are below.

0

The action choice state does not have a probability profile specified.

i>1

The number i of cycle directions with positive profile probabilities assigned.

i<0

A single cycle direction has a positive profile probability assigned, and −i−1 is equal to identifier x of an output signal only allowed by the probability profile.

1

Disallowed.

This field is read-only when using the functions qsmm_set_storage_state_stats and qsmm_get_storage_state_stats: qsmm_set_storage_state_stats ignores the field, and qsmm_get_storage_state_stats calculates its value based on the number of cycle directions with positive profile probabilities specified in the field profile of qsmm_cycle_s structure for cycle types starting at this action choice state.

If storage does not contain the condition of the action choice state, and storage has a set redirection function for retrieving the initial condition of an action choice state, qsmm_get_storage_state_stats calls the redirection function, and it should set nsig_pos to a correct value. See Specifying Redirection Functions, for more information on the redirection function.

The condition of an action choice state includes an array of instances of a structure holding an initial cycle-summed value recorded by the function qsmm_actor_reg_sig_out for the last cycle started at the action choice state. The number of elements in the array is equal to the number of cycle-summed value types supported by storage. The array begins with initial cycle-summed values for spur followed by initial cycle-summed values for continuous time.

The structure contains only one field but is a structure to simplify associating other information with an action choice state and cycle-summed value type for research purposes. When storage prepares a structure instance for first use, it initializes the instance with zeroes by the function memset, so fields you may have added will initially be zero.

The structure description is below.

Structure: qsmm_sspval_s

This structure holds condition associated with an action choice state and cycle-summed value type. The structure contains the following field.

Field: double val0

The current value of spur or continuous time recorded by the function qsmm_actor_reg_sig_out for the last cycle started at the action choice state when registering the emission of an output signal in the action choice state.

The following structure holds statistics on a cycle type.

Structure: qsmm_cycle_s

This structure holds statistics on a cycle type—a pair comprised of an action choice state and a cycle direction (i.e. an output signal emittable in the action choice state). In Spur Perception, the notation <h,z> is a cycle type for action choice state h and cycle direction z. The structure contains the following fields.

Field: long fq

The number of registered cycles of <h,z> type.

Field: long period_sum_d

The total length of registered cycles of <h,z> type measured in discrete time. In Spur Perception, the notation ω(h,z)  is that total length measured in discrete or continuous time.

Field: double profile

A profile probability—weight to multiply the relative probability of output signal z selectable in action choice state h. When using a probability profile, the sum of profile probabilities of all cycle types for action choice state h must be equal to 1. When not using a probability profile, the field must be equal to 0.

The statistics on a cycle type includes an array of instances of a structure holding an accumulated cycle-summed value incremented on registering a cycle of this type by the function qsmm_actor_reg_ngram_in. The number of elements in the array is equal to the number of cycle-summed value types supported by storage. The array begins with accumulated cycle-summed values for spur followed by accumulated cycle-summed values for continuous time.

The structure contains only one field but is a structure to simplify associating other information with a cycle type and cycle-summed value type for research purposes. When storage prepares a structure instance for first use, it initializes the instance with zeroes by the function memset, so fields you may have added will initially be zero.

The structure description is below.

Structure: qsmm_cspval_s

This structure holds statistics associated with cycle type <h,z> and a cycle-summed value type. The structure contains the following field.

Field: double delta_sum

The sum of increments of spur or continuous time over cycles of <h,z> type registered by the function qsmm_actor_reg_ngram_in. Each spur increment is the difference between a current spur or continuous time value at a moment of calling qsmm_actor_reg_ngram_in and a spur or continuous time value recorded at a cycle start and stored in the field val0 of qsmm_sspval_s structure.


3.3 Retrieving, Storing, and Removing Statistics

Use the following functions to retrieve or store the condition of an action choice state.

Function: int qsmm_get_storage_state_stats (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p, struct qsmm_state_s *state_p, struct qsmm_sspval_s *sspval_p)

This function retrieves from storage the condition of an action choice state encoded by an array of signal identifiers sig_ngram_p holding ngram_sz elements. If state_p is not NULL, the function copies the condition to *state_p. If sspval_p is not NULL, the function copies conditions for all cycle-summed value types associated with the action choice state to an array addressed by sspval_p. The array must be capable of holding the number of elements returned by the function qsmm_get_storage_nspval.

If storage does not contain the condition of the action choice state, and storage has a set redirection function for retrieving the initial condition of an action choice state, qsmm_get_storage_state_stats calls the redirection function to obtain the initial condition of the action choice state. When validating the field sig_cycle_next of qsmm_state_s structure obtained by the redirection function, qsmm_get_storage_state_stats may also call a redirection function for retrieving the initial statistics of a cycle type. See Specifying Redirection Functions, for more information on the redirection functions.

If storage contained the condition of the action choice state, or storage did not contain the condition, but the redirection function has retrieved it, qsmm_get_storage_state_stats returns a positive value. If storage did not contain the condition, and the redirection function has not retrieved it, qsmm_get_storage_state_stats returns 0 and the constant default condition. On failure, qsmm_get_storage_state_stats returns a negative error code. Currently, this function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is a set of action choice states supported by an actor owning the storage.

QSMM_ERR_STORAGE

The storage did not contain the condition of the action choice state, and a redirection function called to obtain the initial condition of the action choice state has reported QSMM_ERR_STORAGE or an unexpected error code, or the redirection function succeeded, but the function qsmm_get_storage_cycle_stats called to validate the field sig_cycle_next of qsmm_state_s structure obtained by that redirection function has reported QSMM_ERR_STORAGE.

See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

A redirection function for retrieving the initial condition of an action choice state reported QSMM_ERR_STATS, or condition retrieved by the redirection function was inconsistent.

QSMM_ERR_ILSEQ

A redirection function for retrieving the initial condition of an action choice state or the initial statistics of a cycle type reported QSMM_ERR_ILSEQ, or a generated error message was not convertible to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_set_storage_state_stats (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p, const struct qsmm_state_s *state_p, const struct qsmm_sspval_s *sspval_p)

This function writes to storage the condition of an action choice state encoded by an array of signal identifiers sig_ngram_p holding ngram_sz elements. If state_p is not NULL, the function copies the condition from *state_p. If sspval_p is not NULL, the function copies conditions for all cycle-summed value types associated with the action choice state from an array addressed by sspval_p. The function qsmm_get_storage_nspval returns the number of elements of sspval_p array copied.

The function qsmm_set_storage_state_stats may call a redirection function for obtaining the initial condition of the action choice state when adding information on it to storage. The function qsmm_set_storage_state_stats may also call a redirection function for obtaining the initial statistics of a cycle type when validating the field sig_cycle_next of qsmm_state_s structure. See Specifying Redirection Functions, for more information on the redirection functions.

The function qsmm_set_storage_state_stats returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is a set of action choice states supported by an actor owning the storage.

QSMM_ERR_STORAGE

The function qsmm_get_storage_cycle_stats called to validate the field sig_cycle_next of *state_p or validate the field sig_cycle_next of an instance of qsmm_state_s structure obtained by a redirection function for retrieving the initial condition of an action choice state reported QSMM_ERR_STORAGE, or the redirection function reported QSMM_ERR_STORAGE or an unexpected error code.

See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent condition in *state_p or an element of sspval_p array, or a redirection function for retrieving the initial condition of an action choice state reported QSMM_ERR_STATS, or condition retrieved by the redirection function was inconsistent.

Condition in qsmm_state_s is inconsistent in the following cases:

  • nsig_ctrl is not finite;
  • nsig_ctrl is negative;
  • the action choice state has a single cycle direction allowed by a probability profile, but nsig_ctrl is not 0 and 1;
  • the action choice state has multiple cycle directions allowed by a probability profile, and nsig_ctrl is not 0 but is less than or equal to 1 or is greater than the number of cycle directions allowed by the probability profile;
  • sig_cycle_next is not QSMM_SIG_INVALID but also not an output signal of an actor owning the storage;
  • sig_cycle_next is not QSMM_SIG_INVALID, and tmd0 is negative;
  • sig_cycle_next is not QSMM_SIG_INVALID, the action choice state has a probability profile assigned, and the function qsmm_get_storage_cycle_stats called to check the presence of statistics on a cycle type for the action choice state and cycle direction sig_cycle_next returned 0 or reported QSMM_ERR_STATS.

Condition in an element of sspval_p array is inconsistent if the field val0 of the element is not finite.

QSMM_ERR_ILSEQ

A redirection function for retrieving the initial condition of an action choice state or the initial statistics of a cycle type reported QSMM_ERR_ILSEQ, or a generated error message was not convertible to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

To update the condition of an action choice state, you first need to retrieve existing condition by the function qsmm_get_storage_state_stats, then change some fields, and, finally, store the condition by the function qsmm_set_storage_state_stats. For example, you can reset the field tmd in the condition of an action choice state using a block of code like this:

int rc;
struct qsmm_state_s state;
if ((rc=
     qsmm_get_storage_state_stats(storage, ngram_sz, sig_ngram_p,
                                  &state, 0))<0)
    REPORT_ERROR(rc);
state.tmd=-1;
if ((rc=
     qsmm_set_storage_state_stats(storage, ngram_sz, sig_ngram_p,
                                  &state, 0))<0)
    REPORT_ERROR(rc);

To satisfy validity checks performed by the function qsmm_set_storage_state_stats for the fields nsig_ctrl and sig_cycle_next of qsmm_state_s structure, a call to that function should go after a series of calls to the function qsmm_set_storage_cycle_stats described further on in this section. This is necessary because the validity checks depend on the value of nsig_pos field automatically calculated based on previous calls to qsmm_set_storage_cycle_stats. If nsig_pos is non-zero, sig_cycle_next should be QSMM_SIG_INVALID or specify the direction of a cycle type with statistics held in storage.

Use the following functions to retrieve or store statistics on a cycle type.

Function: int qsmm_get_storage_cycle_stats (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p, qsmm_sig_t sig_cycle, struct qsmm_cycle_s *cycle_p, struct qsmm_cspval_s *cspval_p)

This function retrieves statistics on a cycle type from storage. An action choice state and cycle direction sig_cycle specify the cycle type. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state.

If cycle_p is not NULL, the function copies the statistics to *cycle_p. If cspval_p is not NULL, the function copies statistics on all cycle-summed value types associated with the cycle type to an array addressed by cspval_p. The array must be capable of holding the number of elements returned by the function qsmm_get_storage_nspval.

If storage does not contain statistics on the cycle type, and storage has a set redirection function for retrieving the initial statistics of a cycle type, qsmm_get_storage_cycle_stats calls the redirection function to obtain initial statistics on the cycle type. See Specifying Redirection Functions, for more information on the redirection function.

If storage contained statistics on the cycle type, or storage did not contain the statistics, but the redirection function has retrieved it, qsmm_get_storage_cycle_stats returns a positive value. If storage did not contain the statistics, and the redirection function has not retrieved it, qsmm_get_storage_cycle_stats returns 0 and zero statistics. On failure, qsmm_get_storage_cycle_stats returns a negative error code. Currently, this function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states, or sig_cycle is not an output signal of an actor owning the storage.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is a set of action choice states supported by an actor owning the storage.

QSMM_ERR_STORAGE

The storage did not contain statistics on the cycle type, and a redirection function called to obtain initial statistics on the cycle type has reported QSMM_ERR_STORAGE or an unexpected error code. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

A redirection function for retrieving the initial statistics of a cycle type reported QSMM_ERR_STATS, or statistics retrieved by the redirection function was inconsistent.

QSMM_ERR_ILSEQ

A redirection function for retrieving the initial statistics of a cycle type reported QSMM_ERR_ILSEQ, or a generated error message was not convertible to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_set_storage_cycle_stats (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p, qsmm_sig_t sig_cycle, const struct qsmm_cycle_s *cycle_p, const struct qsmm_cspval_s *cspval_p)

This function writes statistics on a cycle type to storage. An action choice state and cycle direction sig_cycle specify the cycle type. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state.

If cycle_p is not NULL, the function copies the statistics from *cycle_p. If cspval_p is not NULL, the function copies statistics for all cycle-summed value types associated with the cycle type from an array addressed by cspval_p. The function qsmm_get_storage_nspval returns the number of elements of cspval_p array copied.

The function qsmm_set_storage_cycle_stats calls a redirection function for the interception of updating statistics on a cycle type if storage has the redirection function set. See Specifying Redirection Functions, for more information on the redirection function. The function qsmm_set_storage_cycle_stats may call redirection functions for obtaining the initial condition of the action choice state or the initial statistics of the cycle type when adding information on it to storage. See Specifying Redirection Functions, for more information on the redirection functions.

The function qsmm_set_storage_cycle_stats returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states, or sig_cycle is not an output signal of an actor owning the storage.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is a set of action choice states supported by an actor owning the storage.

QSMM_ERR_STORAGE

A storage redirection function reported QSMM_ERR_STORAGE or an unexpected error code. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

Inconsistent statistics in *cycle_p or an element of cspval_p array, or a storage redirection function reported QSMM_ERR_STATS, or statistics obtained from a storage redirection function was inconsistent.

Statistics in qsmm_cycle_s is inconsistent in the following cases:

  • fq is negative;
  • period_sum_d is negative;
  • profile is not finite;
  • profile is negative;
  • profile is greater than 1;
  • fq is zero, but period_sum_d is positive.

Statistics in an element of cspval_p array is inconsistent if the field delta_sum of the element is not finite.

QSMM_ERR_ILSEQ

A storage redirection function reported QSMM_ERR_ILSEQ, or a generated error message was not convertible to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

To update statistics on a cycle type, you first need to retrieve existing statistics by the function qsmm_get_storage_cycle_stats, then change some fields, and, finally, store the statistics by the function qsmm_set_storage_cycle_stats. For example, you can update a profile probability2 for a cycle type to a new value profile using a block of code like this:

int rc;
struct qsmm_cycle_s cycle;
if ((rc=
     qsmm_get_storage_cycle_stats(storage, ngram_sz, sig_ngram_p,
                                  sig_cycle, &cycle, 0))<0)
    REPORT_ERROR(rc);
cycle.profile=profile;
if ((rc=
     qsmm_set_storage_cycle_stats(storage, ngram_sz, sig_ngram_p,
                                  sig_cycle, &cycle, 0))<0)
    REPORT_ERROR(rc);

At present, an actor uses storage to hold statistics on action choice states encoded by arrays of signal identifiers with a fixed number of elements. The argument ngram_sz of Storage API functions must be equal to this fixed length. In the future, storage may hold statistics on action choice states encoded by arrays of signal identifiers with varying lengths, so that argument may have multiple valid values.

Use the following function to remove information on an action choice state from storage.

Function: int qsmm_storage_remove_state (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p)

This function removes from storage information on an action choice state encoded by an array of signal identifiers sig_ngram_p holding ngram_sz elements. The information includes the condition of the action choice state and statistics on all types of cycles starting at the action choice state.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is a set of action choice states supported by an actor owning the storage.

QSMM_ERR_NOTFOUND

Information on the action choice state not found in the storage—nothing to remove.


3.4 Enumerating Action Choice States and Cycle Types

Use the following function to enumerate action choice states that have the pieces of information held in storage.

Function: int qsmm_storage_enum_states_v2 (qsmm_storage_t storage, int ngram_lower_sz, int ngram_upper_sz, int range_sz, int rez1, const qsmm_sig_t *sig_ngram_lower_p, const qsmm_sig_t *sig_ngram_upper_p, const struct qsmm_pair_sig_s *range_sig_p, qsmm_enum_state_callback_func_t callback_func, void *paramp)

This function enumerates lists of signal identifiers encoding action choice states that have the pieces of information held in storage.

If ngram_lower_sz is positive, it specifies the length of sig_ngram_lower_p array containing a lower bound for the enumerated lists—their prefixes with length ngram_lower_sz must be greater than or equal to the lower bound. If ngram_upper_sz is positive, it specifies the length of sig_ngram_upper_p array containing an upper bound for the enumerated lists—their prefixes with length ngram_upper_sz must be less than the upper bound. If range_sz is positive, it specifies the length of range_sig_p array containing allowed ranges of signal identifiers in prefixes with length range_sz in the enumerated lists—every signal identifier in a prefix must be greater than or equal to the field first of an element of range_sig_p at the same index and must be less than or equal to the field second of the element.

The function compares two lists of signal identifiers from left to right. If a signal identifier in the first list is less than or greater than a signal identifier in the second list at the same index, the first list is less than or greater than the second list respectively. If the first list is a prefix of the second list, the first list is less than the second list. If the second list is a prefix of the first list, the first list is greater than the second list. If the two lists have the same length and content, the lists are equal.

The process of enumeration is repeated calling a callback function callback_func with passing an array of signal identifiers encoding an enumerated action choice state in ascending order of the arrays. The callback function also receives a user parameter paramp. If the callback function returns a positive value, qsmm_storage_enum_states_v2 continues enumeration. If the callback function returns zero, qsmm_storage_enum_states_v2 terminates enumeration and reports success. If the callback function returns a negative value, qsmm_storage_enum_states_v2 terminates enumeration and reports failure.

The function qsmm_storage_enum_states_v2 does not support recursive calling from the callback function for storage.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • ngram_lower_sz is negative;
  • ngram_lower_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • ngram_lower_sz is positive, but sig_ngram_lower_p is NULL;
  • ngram_upper_sz is negative;
  • ngram_upper_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • ngram_upper_sz is positive, but sig_ngram_upper_p is NULL;
  • range_sz is negative;
  • range_sz is greater than the length of a list of signal identifiers encoding an action choice state;
  • range_sz is positive, but range_sig_p is NULL;
  • field first in an element of range_sig_p is greater than the field second of the element;
  • field second in an element of range_sig_p is greater than QSMM_SIG_MAX.
QSMM_ERR_CALLBACK

The callback function reported an error.

The type of a pointer to a callback function called for every enumerated action choice state is below.

Data type: qsmm_enum_state_callback_func_t

This is a type of a callback function pointer with the following declaration:

typedef int
(*qsmm_enum_state_callback_func_t)(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    void *paramp
);

The function qsmm_storage_enum_states_v2 calls the callback function for every enumerated action choice state of storage. The argument sig_ngram_p specifies an array of signal identifiers encoding an enumerated action choice state. The argument ngram_sz specifies the length of the array. The argument paramp is a user parameter passed to qsmm_storage_enum_states_v2.

The callback function shall return a positive value to continue the process of enumeration, zero to terminate the process of enumeration, or a negative value on error.

Use a function described below to enumerate types of cycles starting at an action choice state. The action choice state and a cycle direction make up an enumerated cycle type.

Function: int qsmm_get_storage_cycle_next (qsmm_storage_t storage, int ngram_sz, const qsmm_sig_t *sig_ngram_p, qsmm_sig_t *sig_cycle_next_p)

This function retrieves the next cycle type that has a piece of information held in storage. An action choice state and cycle direction specify the cycle type. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state.

If *sig_cycle_next_p is QSMM_SIG_INVALID, then on successful function completion, *sig_cycle_next_p will contain the first cycle direction. It has a minimum value among existing cycle directions. If *sig_cycle_next_p is not QSMM_SIG_INVALID, then on successful function completion, *sig_cycle_next_p will contain the next cycle direction greater than a cycle direction specified in *sig_cycle_next_p when calling the function. If the first or next cycle direction does not exist, then on successful function completion, *sig_cycle_next_p will be QSMM_SIG_INVALID.

If storage has a set redirection function for retrieving the next cycle type of an action choice state, qsmm_get_storage_cycle_next calls the redirection function to obtain the next cycle type. If the redirection function reports that it has not retrieved the next cycle type, qsmm_get_storage_cycle_next proceeds as if storage does not have the redirection function set. See Specifying Redirection Functions, for more information on the redirection function.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The storage does not support length ngram_sz for arrays of signal identifiers encoding action choice states.

QSMM_ERR_NGRAM

The storage does not support holding information on an action choice state encoded by the array sig_ngram_p. A set of action choice states supported by storage is equal to a set of action choice states supported by an actor owning the storage.

QSMM_ERR_STORAGE

The storage redirection function reported QSMM_ERR_STORAGE or an unexpected error code. See Getting the Reason of a Storage Failure, for how to get an error message describing the failure.

QSMM_ERR_STATS

The storage redirection function reported QSMM_ERR_STATS, or a cycle direction obtained by that redirection function was not QSMM_SIG_INVALID and was greater than or equal to the number of output signals of an actor owning the storage or was less than or equal to *sig_cycle_next_p if it was not QSMM_SIG_INVALID.

QSMM_ERR_ILSEQ

The storage redirection function reported QSMM_ERR_ILSEQ, or a generated error message was not convertible to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


3.5 Specifying Redirection Functions

Before first use, Storage API functions initialize by the function memset with zeroes the instances of qsmm_state_s, qsmm_sspval_s, qsmm_cycle_s, and qsmm_cspval_s structures holding conditions for action choice states and statistics on cycle types. For every instance of qsmm_state_s structure, Storage API functions also perform the following assignments: set the field tmd0 to −1 and the field sig_cycle_next to QSMM_SIG_INVALID.

An application program can provide redirection functions called by Storage API functions just after the aforementioned initialization. The redirection functions can perform application-specific initialization. Storage API functions will call the redirection functions on accessing condition for an action choice state or statistics on a cycle type when storage does not contain requested information about the action choice state or cycle type.

Storage redirection functions performing application-specific initialization may set the parameters of a probability profile for an action choice state. They may also call Storage API functions for other action choice states, for example, to copy the parameters of a probability profile from another action choice state.

Data type: qsmm_get_state_stats_func_t

This is a type for the pointer to a redirection function for application-specific initialization of condition of an action choice state. The type has the following declaration:

typedef int
(*qsmm_get_state_stats_func_t)(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    struct qsmm_state_s *state_p,
    struct qsmm_sspval_s *sspval_p,
    void *paramp
);

The argument storage is a storage handle with the redirection function set. On calling the function, *state_p and the array sspval_p contain preinitialized values. The function can set *state_p and/or the elements of sspval_p array to application-specific initial condition of an action choice state. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state. The elements of sspval_p array contain initial cycle-summed values. The function qsmm_get_storage_nspval returns the number of elements in the array. The argument paramp is a user parameter specified when setting the redirection function for storage.

If the function has performed the redirection and possibly modified preinitialized values in *state_p or the array sspval_p, the function shall return a positive value. If the function has not performed the redirection and has left the preinitialized values intact, the function shall return 0. On failure, the function shall return one of the following negative error codes.

QSMM_ERR_STORAGE

Storage failure. Before reporting this error, the function shall add to the storage message list at least one message describing the reason of the failure. See Getting the Reason of a Storage Failure, for more information on the storage message list.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to retrieve or set a redirection function for application-specific initialization of condition of an action choice state.

Function: int qsmm_get_storage_state_stats_redir (qsmm_storage_t storage, qsmm_get_state_stats_func_t *get_state_stats_func_p, void **param_pp)

This function retrieves a previously set redirection function for application-specific initialization of conditions of action choice states in storage. If get_state_stats_func_p is not NULL, qsmm_get_storage_state_stats_redir sets *get_state_stats_func_p to a pointer to the redirection function or to NULL if storage does not have the redirection function assigned. If param_pp is not NULL, qsmm_get_storage_state_stats_redir sets *param_pp to a user parameter of that redirection function specified when assigning it to storage. The function qsmm_get_storage_state_stats_redir returns a non-negative value.

Function: int qsmm_set_storage_state_stats_redir (qsmm_storage_t storage, qsmm_get_state_stats_func_t get_state_stats_func, void *paramp)

This function sets a redirection function for application-specific initialization of conditions of action choice states in storage. The argument get_state_stats_func specifies a pointer to the redirection function. The argument paramp specifies the user parameter of the redirection function. If get_state_stats_func is NULL, storage will not use a redirection function for application-specific initialization of conditions of action choice states. The function qsmm_set_storage_state_stats_redir returns a non-negative value.

Data type: qsmm_get_cycle_stats_func_t

This is a type for the pointer to a redirection function for application-specific initialization of statistics on a cycle type. The pointer type has the following declaration:

typedef int
(*qsmm_get_cycle_stats_func_t)(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    qsmm_sig_t sig_cycle,
    struct qsmm_cycle_s *cycle_p,
    struct qsmm_cspval_s *cspval_p,
    void *paramp
);

The argument storage is a storage handle with the redirection function set. On calling the function, *cycle_p and the array cspval_p contain preinitialized values. The function can set *cycle_p and/or the elements of cspval_p array to application-specific initial statistics on a cycle type. An action choice state and output signal sig_cycle indicating a cycle direction specify the cycle type. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state. The elements of cspval_p array contain accumulated cycle-summed values. The function qsmm_get_storage_nspval returns the number of elements in the array. The argument paramp is a user parameter specified when setting the redirection function for storage.

If the function has performed the redirection and possibly modified preinitialized values in *cycle_p or the array cspval_p, the function shall return a positive value. If the function has not performed the redirection and has left the preinitialized values intact, the function shall return 0. On failure, the function shall return one of the following negative error codes.

QSMM_ERR_STORAGE

Storage failure. Before reporting this error, the function shall add to the storage message list at least one message describing the reason of the failure. See Getting the Reason of a Storage Failure, for more information on the storage message list.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to retrieve or set a redirection function for application-specific initialization of statistics on a cycle type.

Function: int qsmm_get_storage_cycle_stats_redir (qsmm_storage_t storage, qsmm_get_cycle_stats_func_t *get_cycle_stats_func_p, void **param_pp)

This function retrieves a previously set redirection function for application-specific initialization of statistics on cycle types in storage. If get_cycle_stats_func_p is not NULL, qsmm_get_storage_cycle_stats_redir sets *get_cycle_stats_func_p to a pointer to the redirection function or to NULL if storage does not have the redirection function assigned. If param_pp is not NULL, qsmm_get_storage_cycle_stats_redir sets *param_pp to a user parameter of that redirection function specified when assigning it to storage. The function qsmm_get_storage_cycle_stats_redir returns a non-negative value.

Function: int qsmm_set_storage_cycle_stats_redir (qsmm_storage_t storage, qsmm_get_cycle_stats_func_t get_cycle_stats_func, void *paramp)

This function sets a redirection function for application-specific initialization of statistics on cycle types in storage. The argument get_cycle_stats_func specifies a pointer to the redirection function. The argument paramp specifies the user parameter of the redirection function. If get_cycle_stats_func is NULL, storage will not use a redirection function for application-specific initialization of statistics on cycle types. The function qsmm_set_storage_cycle_stats_redir returns a non-negative value.

If an application sets a redirection function for custom initialization of statistics on cycle types, the application may need to provide a redirection function for retrieving the next cycle type for an action choice state. The latter redirection function enables correct enumeration of cycle types with initial statistics provided by the former redirection function. Enumerating cycle types that do not yet have information held in storage is necessary for generating probability profiles of action choice states on demand, that is, on read access to information about action choice states and their cycle types before the first write access to the information.

Data type: qsmm_get_cycle_next_func_t

This is a type for the pointer to a redirection function for retrieving the next cycle type for an action choice state. The pointer type has the following declaration:

typedef int
(*qsmm_get_cycle_next_func_t)(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    qsmm_sig_t *sig_cycle_next_p,
    void *paramp
);

The argument storage is a storage handle with the redirection function assigned passed to the function qsmm_get_storage_cycle_next. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state. The argument paramp is a user parameter specified when setting the redirection function for storage.

If *sig_cycle_next_p is QSMM_SIG_INVALID, then on successfully performed redirection, *sig_cycle_next_p shall contain a minimum output signal that along with the action choice state specifies the first cycle type for the action choice state. If *sig_cycle_next_p is not QSMM_SIG_INVALID, then on successfully performed redirection, *sig_cycle_next_p shall contain the next output signal greater than a signal specified in *sig_cycle_next_p when calling the redirection function; that output signal along with the action choice state shall specify the next cycle type for the action choice state. If the first or next cycle type does not exist, then on successful function completion, *sig_cycle_next_p shall be QSMM_SIG_INVALID.

If the function has performed the redirection and possibly updated *sig_cycle_next_p, the function shall return a positive value. If the function has not performed the redirection and has left *sig_cycle_next_p intact, the function shall return 0; in this case, qsmm_get_storage_cycle_next retrieves the next cycle type without the redirection. On failure, the redirection function shall return one of the following negative error codes.

QSMM_ERR_STORAGE

Storage failure. Before reporting this error, the function shall add to the storage message list at least one message describing the reason of the failure. See Getting the Reason of a Storage Failure, for more information on the storage message list.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to retrieve or set a redirection function for obtaining the next cycle type for an action choice state.

Function: int qsmm_get_storage_cycle_next_redir (qsmm_storage_t storage, qsmm_get_cycle_next_func_t *get_cycle_next_func_p, void **param_pp)

This function retrieves a previously set redirection function for obtaining the next cycle type that has a piece of information held in storage. If get_cycle_next_func_p is not NULL, qsmm_get_storage_cycle_next_redir sets *get_cycle_next_func_p to a pointer to the redirection function or to NULL if storage does not have the redirection function assigned. If param_pp is not NULL, qsmm_get_storage_cycle_next_redir sets *param_pp to a user parameter of that redirection function specified when assigning it to storage. The function qsmm_get_storage_cycle_next_redir returns a non-negative value.

Function: int qsmm_set_storage_cycle_next_redir (qsmm_storage_t storage, qsmm_get_cycle_next_func_t get_cycle_next_func, void *paramp)

This function sets a redirection function for obtaining the next cycle type that has a piece of information held in storage. The argument get_cycle_next_func specifies a pointer to the redirection function. The argument paramp specifies the user parameter of the redirection function. If get_cycle_next_func is NULL, storage will not use a redirection function for obtaining the next cycle type. The function qsmm_set_storage_cycle_next_redir returns a non-negative value.

An application program can provide a redirection function for intercepting updates of statistics on cycle types to organize keeping the statistics only for latest events in the event history rather than for the entire event history. Keeping statistics for a tail of the event history might make a state model less stable thereby improving the response of a system to latest tendencies in the event history. By making a state model less stable, a system might also try more state model variations and then select a variation that occurs more frequently.

The function qsmm_set_storage_cycle_stats calls a storage redirection function for intercepting updates of statistics on a cycle type if storage has the redirection function set. See Example of Using the Storage API, for an example redirection function for intercepting updates of statistics on a cycle type, an example helper function for calculating the relative probability of an output signal, and a function that sets the two example functions for a large actor.

The type of a pointer to the redirection function is below.

Data type: qsmm_update_cycle_stats_func_t

This is a type for the pointer to a redirection function for intercepting updates of statistics on cycle types. The pointer type has the following declaration:

typedef int
(*qsmm_update_cycle_stats_func_t)(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    qsmm_sig_t sig_cycle,
    const struct qsmm_cycle_s *cycle_new_p,
    struct qsmm_cycle_s *cycle_result_p,
    const struct qsmm_cspval_s *cspval_new_p,
    struct qsmm_cspval_s *cspval_result_p,
    void *paramp
);

The argument storage is a storage handle with the redirection function assigned passed to the function qsmm_set_storage_cycle_stats. An action choice state and output signal sig_cycle indicating a cycle direction specify a cycle type. An array of signal identifiers sig_ngram_p holding ngram_sz elements encodes the action choice state.

New statistics on the cycle type is in *cycle_new_p and an array cspval_new_p. On calling the function, current statistics on the cycle type is in *cycle_result_p and an array cspval_result_p. The arrays cspval_new_p and cspval_result_p hold the number of elements returned by the function qsmm_get_storage_nspval. The redirection function can compute the difference between *cycle_new_p and *cycle_result_p and between the elements of cspval_new_p and cspval_result_p arrays.

To use *cycle_result_p and the array cspval_result_p as new statistics on the cycle type, the function shall return a positive value; in this case, the function can change *cycle_result_p and the array cspval_result_p in its own way. To replace *cycle_result_p with *cycle_new_p, replace the elements of cspval_result_p with the elements of cspval_new_p, and use *cycle_result_p and the array cspval_result_p as new statistics on the cycle type, the function shall return 0. On failure, the function shall return one of the following negative error codes.

QSMM_ERR_STORAGE

Storage failure. Before reporting this error, the function shall add to the storage message list at least one message describing the reason of the failure. See Getting the Reason of a Storage Failure, for more information on the storage message list.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to retrieve or set a redirection function for intercepting updates of statistics on cycle types.

Function: int qsmm_get_storage_cycle_update_hook (qsmm_storage_t storage, qsmm_update_cycle_stats_func_t *update_cycle_stats_func_p, void **param_pp)

This function retrieves a previously set redirection function for intercepting updates of statistics on cycle types by the function qsmm_set_storage_cycle_stats called for storage. If update_cycle_stats_func_p is not NULL, qsmm_get_storage_cycle_update_hook sets *update_cycle_stats_func_p to a pointer to the redirection function or to NULL if storage does not have the redirection function assigned. If param_pp is not NULL, qsmm_get_storage_cycle_update_hook sets *param_pp to a user parameter of that redirection function specified when assigning it to storage. The function qsmm_get_storage_cycle_update_hook returns a non-negative value.

Function: int qsmm_set_storage_cycle_update_hook (qsmm_storage_t storage, qsmm_update_cycle_stats_func_t update_cycle_stats_func, void *paramp)

This function sets a redirection function for intercepting updates of statistics on cycle types by the function qsmm_set_storage_cycle_stats called for storage. The argument update_cycle_stats_func specifies a pointer to the redirection function. The argument paramp specifies the user parameter of the redirection function. If update_cycle_stats_func is NULL, storage will not use a redirection function for intercepting updates of statistics on cycle types. The function qsmm_set_storage_cycle_update_hook returns a non-negative value.


3.6 Getting the Reason of a Storage Failure

When a Storage API function returns error code QSMM_ERR_STORAGE, the function clears a storage message list and adds to it at least one error message describing a failure.

A handle of qsmm_msglist_t type represents a message list. See Messages and Message Lists, for how to work with message lists. Use the following function to obtain a message list associated with a storage instance.

Function: qsmm_msglist_t qsmm_get_storage_msglist (qsmm_storage_t storage)

This function returns the handle of a message list associated with storage. The function never returns NULL.

To dump to stderr the message list of storage in an application program with an executable named prg_name, use lines of code like these:

const int rc=qsmm_msglist_dump(qsmm_get_storage_msglist(storage),
                               prg_name, 0, 0, stderr);
if (rc<0) REPORT_ERROR(rc);

If an Actor API function returns error code QSMM_ERR_STORAGE, and the actor is the small one, the message list of a storage instance owned by the actor contains at least one error message describing a storage failure. Use the function qsmm_get_actor_storage to get the handle of a storage instance owned by the small actor.

If an Actor API function returns error code QSMM_ERR_STORAGE, and the actor is the large one, then a failed storage instance can be the storage instance of the actor itself or the storage instance of an associated small actor representing the environment state identification engine or the storage instance of an associated small actor representing the instruction emitting engine. Provided that all storage message lists were empty before calling the Actor API function, one of them would be non-empty and would contain a message describing the failure.

The following function returns the handle of failed storage instance of a small or large actor or NULL if the storage message lists are empty:

qsmm_storage_t
get_err_storage(
    qsmm_actor_t actor
) {
    qsmm_storage_t storage=qsmm_get_actor_storage(actor);
    if (qsmm_get_msglist_sz(qsmm_get_storage_msglist(storage))) return storage;
    const qsmm_t qsmm_large=qsmm_get_actor_large_model(actor);
    if (!qsmm_large) return 0;
    const qsmm_actpair_t actpair=qsmm_get_actpair(qsmm_large);
    if ((storage=
         get_err_storage(qsmm_get_actpair_actor(actpair,QSMM_ENGINE_ENV))))
        return storage;
    if ((storage=
         get_err_storage(qsmm_get_actpair_actor(actpair,QSMM_ENGINE_IEE))))
        return storage;
    return 0;
}

3.7 Example of Using the Storage API

As mentioned in Specifying Redirection Functions, achieving acceptable optimality of emitting output signals by an actor may require it to keep statistics for a tail of the event history rather than for the entire event history. If an actor learns a state model, keeping statistics for a tail of the event history makes a current state model less stable allowing the actor to try more state model variations. After trying state model variations with counting frequencies of state transitions performed, an application program can partially determinize a current state model by disallowing some less frequent state transitions and continue state model training. A state model fully determinized at the end of iterative partial determinization becomes a learned deterministic state model.

The file samples/cyc_stats_upd_hook.c in the package distribution installed to $prefix/share/qsmm/samples/cyc_stats_upd_hook.c contains:

  • an example redirection function cycle_stats_update_hook for intercepting updates of statistics on a cycle type to implement keeping cycle type statistics for an event history tail;
  • an example helper function relprob_user2 for calculating the relative probability of an output signal based on cycle type statistics for an event history tail;
  • the function setup_actor setting the functions cycle_stats_update_hook and relprob_user2 for a large actor.

All functions use an allocated instance of hook_param_s structure initially zeroed and passed to setup_actor. This section includes the source code of the three functions and associated macros and data structures.

To organize storing statistics on cycle types for a tail of the event history of a small actor associated with the large actor, cycle_stats_update_hook keeps a queue of records held in the instances of histev_cycle_s structure, where every record contains the following information about an update of statistics on a cycle type:

step

virtual time of the update designated as “modeling step”

spur

spur accumulated by the actor

tmc

continuous time of the update

sig_ngram

signal array encoding an action choice state that along with a cycle direction sig_cycle specifies the cycle type

sig_cycle

cycle direction that along with an action choice state encoded by sig_ngram specifies the cycle type

fq_delta

increment to the field fq of qsmm_cycle_s structure equal to a difference between a new value and old value passed to the redirection function

period_sum_d_delta

increment to the field period_sum_d of qsmm_cycle_s structure equal to a difference between a new value and old value passed to the redirection function

period_sum_c_delta

increments to continuous time in the field delta_sum in the elements of array of qsmm_cspval_s structures for continuous time types equal to differences between new values and old values passed to the redirection function

spur_delta_sum

increments to spur in the field delta_sum in the elements of array of qsmm_cspval_s structures for spur types equal to differences between new values and old values passed to the redirection function

The redirection function does the following:

  1. Prevents recursive calls to itself when calling the function qsmm_set_storage_cycle_stats to decrement statistics on cycle types.
  2. Removes too old records from the queue with decrementing statistics on cycle types specified by removed records and with decrementing spur accumulated by the actor according to the removed records. A removed record contains differences to statistics on the cycle type and differences to spur tracked by the actor relative to a previously added record. After removing the old records, storage contains statistics on cycle types for an event history tail, and the actor holds current spur values accumulated for the event history tail.
  3. Adds a new record to the queue.

An application program should keep the fields step_histev and nstep_histev in the instance of hook_param_s structure up-to-date while performing state model training. The field step_histev holds a modeling step index equal, for example, to the number of nondeterministic state transitions performed. The field nstep_histev holds the length of an event history tail in modeling steps. Calculating the length of an event history tail to keep statistics is out of scope of this section.

#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <qsmm/qsmm.h>


#define HISTEV_CYCLE_NSPUR    2  // number of spur types
#define HISTEV_CYCLE_NTIME    2  // number of continuous time types

#define HISTEV_CYCLE_NGRAM_SZ 4
    // length of action choice state n-grams of a small actor associated
    // with a large actor


#define GET_NSTEP_HISTEV(hook_param_p)                                    \
    ((long) ((hook_param_p)->nstep_histev+0.5))


#define ERREXIT(fmt, ...)                                                 \
    do {                                                                  \
        fprintf(stderr,fmt "\n", ## __VA_ARGS__);                         \
        goto Exit;                                                        \
    }                                                                     \
    while (0)


#define ERR_NOMEM()  ERREXIT("out of memory")


#define CHK_FAIL(func, ...)                                               \
    do {                                                                  \
        const int rc=func(__VA_ARGS__);                                   \
        if (rc<0) ERREXIT(#func ": %s", qsmm_err_str(rc));                \
    }                                                                     \
    while (0)


struct histev_cycle_s {

    long                  step;
        // modeling step

    long                  fq_delta;
        // increment of cycle type frequency

    long                  period_sum_d_delta;
        // increment of the sum of discrete time periods

    double                spur[HISTEV_CYCLE_NSPUR];
        // actor spur:
        // [ii] = spur with type `ii'

    double                tmc[HISTEV_CYCLE_NTIME];
        // continuous time:
        // [ii] = continuous time with type `ii'

    double                period_sum_c_delta[HISTEV_CYCLE_NTIME];
        // increments of the sums of continuous time periods:
        // [ii] = increment of the sum of periods of continuous
        //        time with type `ii'

    double                spur_delta_sum[HISTEV_CYCLE_NSPUR];
        // increments of the sums of spur increments:
        // [ii] = increment of the sum of spur increments for
        //        spur type `ii'

    qsmm_sig_t            sig_cycle;
        // cycle direction

    qsmm_sig_t            sig_ngram[HISTEV_CYCLE_NGRAM_SZ];
        // action choice state n-gram

    struct histev_cycle_s *nextp;
        // next event in the list;
        // special value:
        // ==NULL - this event is the last event in the list
};


struct hook_param_s {

    char                  in_cycle_update_hook;
        // cycle update hook execution indicator:
        // !=0 - cycle statistics update hook is being executed;
        // ==0 - not executed

    long                  step_histev;
        // modeling step

    double                nstep_histev;
        // number of modeling steps within the cycle event history window

    qsmm_actor_t          actor_small;
        // reference to a small actor corresponding to the environment
        // state identification engine

    struct histev_cycle_s *histev_cycle_head_p;
        // oldest event in the history of last cycle events;
        // special value:
        // ==NULL - history is empty

    struct histev_cycle_s *histev_cycle_tail_p;
        // newest event in the history of last cycle events;
        // special value:
        // ==NULL - history is empty
};


// The hook for calling on updating cycle type statistics.
// Returns: 0 = success; no return on failure.

static int
cycle_stats_update_hook(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,             // [ngram_sz]
    qsmm_sig_t sig_cycle,
    const struct qsmm_cycle_s *cycle_new_p,
    struct qsmm_cycle_s *cycle_result_p,
    const struct qsmm_cspval_s *cspval_new_p,  // [nspval]
    struct qsmm_cspval_s *cspval_result_p,     // [nspval]
    void *paramp
) {
    int result=-1;
    struct histev_cycle_s *histev_new_p=0;
    struct hook_param_s *const hook_param_p=paramp;
    if (hook_param_p->in_cycle_update_hook) {
        result=0;
        goto Exit;
    }
    hook_param_p->in_cycle_update_hook=1;
    const long step_beg=
        hook_param_p->step_histev-GET_NSTEP_HISTEV(hook_param_p);
    const qsmm_actor_t actor_small=hook_param_p->actor_small;
    const int nspur=qsmm_get_actor_nspur(actor_small),
        ntime=qsmm_get_actor_ntime(actor_small),
        nspval=qsmm_get_storage_nspval(storage);
    int ispur, itime;
    struct histev_cycle_s *histev_old_p;
    assert(ngram_sz==HISTEV_CYCLE_NGRAM_SZ);
    assert(nspur==HISTEV_CYCLE_NSPUR);
    assert(ntime==HISTEV_CYCLE_NTIME);
    assert(nspur+ntime==nspval);
    while ((histev_old_p=hook_param_p->histev_cycle_head_p) &&
           histev_old_p->step<step_beg) {
        const double *const spur_delta_sum_p=histev_old_p->spur_delta_sum;
        const qsmm_sig_t sig_cycle_old=histev_old_p->sig_cycle,
            *const sig_ngram_old_p=histev_old_p->sig_ngram;
        struct qsmm_cycle_s cycle;
        struct qsmm_cspval_s cspval[nspval];
        CHK_FAIL(qsmm_get_storage_cycle_stats, storage, ngram_sz,
                 sig_ngram_old_p, sig_cycle_old, &cycle, cspval);
        cycle.fq-=histev_old_p->fq_delta;
        cycle.period_sum_d-=histev_old_p->period_sum_d_delta;
        assert(cycle.fq>=0);
        assert(cycle.period_sum_d>=0);
        for (ispur=0; ispur<nspur; ispur++)
            cspval[ispur].delta_sum-=spur_delta_sum_p[ispur];
        for (itime=0; itime<ntime; itime++) {
            cspval[nspur+itime].delta_sum-=
                histev_old_p->period_sum_c_delta[itime];
            assert(cspval[nspur+itime].delta_sum>=0);
        }
        CHK_FAIL(qsmm_set_storage_cycle_stats, storage, ngram_sz,
                 sig_ngram_old_p, sig_cycle_old, &cycle, cspval);
        hook_param_p->histev_cycle_head_p=histev_old_p->nextp;
        free(histev_old_p);
    }
    if (!histev_old_p) hook_param_p->histev_cycle_tail_p=0;
    if (!(histev_new_p=calloc(1,sizeof(*histev_new_p)))) ERR_NOMEM();
    histev_new_p->step=hook_param_p->step_histev;
    histev_new_p->sig_cycle=sig_cycle;
    if (cycle_new_p) {
        histev_new_p->fq_delta=cycle_new_p->fq-cycle_result_p->fq;
        histev_new_p->period_sum_d_delta=cycle_new_p->period_sum_d-
                                         cycle_result_p->period_sum_d;
        assert(histev_new_p->fq_delta>=0);
        assert(histev_new_p->period_sum_d_delta>=0);
    }
    for (ispur=0; ispur<nspur; ispur++) {
        CHK_FAIL(qsmm_get_actor_spur, actor_small, ispur,
                 histev_new_p->spur+ispur);
        histev_new_p->spur_delta_sum[ispur]=
            cspval_new_p?cspval_new_p[ispur].delta_sum-
                         cspval_result_p[ispur].delta_sum:0;
    }
    for (itime=0; itime<ntime; itime++) {
        CHK_FAIL(qsmm_get_actor_time,
                 actor_small, itime, histev_new_p->tmc+itime);
        histev_new_p->period_sum_c_delta[itime]=
            cspval_new_p?cspval_new_p[nspur+itime].delta_sum-
                         cspval_result_p[nspur+itime].delta_sum:0;
        assert(histev_new_p->period_sum_c_delta[itime]>=0);
    }
    memmove(histev_new_p->sig_ngram, sig_ngram_p,
            ngram_sz*sizeof(*sig_ngram_p));
    if (hook_param_p->histev_cycle_tail_p) {
        assert(!hook_param_p->histev_cycle_tail_p->nextp);
        hook_param_p->histev_cycle_tail_p->nextp=histev_new_p;
    }
    else {
        assert(!hook_param_p->histev_cycle_head_p);
        hook_param_p->histev_cycle_head_p=histev_new_p;
    }
    hook_param_p->histev_cycle_tail_p=histev_new_p;
    histev_new_p=0;
    hook_param_p->in_cycle_update_hook=0;
    result=0;

Exit:
    if (histev_new_p) free(histev_new_p);
    if (result<0) exit(1);
    return result;
}


// The helper function for computing the relative probability of an
// output signal.

static double
relprob_user2(
    qsmm_actor_t actor,
    qsmm_sig_t sig_cycle,
    const struct qsmm_state_s *state_p,
    const struct qsmm_cycle_s *cycle_p,
    const struct qsmm_sspval_s *sspval_p,
    const struct qsmm_cspval_s *cspval_p,
    void *paramp
) {
    const long fq=cycle_p->fq;
    double result=0/0.0;
    if (fq<1) {
        result=0;
        goto Exit;
    }
    const struct histev_cycle_s *const histev_head_p=
        ((struct hook_param_s *) paramp)->histev_cycle_head_p;
    const int nspur=qsmm_get_actor_nspur(actor);
    double exp_arg=0;
    assert(histev_head_p);
    for (int ispur=0; ispur<nspur; ispur++) {
        int itime=-1;
        CHK_FAIL(qsmm_get_actor_spur_time,actor,ispur,&itime);
        assert(itime>=0);
        double spur_val=0, time_val=0;
        CHK_FAIL(qsmm_get_actor_spur,actor,ispur,&spur_val);
        CHK_FAIL(qsmm_get_actor_time,actor,itime,&time_val);
        spur_val-=histev_head_p->spur[ispur];
        time_val-=histev_head_p->tmc[itime];
        const double spur_delta_mean=time_val>0?spur_val/time_val:0;
        double spur_weight=0;
        CHK_FAIL(qsmm_get_actor_spur_weight,actor,ispur,&spur_weight);
        const double num=cspval_p[ispur].delta_sum,
            den=cspval_p[nspur+itime].delta_sum*fabs(spur_delta_mean);
        enum qsmm_spur_perception_e spur_perception;
        CHK_FAIL(qsmm_get_actor_spur_perception, actor,
                 ispur, &spur_perception);
        switch (spur_perception) {
            case QSMM_SPUR_PERCEPTION_NORMAL:
                if (den) exp_arg+=spur_weight*num/den;
                break;
            case QSMM_SPUR_PERCEPTION_INVERSE:
                if (num) exp_arg+=-spur_weight*den/num;
                break;
        }
    }
    assert(cycle_p->period_sum_d>0);
    exp_arg*=log(qsmm_get_actor_nsig_ctrl(actor))*cycle_p->period_sum_d/fq;
    result=exp_arg;

Exit:
    return result;
}


// Set up a hook for updating cycle type statistics and a helper function
// for computing the relative probability of an output signal for a
// large actor.
// Returns: 0 = success;
//         -1 = failure.

int
setup_actor(
    qsmm_actor_t actor_large,
    struct hook_param_s *hook_param_p
) {
    int result=-1;
    qsmm_set_actor_relprob_type(actor_large,QSMM_RELPROB_USER2);
    qsmm_set_actor_relprob_helper(actor_large,&relprob_user2,hook_param_p);
    const qsmm_actor_t actor_small=
        qsmm_get_actpair_actor(
            qsmm_get_actpair(qsmm_get_actor_large_model(actor_large)),
            QSMM_ENGINE_ENV);
    CHK_FAIL(qsmm_set_storage_cycle_update_hook,
             qsmm_get_actor_storage(actor_small),
             &cycle_stats_update_hook, hook_param_p);
    hook_param_p->actor_small=actor_small;
    hook_param_p->step_histev=0;
    result=0;

Exit:
    return result;
}

4 Multinode Model

Multinode model is the concept of using an individual actor or a pair of actors in multiple contexts where producing adaptive actions is necessary. The contexts might relate to the components of a system you develop or entities external to the system. The nodes of a multinode model are adaptive programmatic representations of the contexts. They provide learning capabilities to the system and the ability to produce actions based on learned interactions and can define preprogrammed behavior. A special case of multinode model is a single-node model.

Every node has a certain number of states. One of them is a current node state. A node possesses control when it performs interactions with other entities by executing the instructions of a possibly nondeterministic subroutine contained in the node. The execution of the subroutine we briefly call node execution. It results in changing a current node state. At present, QSMM supports not more than one node in a multinode model possessing control at any moment of time; in addition to that, a node can execute not more than one instruction at any time. A node can pass control to another node while executing an instruction at some location in the subroutine, and the other node can return control to that location afterwards.

A node learns something when the subroutine becomes more deterministic or stable. This added determinism affects subsequent interactions of the node with other entities.

Considering the sources of deterministic and stochastic behavior, their location, and their ability to influence each other gives answers to the questions “Which entity is choosing actions?” and “Is it easy for that entity to choose actions?” For example, a node can use a stochastic physical process, such as the interference of individual electrons, to produce random numbers for the subroutine to choose actions. If the node is not using a stochastic physical process, and hardware for executing the subroutine operates deterministically, then information the node receives from the environment may define the choice of actions.

Working with a multinode model begins with its preparation. It includes registering meta-classes for instructions executable by nodes and registering sets of instruction classes—different nodes can have different instruction sets. A multinode model learns and performs useful work during execution phase—the execution of nodes and transferring control between them. Various information about a multinode model is available at various points in its lifetime.


4.1 Principle of Operation

A schematic diagram of multinode model implementation is in Figure 4.1.

An environment state identification engine, instruction emitting engine, and instruction execution environment are main model components taking part in model execution.

The environment state identification engine is a small or large actor keeping an adaptive state model of an environment and identifying node states according to the model. This identification is a bidirectional process: the current state of a node depends on the state of the environment and needs identification; conversely, the node acts on the environment, and, therefore, the state of the environment depends on an identified node state. For a single-node model, its node corresponds to the entire environment. For a multinode model, a node corresponds to part of the environment.

Along with the adaptive state model, the environment state identification engine keeps the identifier of a currently executed node, the index of its previous state, the identifier of the last instruction or the last instruction sequence emitted by the instruction emitting engine, the outcome of that instruction or instruction sequence, an optional array of identifiers of look-ahead signals (see Setting Look-Ahead Signals), and, as an actor, it keeps current values of spur and continuous time. For a single-node model, the identifier of a currently executed node is always equal to 0. The structure of tuples encoding action choice states of the environment state identification engine is in Figure 4.2.

The environment state identification engine identifies the current state of a node based on its identifier, the previous state of the node, the identifier of the last instruction or the last instruction sequence emitted, the outcome of that instruction or instruction sequence, and optional look-ahead signals. The environment state identification engine sends the identifier of a currently executed node and the index of its identified state to the instruction emitting engine. The latter engine is a small or large actor keeping an adaptive model of emitting various assembler instructions and their sequences in various node states. As an actor, the instruction emitting engine keeps current values of spur and continuous time, and they can be different from current values of spur and continuous time for the environment state identification engine.

The structure of tuples encoding action choice states of the instruction emitting engine is in Figure 4.3. The instruction emitting engine selects an output signal encoding an assembler instruction or a sequence of assembler instructions. The identifier of a currently executed node and a current node state received from the environment state identification engine take part in selecting the output signal.

The instruction emitting engine sends a selected assembler instruction or a selected sequence of assembler instructions to the instruction execution environment for performing effective work and to the environment state identification engine for identifying the next node state. That instruction execution environment represents everything else in the multinode model, interacts with application logic or incorporates it, and is aware of all parameters of the environment state identification engine and instruction emitting engine. An assembler instruction or a sequence of assembler instructions returns an instruction outcome after execution. The instruction execution environment sends the outcome to the environment state identification engine for identifying the next node state.

The instruction execution environment keeps a node call stack for the execution of nodes to be similar to the execution of program subroutines (functions or procedures) calling each other and returning control to caller subroutines. An executed assembler instruction can push the identifier of a currently executed node and the index of its current state to the node call stack and transfer control to another node with resetting the current node state to the initial node state corresponding to the beginning of execution of a subroutine. The assembler instruction can also return control to a previously executed node by popping the identifier of the node and the index of its current state from the stack.

An assembler instruction can change look-ahead signals taking part in identifying the next node state and increment current values of spur and continuous time tracked by the environment state identification engine and instruction emitting engine.

multinode model implementation

Figure 4.1: multinode model implementation

action choice state of environment state identification engine

Figure 4.2: action choice state of environment state identification engine

action choice state of instruction emitting engine

Figure 4.3: action choice state of instruction emitting engine

A helpful feature of a multinode model is ability to convert internal data stored in its environment state identification engine and instruction emitting engine to a representation in the form of an assembler program (see Assembler Programs). One can think about this feature as automatic synthesis of an assembler program solving an assigned task.

An important point the developer should realize is that automatic program synthesis may work only if there exists a steady state model solving an assigned task. Steady state model is a model where states have predictable input from an environment.

Below there is a list of concepts for enabling the automatic synthesis of assembler programs.

Instruction meta-class

Represents an instruction name without taking into account optional instruction parameters following the instruction name after a whitespace character. The name of an instruction meta-class is the name of an instruction without including instruction parameters. Example:

move

This instruction meta-class might represent an instruction that moves an agent in an environment one step in a specific direction. The name of the instruction meta-class does not include a movement direction.

Individual instruction class

Represents an instruction name optionally followed by instruction parameters. Distinct strings, where every string consists of an instruction name and instruction parameters in canonical form (see Setting Text Instruction Parameters), identify distinct individual instruction classes. Example:

move north

This instruction class might represent an instruction that moves an agent in the environment one step in the north direction.

Instruction class sequence

A sequence of individual instruction classes. Example:

move west
move west
move south

This instruction class sequence might move an agent two steps in the west direction and then one step in the south direction.

Instruction outcome

An individual instruction class has a specific number of instruction outcomes. The outcome of a sequence of instructions is the outcome of the last instruction in the sequence.

The environment state identification engine uses the outcome of an emitted instruction or an emitted sequence of instructions to identify the next node state. The instruction emitting engine uses the next node state to select the next instruction or the next sequence of instructions.

For example, the instruction ‘move north’ as well as other movement instructions could return a bitmask of four bits (i.e. an integer number in the range 0 to 15) after performing a move. A bit of the bitmask equal to 0 could indicate that there was an obstacle in a corresponding direction, thus giving a piece of information to the agent about the configuration of an environment. It might also be useful to return special outcome 16 if there was an obstacle in a direction specified by an emitted instruction, and the obstacle disallowed the agent to move.

Instruction class set

Represents a set containing individual instruction classes and sequences of instruction classes along with their properties and is a class for nodes. For example, the instruction class set ‘walker’ intended for investigating an environment might contain the individual instruction classes

move north
move east
move south
move west

the instruction class sequence

move west
move west
move south

and the instruction class sequence

move north
move east

A node belonging to this node class might represent an agent investigating an environment.

Instruction instance

An instance of an instruction class in an assembler program. For example, in the assembler program fragment

        move north
        joe  14, return_back
        move north
        ...
return_back:
        move south
        ...

there are two instances of ‘move north’ instruction class.


4.2 Creating a Multinode Model

A handle of qsmm_t type refers to a multinode model. The function qsmm_create creates a multinode model according to specified initial parameters and returns its handle. The function qsmm_destroy destroys a multinode model specified by its handle. A number of functions fetch initial model parameters after creating a model. The handle of a multinode model can have a number of arbitrary pointers associated with it.

After creating an empty model, an application program should register instruction meta-classes and instruction class sets defining assembler instruction sets for model nodes. Instruction meta-classes specify instruction-centric model behavior. Instruction class sets specify node-centric model behavior. An instruction meta-class is an entity for an assembler instruction name. An individual instruction class belongs to an instruction meta-class, is a member of an instruction class set, and represents an assembler instruction with specific parameters. Every instruction meta-class requires providing an event handler function. An instruction class set can have an event handler function too.

After registering one or more instruction class sets, an application program should create nodes belonging to node classes represented by the instruction class sets. Every node has a numeric identifier, a state transition matrix maintained by the environment state identification engine, and an action emission matrix maintained by the instruction emitting engine. Both engines exist in a model instance scope holding model execution parameters. After creating a model instance, it may be necessary to override default parameters of actors representing the engines.


4.2.1 Creating a Handle

A model handle refers to a multinode model.

Data type: qsmm_t

This is a type for a model handle. It is a pointer, so variables of this type can be NULL. The function qsmm_create creates a new model and returns its handle. The function qsmm_destroy destroys an existing model addressed by a handle. You can pass a model handle to API functions taking an argument of qsmm_t type after the creation of a model and until its destruction.

Use the following functions to create and destroy a multinode model.

Function: int qsmm_create (const struct qsmm_desc_s *desc_p, qsmm_t *model_p)

This function creates a multinode model using parameters in *desc_p and stores a model handle in *model_p.

If model_p is NULL, the function only validates parameters in *desc_p.

The function returns a non-negative value on success or a negative error code on failure in creating a multinode model. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

Parameters in *desc_p are invalid.

QSMM_ERR_NOMEM

There was not enough memory to create a multinode model.

Function: void qsmm_destroy (qsmm_t model)

This function destroys a multinode model. You must not use model after its destruction. If model is NULL, the function has no effect.

The following enumeration contains an element denoting an environment state identification engine and an element denoting an instruction emitting engine. The structure qsmm_desc_s uses the enumeration for specifying engine parameters when creating a multinode model.

Enumeration: qsmm_engine_e

This enumeration specifies the type of a multinode model engine. The enumeration contains the following elements.

QSMM_ENGINE_ENV

Environment state identification engine

QSMM_ENGINE_IEE

Instruction emitting engine

QSMM_ENGINE_COUNT

The last element of this enumeration equal to the number of engine types

Below there is a description of a structure passed in *desc_p to the function qsmm_create.

Structure: qsmm_desc_s

This structure describes parameters for creating a multinode model by the function qsmm_create. The structure contains the following fields.

Field: char dont_use_instr_class_weights

A flag defining whether to set weights of output signals of the instruction emitting engine equal to weights of instruction classes specified by the functions qsmm_set_instr_class_weight and qsmm_set_instr_class_weight_by_name_f (see Setting Instruction Classes Weights, for function descriptions). Zero flag means to set the weights, and non-zero flag means not to set them. If the flag is non-zero, the two functions report QSMM_ERR_NOTSUP. If the field engine_desc[QSMM_ENGINE_IEE].is_determ or engine_desc[QSMM_ENGINE_IEE].is_large of this structure is non-zero, qsmm_create implicitly sets the flag to a non-zero value. Eliminating the need to set the weights speeds up model execution when the number of instruction classes in the instruction class set is large.

Field: int stack_sz_max

The maximum allowed number of frames in the node call stack. If the actual number of stack frames exceeds that value, the function qsmm_node_call_default reports QSMM_ERR_STACKOVR. If the maximum allowed number of stack frames is too large, a stack overflow may occur without reporting this error. This kind of stack overflow typically causes a segmentation fault. The value of this field must be positive.

Field: int ngram_env_la_sz

The length of a segment of extra signals in a signal list encoding an action choice state of the environment state identification engine. The extra signals take part in the identification of a current node state. See Setting Look-Ahead Signals, for more information on them. The node assembler does not support loading assembler programs into the nodes of a model with positive length of look-ahead signal segment. The value of this field must be non-negative.

Field: int compat

Compatibility level of algorithms. Must be equal to 3.

Field: qsmm_sig_t nnode_max

[New in QSMM 1.19] The maximum number of nodes. It must not exceed QSMM_SIG_MAX. If this field is equal to 0, qsmm_create uses value QSMM_SIG_MAX instead. Setting this field to 1 means to create a single-node model.

Field: qsmm_sig_t nsig_ngram_env_la

An upper bound on the identifier of every signal in the look-ahead signal segment with length specified in the field ngram_env_la_sz of this structure. Every identifier must be less than the upper bound. If the length is positive, the upper bound must also be positive. If the length is zero, the upper bound must also be zero.

Field: qsmm_rng_t rng

The handle of a random number generator the environment state identification engine and instruction emitting engine will use. See Random Number Generators, for how to create and destroy random number generators and perform other operations on them. If this field is NULL, qsmm_create creates an instance of default random number generator for use by both engines until model destruction.

Field: struct qsmm_pair_sig_s * range_sig_env_la_p

Ranges of signal identifiers in the look-ahead signal segment. The field ngram_env_la_sz of this structure specifies look-ahead signal segment length. The multinode model uses the ranges to check segment validity.

If range_sig_env_la_p is not NULL, the field must be the pointer to an array holding ngram_env_la_sz elements, where each element is a pair (see Creating an Actor, for a description of qsmm_pair_sig_s structure). Indices of the elements are indices of signal identifiers in the look-ahead signal segment. The fields first and second of each pair define a minimum value and maximum value for a corresponding signal identifier. The value of first must be less than or equal to the value of second. The value of second must be less than the value of nsig_ngram_env_la field of this structure. Setting range_sig_env_la_p to NULL means that every signal in the segment can lie in the range 0 (inclusive) to nsig_ngram_env_la (exclusive).

Field: struct qsmm_engine_desc_s engine_desc[QSMM_ENGINE_COUNT]

[New in QSMM 1.19] Parameters for creating the environment state identification engine and instruction emitting engine.

To improve compatibility with future versions of QSMM library, zero by the function memset an instance of qsmm_desc_s structure before setting its fields.

Below there is a description of a structure defining the type of elements of engine_desc array in the structure qsmm_desc_s.

Structure: qsmm_engine_desc_s

This structure describes parameters for creating an environment state identification engine or instruction emitting engine for a multinode model. The structure contains the following fields.

Field: char is_determ

If this field is non-zero, it imposes a restriction on assembler programs loadable into the nodes of a multinode model. This field can be non-zero only if the field large_desc_p of this structure is NULL.

For the environment state identification engine, the restriction is that assembler programs must define deterministic probability profiles for state transition matrices: for every triple comprised of a source node state, an individual instruction or instruction sequence emitted in the source node state, and an instruction outcome, the probability profiles must specify a single target state, that is, the selection of a target node state must be deterministic. In this mode the node assembler considers jprob instructions and choice instruction blocks in an assembler program as specifying nondeterministic instruction emissions unless the action emission matrix is also deterministic. You can omit marking node states by stt instructions, as node states implicitly begin just before blocks of jprob instructions and choice instruction blocks, just before individual user or mixed-type instructions without probabilistic jumps to them, and just before sequences of user or mixed-type instructions without probabilistic jumps to them.

For the instruction emitting engine, the restriction is that assembler programs must define deterministic probability profiles for action emission matrices: for every node state, the probability profiles must specify a single instruction or a single instruction sequence emitted in the node state, that is, the selection of an individual instruction or instruction sequence must be deterministic. In this mode the node assembler considers jprob instructions and choice instruction blocks in an assembler program as specifying nondeterministic state transitions unless the state transition matrix is also deterministic. You can omit marking node states by stt instructions, as node states implicitly begin just before individual user or mixed-type instructions and sequences of user or mixed-type instructions. If you use stt instructions, you cannot place them just before jprob instructions and choice instruction blocks.

Field: int nspur

The number of spur types. This field must have a non-negative value.

Field: int ntime

The number of continuous time types. This field must have a non-negative value.

Field: const struct qsmm_actor_large_desc_s * large_desc_p

The parameters of a large actor representing the environment state identification engine or instruction emitting engine. A non-NULL value of this field means to use a large actor for the engine. See Creating an Actor, for a description of qsmm_actor_large_desc_s structure. The function qsmm_create copies a structure instance referenced by this field to an internal structure. This field can be non-NULL only if the field is_determ of this structure is zero.

You can retrieve some initial model parameters later by the following functions.

Function: int qsmm_get_use_instr_class_weights (qsmm_t model)

This function returns a positive value if the function qsmm_node_call_default sets weights of output signals of the instruction emitting engine of a multinode model equal to weights of instruction classes of a currently executed node, and the functions qsmm_set_instr_class_weight and qsmm_set_instr_class_weight_by_name_f support setting weights of instruction classes. If qsmm_node_call_default does not set the weights and qsmm_set_instr_class_weight and qsmm_set_instr_class_weight_by_name_f report QSMM_ERR_NOTSUP, qsmm_get_use_instr_class_weights returns 0. A value returned by qsmm_get_use_instr_class_weights may depend on the field dont_use_instr_class_weights of qsmm_desc_s structure passed to the function qsmm_create when creating the multinode model. A returned value is always non-negative.

Function: int qsmm_get_stack_sz_max (qsmm_t model)

This function returns the maximum allowed number of frames in the node call stack of a multinode model. It is a number specified in the field stack_sz_max of qsmm_desc_s structure passed to the function qsmm_create when creating the multinode model. A returned value is always positive.

Function: int qsmm_get_ngram_env_la_sz (qsmm_t model)

This function returns the length of look-ahead signal segment of a multinode model. It is length specified in the field ngram_env_la_sz of qsmm_desc_s structure passed to the function qsmm_create when creating the multinode model. A returned value is always non-negative.

Function: qsmm_sig_t qsmm_get_nsig_ngram_env_la (qsmm_t model)

This function returns an upper bound on the identifier of every signal in the look-ahead signal segment of a multinode model. It is a number specified in the field nsig_ngram_env_la of qsmm_desc_s structure passed to the function qsmm_create when creating the multinode model.

Function: const struct qsmm_actor_large_desc_s * qsmm_get_engine_desc (qsmm_t model, enum qsmm_engine_e engine_type)

This function returns the parameters of an engine of a multinode model stored in its internal structure. The field engine_desc of qsmm_desc_s structure passed to the function qsmm_create when creating the multinode model specifies the parameters. The argument engine_type selects the environment state identification engine or instruction emitting engine. If engine_type is incorrect, the function returns NULL.


4.2.2 Defining Instruction Meta-Classes

An instruction meta-class represents an assembler instruction with a specific name and encapsulates logic associated with the instruction. The name of an instruction meta-class is the name of an assembler instruction. Various individual instruction classes derived from the instruction meta-class represent the assembler instruction followed by various parameter strings.

Every instruction meta-class has an event handler function processing the initialization of individual instruction classes derived from the instruction meta-class and the invocation of instructions belonging to the instruction classes during model execution. By default, the name of this event handler function is the name of an instruction meta-class.

An individual instruction class has various identifiers including binary parameters and text parameters convertible from the binary parameters. An instruction meta-class name along with the text parameters converted to canonical form according to a set of rules, such as removing all whitespace characters from a parameter string, make up an instruction class name for identifying instructions belonging to the instruction class in assembler programs.

The initialization of an individual instruction class by the event handler function of an instruction meta-class typically includes setting the text parameters and the number of instruction outcomes. An invoked assembler instruction sends its outcome to the environment state identification engine to affect the identification of the next state of an assembler program encoding an environment.


4.2.2.1 Function Declaration

You should declare or define an instruction meta-class using the following macro.

Macro: QSMM_INSTR_META_CLASS (instr_meta_class_name)

This macro declares the prototype of a function named instr_meta_class_name that represents an instruction meta-class with the same name and is the event handler function of the instruction meta-class. You can prepend the macro with the static keyword to declare or define a static function. A pointer to the function has the type qsmm_instr_meta_class_func_t. The function has the return type int and the following arguments.

Function argument: qsmm_t qsmm

The handle of a multinode model containing the instruction meta-class.

Function argument: qsmm_mehcall_t mehcall

The parameters of a call to the event handler function. See Event Handler Call Parameters, for a description of parameters of a model event handler call.

For example, you can declare the prototype of a static function representing the instruction meta-class ‘move’ as follows:

static QSMM_INSTR_META_CLASS(move);

Define the static function ‘move’ as follows:

static QSMM_INSTR_META_CLASS(move) {
    ...
}
Data type: qsmm_instr_meta_class_func_t

This is a type for a pointer to the event handler function of an instruction meta-class. See above for the description of non-deprecated arguments of that event handler function. To improve compatibility with future versions of QSMM library, avoid declaring the event handler function explicitly—use the macro QSMM_INSTR_META_CLASS instead.


4.2.2.2 Event Handling

The event handler function of an instruction meta-class can process events with types represented by macros listed below. Event type is available in mehcall->evt, where mehcall is an argument of that event handler function.

Macro: QSMM_EVT_ENT_INIT

Instruction meta-class initialization. The function qsmm_reg_instr_meta_class called to register the instruction meta-class sends this event.

Macro: QSMM_EVT_ENT_DONE

Instruction meta-class uninitialization. The function qsmm_destroy called to destroy the multinode model sends this event to all registered instruction meta-class event handlers.

This event can trigger deallocating resources allocated on preparing the multinode model or processing the event QSMM_EVT_ENT_INIT.

Macro: QSMM_EVT_INSTR_CLASS_INIT

Instruction class initialization. The function qsmm_reg_instr_class_v2 (see Registering Instruction Classes) called to register an individual instruction class derived from the instruction meta-class sends this event.

Handling this event typically includes the following operations:

  • setting the text parameters of the instruction class by the function qsmm_set_mehcall_instr_param_f if the instruction has parameters (see Setting Text Instruction Parameters);
  • setting the number of instruction outcomes by the function qsmm_set_mehcall_noutcome if the instruction has more than one outcome or should behave depending on the outcome of the previous instruction invoked (see Setting the Number of Instruction Outcomes).
Macro: QSMM_EVT_INSTR_CLASS_DONE

Instruction class uninitialization. The function qsmm_destroy called to destroy the multinode model sends this event to instruction meta-class event handlers for individual instruction classes registered by the function qsmm_reg_instr_class_v2 and then sends the event QSMM_EVT_ENT_DONE to the event handlers.

This event can trigger the uninitialization of binary instruction class parameters (see Accessing Binary Instruction Parameters) and the deallocation of additional resources associated with the instruction class allocated on processing the event QSMM_EVT_INSTR_CLASS_INIT.

Macro: QSMM_EVT_ENGINE_INIT

Model instance initialization. The function qsmm_engine_create called to create the model instance sends this event to all registered instruction meta-class event handlers at the end of execution of that function.

Macro: QSMM_EVT_ENGINE_DONE

Model instance uninitialization. The function qsmm_engine_destroy called to destroy the model instance sends this event to all registered instruction meta-class event handlers at the beginning of execution of that function in reverse order relative to the order of sending events QSMM_EVT_ENGINE_INIT. The function qsmm_engine_create calls qsmm_engine_destroy implicitly when recreating the model instance. The function qsmm_destroy calls qsmm_engine_destroy implicitly when destroying the multinode model.

This event can trigger deallocating resources allocated on preparing the model instance or processing the event QSMM_EVT_ENGINE_INIT.

Macro: QSMM_EVT_ACTIVATE

Instruction invocation. See Handling Instruction Invocation. On emitting an individual instruction class by the instruction emitting engine, the function qsmm_node_call_default sends this event to the event handler of instruction meta-class of the instruction class. On emitting an instruction class sequence, qsmm_node_call_default sends this event to instruction meta-class event handlers for all instruction classes in the sequence.

On successful completion, the event handler function shall return a non-negative value. A specific non-negative value has no effect on model operation. On error, the event handler function shall return a negative value. This negative value causes the invocation of an error handler function with passing QSMM_ERR_EVTHNDLR to it if the model has an error handler set.


4.2.2.3 Registering the Function

Use the following macro to register the event handler function of an instruction meta-class.

Macro: QSMM_REG_INSTR_META_CLASS_PARAM (model, instr_meta_class_name, paramp)

This macro registers an instruction meta-class instr_meta_class_name for a multinode model. The event handler function of the instruction meta-class previously declared or defined by the macro QSMM_INSTR_META_CLASS should have the name instr_meta_class_name. The event handler function will be receiving a parameter paramp in mehcall->param_p on all events, where mehcall is an argument of that event handler function.

The macro QSMM_REG_INSTR_META_CLASS_PARAM expands to:

qsmm_reg_instr_meta_class((model), #instr_meta_class_name,
                          &instr_meta_class_name, (paramp))

Below there is the description of a function called by the macro QSMM_REG_INSTR_META_CLASS_PARAM.

Function: int qsmm_reg_instr_meta_class (qsmm_t model, const char *instr_meta_class_name, qsmm_instr_meta_class_func_t instr_meta_class_func, void *paramp)

This function registers an instruction meta-class instr_meta_class_name for a multinode model. A function instr_meta_class_func will be the event handler of the instruction meta-class. The event handler will be receiving a parameter paramp in mehcall->param_p on all events, where mehcall is an argument of that event handler.

A string instr_meta_class_name must begin with an English letter or underscore followed by zero or more characters where each character is an English letter, decimal digit, or underscore.

After registering an instruction meta-class, the function sends the event QSMM_EVT_ENT_INIT to the event handler, and it can perform the initialization of the instruction meta-class.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The string instr_meta_class_name has invalid format.

QSMM_ERR_EXIST

A program has already registered an instruction meta-class or instruction class set named instr_meta_class_name in the multinode model.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to get a pointer to the event handler of an instruction meta-class and the user parameter of that event handler.

Function: int qsmm_get_instr_meta_class_handler (qsmm_t model, const char *instr_meta_class_name, qsmm_instr_meta_class_func_t *instr_meta_class_func_p, void **param_pp)

This function retrieves the parameters of the event handler of an instruction meta-class instr_meta_class_name registered for a multinode model. If instr_meta_class_func_p is not NULL, the function sets *instr_meta_class_func_p to a pointer to that event handler. If param_pp is not NULL, the function sets *param_pp to a parameter of the event handler passed in mehcall->param_p on all events, where mehcall is an argument of that event handler.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction meta-class instr_meta_class_name not found.

QSMM_ERR_TYPE

An entity named instr_meta_class_name is not an instruction meta-class. The entity is an instruction class set.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.2.2.4 Instruction Class Identifiers

An individual instruction class has the following identifiers unique in various scopes.

  • Binary parameters. This is the encoded form of parameters of an individual instruction class.

    The function qsmm_reg_instr_class_v2 (see Registering Instruction Classes) registers an individual instruction class and sets its binary parameters. That function sends an event QSMM_EVT_INSTR_CLASS_INIT to the event handler of a corresponding instruction meta-class. The event can set the text parameters of the instruction class by the function qsmm_set_mehcall_instr_param_f (see Setting Text Instruction Parameters) based on the binary parameters. An event QSMM_EVT_INSTR_CLASS_DONE sent on destroying the instruction class can uninitialize its binary parameters if they address allocated memory blocks or reference other resources.

    An event QSMM_EVT_ACTIVATE has access to the binary parameters of an individual instruction class to determine how to handle the invocation of an assembler instruction belonging to the instruction class. See Accessing Binary Instruction Parameters, for how to access the binary parameters of an individual instruction class on processing events QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, and QSMM_EVT_ACTIVATE.

  • Text parameters. This is the decoded form of parameters of an individual instruction class necessary for identifying instructions belonging to the instruction class in assembler programs. The text parameters have a canonical form obtained by applying a set of rules to a parameter string, such as removing all whitespace characters from it.

    The function qsmm_set_mehcall_instr_param_f (see Setting Text Instruction Parameters) called on processing an event QSMM_EVT_INSTR_CLASS_INIT usually sets the text parameters of an individual instruction class based on its binary parameters. That function converts the text parameters to the canonical form.

  • Name. An instruction meta-class name, the space character, and text instruction class parameters in canonical form make up an instruction class name. This name is an assembler instruction with parameters. If an individual instruction class does not have text parameters, the assembler instruction is solely the name of the instruction meta-class.
  • Index. The ordinal number of an instruction class in an instruction class set (acting as an instruction class list in this context). The function qsmm_reg_instr_class_v2 returns that ordinal number after registering an individual instruction class. API functions provide access to various parameters of an individual instruction class by its index.

    An instruction class index is the identifier of an output signal of the instruction emitting engine. Emitting the output signal corresponds to emitting an assembler instruction belonging to the instruction class. A list of signal identifiers encoding an action choice state of the environment state identification engine includes the output signal as the index of the last emitted instruction. See Figure 4.2, for the structure of the list of signal identifiers.

The following tuples containing instruction class identifiers are unique in various scopes of a multinode model.

Tuple or IdentifierScope of Uniqueness
<instruction meta-class name, binary instruction class parameters>instruction class set
<instruction class set name, binary instruction class parameters>instruction meta-class
instruction class nameinstruction class set
instruction class indexinstruction class set

An instruction class index identifies an individual instruction class or instruction class sequence. The function qsmm_reg_instr_class_seq (see Instruction Class Sequences) returns an instruction class index for an instruction class sequence after registering it in an instruction class set. If an output signal of an instruction emitting engine is an instruction class index identifying an instruction class sequence, emitting the output signal corresponds to emitting a sequence of assembler instructions with the same effect as emitting individual assembler instructions comprising the sequence. A list of signal identifiers encoding an action choice state of the environment state identification engine includes the output signal as the index of the last emitted instruction sequence.

The following function retrieves the name of an instruction meta-class from its event handler function. The function might be useful when multiple instruction meta-classes share the same event handler function.

Function: int qsmm_get_mehcall_instr_meta_class (qsmm_mehcall_t mehcall, const char **instr_meta_class_name_pp)

This function retrieves the name of an instruction meta-class associated with an event sent to an instruction meta-class event handler, where mehcall is an argument of the event handler passing information about the event. If instr_meta_class_name_pp is not NULL, the function sets *instr_meta_class_name_pp to the name of the instruction meta-class.

On success, the function returns a non-negative value. If the context of calling the function is not the event handler of an instruction meta-class, the function returns negative error code QSMM_ERR_UNTIMELY.

The function qsmm_reg_instr_class_v2 registers an individual instruction class as belonging to an instruction class set. Use the function described below to get the name of the instruction class set when processing an event by the event handler of instruction meta-class of the instruction class. You can also use this function to get the name of the instruction class set when processing an event by the event handler of the instruction class set.

Function: int qsmm_get_mehcall_instr_class_set (qsmm_mehcall_t mehcall, const char **instr_class_set_name_pp)

This function retrieves the name of an instruction class set associated with an event sent to the event handler of an instruction meta-class or the instruction class set, where mehcall is an argument of that event handler passing information about the event. If instr_class_set_name_pp is not NULL, the function sets *instr_class_set_name_pp to the name of the instruction class set.

If the event handler of an instruction meta-class calls this function while processing an event QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, or QSMM_EVT_ACTIVATE, the function retrieves the name of an instruction class set containing an individual instruction class associated with the event and derived from the instruction meta-class. If the event handler of an instruction class set calls this function, it retrieves the name of the instruction class set.

On success, the function returns a non-negative value. If the context of calling the function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, or QSMM_EVT_ACTIVATE and not the event handler of an instruction class set, the function returns negative error code QSMM_ERR_UNTIMELY.


4.2.2.5 Accessing Binary Instruction Parameters

The function qsmm_reg_instr_class_v2 registers an individual instruction class and sets its binary parameters. The purpose of the following function is to fetch the binary parameters to a buffer by the event handler of an instruction meta-class. The buffer might be a variable or a structure instance.

Function: int qsmm_get_mehcall_instr_param_bin (qsmm_mehcall_t mehcall, size_t buf_sz, size_t *param_sz_p, void *bufp)

This function fetches the binary parameters of an individual instruction class associated with an event sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. The function supports events QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, and QSMM_EVT_ACTIVATE.

If buf_sz is not (size_t) -1, and bufp is not NULL, the function copies the binary parameters to a buffer bufp with size buf_sz bytes. In this case, buf_sz must be greater than or equal to the size of binary parameters specified when registering the instruction class by the function qsmm_reg_instr_class_v2. If buf_sz is greater than the size of binary parameters, qsmm_get_mehcall_instr_param_bin leaves intact remaining content of bufp.

If param_sz_p is not NULL, this function sets *param_sz_p equal to the size of binary parameters. You can call the function with a non-NULL param_sz_p, buf_sz equal to (size_t) -1, and bufp equal to NULL for retrieving the size of binary parameters.

On success, the function returns a positive value if the instruction class has binary parameters (i.e. their size is positive) or returns 0 if the instruction class does not have binary parameters (i.e. their size is 0). On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument buf_sz is not equal to (size_t) -1 and is less than the size of binary parameters specified when registering the instruction class by qsmm_reg_instr_class_v2.

QSMM_ERR_UNTIMELY

The context of calling this function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, or QSMM_EVT_ACTIVATE.

Because the binary parameters of an individual instruction class are necessary when processing multiple event types, it is reasonable to fetch the binary parameters at the beginning of an event handler on processing the events. To prevent reporting QSMM_ERR_UNTIMELY along with a possible invocation of a model error handler because of an inappropriate event type, use the following macro to check if the type of an event is appropriate to call the function qsmm_get_mehcall_instr_param_bin.

Macro: QSMM_HAS_INSTR_CLASS (evt)

This macro expands to:

((evt)==QSMM_EVT_INSTR_CLASS_INIT ||
 (evt)==QSMM_EVT_INSTR_CLASS_DONE ||
 (evt)==QSMM_EVT_ACTIVATE)

The purpose of this macro is to check whether an event with type evt has an associated individual instruction class, and it is safe to call the function qsmm_get_mehcall_instr_param_bin and other functions that use an instruction class context.

For example, to fetch the binary parameters of an individual instruction class at the beginning of event handler of ‘move’ instruction meta-class, declare an enumeration for possible movement directions and define the instruction meta-class as follows:

enum direct_e {
    DIRECT_NORTH,  // move one step up
    DIRECT_EAST,   // move one step right
    DIRECT_SOUTH,  // move one step down
    DIRECT_WEST,   // move one step left
    DIRECT_COUNT   // number of movement directions
};

...

static QSMM_INSTR_META_CLASS(move) {
    enum direct_e direct=DIRECT_COUNT;
    if (QSMM_HAS_INSTR_CLASS(mehcall->evt))
        qsmm_get_mehcall_instr_param_bin(
            mehcall, sizeof(direct), 0, &direct);
    ...
}

4.2.2.6 Setting Text Instruction Parameters

If an individual instruction class has text parameters, the event handler of its instruction meta-class must set them on processing an event QSMM_EVT_INSTR_CLASS_INIT. Use the following functions to set the text parameters.

Function: int qsmm_set_mehcall_instr_param_f (qsmm_mehcall_t mehcall, const char *fmt, ...)
Function: int qsmm_set_mehcall_instr_param_fv (qsmm_mehcall_t mehcall, const char *fmt, va_list ap)

The functions set the text parameters of an individual instruction class associated with an event QSMM_EVT_INSTR_CLASS_INIT sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. The function qsmm_set_mehcall_instr_param_f formats the text parameters according to the argument fmt and subsequent arguments similarly to the function printf. The function qsmm_set_mehcall_instr_param_fv formats the text parameters according to the arguments fmt and ap similarly to the function vprintf. After formatting, the functions convert the text parameters to a canonical form.

The functions return a non-negative value on success or a negative error code on failure. Currently, the functions can return the following error codes.

QSMM_ERR_INVAL

The text parameters have invalid format.

QSMM_ERR_UNTIMELY

The context of calling this function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT.

QSMM_ERR_ILSEQ

Unable to convert the text parameters to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

For example, the following code block sets the text parameters of an individual instruction class derived from the instruction meta-class ‘move’:

const char *ccp=0;
switch (direct) {
    case DIRECT_NORTH: ccp="north"; break;
    case DIRECT_EAST:  ccp="east";  break;
    case DIRECT_SOUTH: ccp="south"; break;
    case DIRECT_WEST:  ccp="west";  break;
}
if (ccp) qsmm_set_mehcall_instr_param_f(mehcall,"%s",ccp);

A call to qsmm_get_mehcall_instr_param_bin can retrieve the content of direct earlier in the event handler (see the example in Accessing Binary Instruction Parameters).

String Literals

The text parameters of an individual instruction class can contain string literals. You must enclose them in double quotes.

The character ‘\’ within a string literal is the escape character. A three-digit octal character code, ‘x’ and a two-digit hexadecimal character code, or the character ‘a’, ‘b’, ‘f’, ‘n’, ‘r’, ‘t’, ‘v’, ‘'’, ‘"’, or ‘\’ can follow ‘\’. The meaning of a resulting character sequence is the same as in the C programming language.

Canonical Form

The function qsmm_set_mehcall_instr_param_f converts the text parameters of an individual instruction class to a canonical form. All instruction classes derived from an instruction meta-class and contained in an instruction class set have distinct text parameters in the canonical form. The process of converting the text parameters to the canonical form consists of the following steps:

  1. Convert a source string to a wide string according to a current locale.
  2. Discard as a comment all characters in the wide string starting from the first character L;’ outside a string literal.
  3. Remove all whitespace characters outside string literals.
  4. Reformat all string literals by parsing them to arrays of wide characters and formatting the arrays according to the following rules:
    1. Replace the wide characters L\a’, L\b’, L\f’, L\n’, L\r’, L\t’, L\v’, L"’, and L\\’ with the corresponding escape sequences.
    2. Replace other wide characters with codes less than 32 with corresponding octal escape sequences.
    3. Copy all other wide characters to the formatted string as is.
    4. Enclose a resulting formatted string in double quotes.

Use the function described below to retrieve in the event handler of an instruction meta-class the text parameters of an individual instruction class in the canonical form.

Function: int qsmm_get_mehcall_instr_param_str (qsmm_mehcall_t mehcall, const char **param_str_pp)

This function fetches the text parameters of an individual instruction class associated with an event sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. The function supports events QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, and QSMM_EVT_ACTIVATE.

If param_str_pp is not NULL, the function sets *param_str_pp to the text parameters in the canonical form. A pointer returned in *param_str_pp is valid until the next call to this function or the function qsmm_get_instr_class_param_str (see Registering Instruction Classes) for the instruction class.

On success, qsmm_get_mehcall_instr_param_str returns a positive value if the instruction class has (non-empty) text parameters or returns 0 if the instruction class does not have text parameters (i.e. has empty text parameters). On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The context of calling this function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, or QSMM_EVT_ACTIVATE.

QSMM_ERR_ILSEQ

Unable to convert the text parameters in the canonical form to a multibyte string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.2.2.7 Setting the Number of Instruction Outcomes

An individual instruction class has a specific number of instruction outcomes. An instruction belonging to the instruction class can return one of them. A returned outcome may affect further execution of an assembler program.

The number of instruction outcomes is non-negative. Special value 0 indicates that an instruction may analyze the outcome of the previous instruction invoked, return that outcome as its own outcome, or return the outcome equal to a non-negative value less than the maximum number of outcomes of all instruction classes in the instruction class set. The default number of outcomes is 1.

The purpose of the following function is to set the number of instruction outcomes on processing an event QSMM_EVT_INSTR_CLASS_INIT by the event handler of an instruction meta-class.

Function: int qsmm_set_mehcall_noutcome (qsmm_mehcall_t mehcall, qsmm_sig_t noutcome)

This function sets to noutcome the number of outcomes of an individual instruction class associated with an event QSMM_EVT_INSTR_CLASS_INIT sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument noutcome is greater than QSMM_SIG_MAX.

QSMM_ERR_UNTIMELY

The context of calling this function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT.

Use the following function to get the number of outcomes of an individual instruction class associated with an event processed by the event handler of an instruction meta-class.

Function: int qsmm_get_mehcall_noutcome (qsmm_mehcall_t mehcall, qsmm_sig_t *noutcome_p)

This function retrieves the number of outcomes of an individual instruction class associated with an event sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. The function supports events QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, and QSMM_EVT_ACTIVATE. If noutcome_p is not NULL, the function sets *noutcome_p to a retrieved number of outcomes.

On success, the function returns a non-negative value:

>1

instruction class has multiple outcomes;

1

instruction class has single outcome 0;

0

instruction class can analyze the outcome of the previous instruction invoked and return an outcome less than the maximum number of outcomes of all instruction classes in the instruction class set; in this case, the retrieved number of outcomes is equal to 0.

If the context of calling this function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_INSTR_CLASS_INIT, QSMM_EVT_INSTR_CLASS_DONE, or QSMM_EVT_ACTIVATE, the function returns negative error code QSMM_ERR_UNTIMELY.


4.2.2.8 Function Layout

A template for the event handler of an instruction meta-class:

QSMM_INSTR_META_CLASS(instr_meta_class_name) {
    struct ic_param_s ic_param;
        // structure "ic_param_s" is for holding the binary parameters of
        // an individual instruction class
    if (QSMM_HAS_INSTR_CLASS(mehcall->evt))
        qsmm_get_mehcall_instr_param_bin(
            mehcall, sizeof(ic_param), 0, &ic_param);
                // fetch the binary parameters of an individual
                // instruction class
    switch (mehcall->evt) {
        case QSMM_EVT_INSTR_CLASS_INIT:
            qsmm_set_mehcall_instr_param_f(
                mehcall, fmt, ic_param.field, ...);
                    // set the text parameters of an individual
                    // instruction class
            qsmm_set_mehcall_noutcome(mehcall,noutcome);
                // set the number of outcomes of the instruction class if
                // that number is not equal to 1
            break;
        case QSMM_EVT_INSTR_CLASS_DONE:
            // TODO: deallocate the fields of "ic_param_s" (held in
            //       "ic_param") allocated before a call to
            //       "qsmm_reg_instr_class_v2".
            break;
        case QSMM_EVT_ACTIVATE:
            // TODO: handle the invocation of an instruction with binary
            //       parameters held in "ic_param".
            break;
        case QSMM_EVT_ENT_INIT:
        case QSMM_EVT_ENT_DONE:
        case QSMM_EVT_ENGINE_INIT:
        case QSMM_EVT_ENGINE_DONE:
            // TODO: optionally handle the events.
            break;
    }
    return 0;
}

4.2.3 Defining Instruction Class Sets

An instruction class set is both a container of instruction classes and a node class. An instruction class set defines an assembler instruction set for nodes belonging to the node class and specifies associated model behavior.

A name and event handler function specify an instruction class set. By default, the name of this event handler function is the name of an instruction class set.

The event handler function can processes transferring control to the nodes of a node class represented by the instruction class set and returning control from the nodes during model execution. Since QSMM 1.19, you can define an instruction class set without an event handler function.

The initialization of an instruction class set typically includes adding instruction classes to it.


4.2.3.1 Function Declaration

If an instruction class set has an event handler function, you normally declare or define the instruction class set using the following macro.

Macro: QSMM_INSTR_CLASS_SET (instr_class_set_name)

This macro declares the prototype of a function named instr_class_set_name that represents an instruction class set with the same name and is the event handler function of the instruction class set. You can prepend the macro with the static keyword to declare or define a static function. A pointer to the function has the type qsmm_instr_class_set_func_t. The function has the return type int and the following arguments.

Function argument: qsmm_t qsmm

The handle of a multinode model containing the instruction class set.

Function argument: qsmm_mehcall_t mehcall

The parameters of a call to the event handler function. See Event Handler Call Parameters, for a description of parameters of a model event handler call.

For example, you can declare the prototype of a static function representing the instruction class set ‘walker’ as follows:

static QSMM_INSTR_CLASS_SET(walker);

Define the static function ‘walker’ as follows:

static QSMM_INSTR_CLASS_SET(walker) {
    ...
}
Data type: qsmm_instr_class_set_func_t

This is a type for a pointer to the event handler function of an instruction class set. See above for the description of non-deprecated arguments of that event handler function. To improve compatibility with future versions of QSMM library, avoid declaring the event handler function explicitly—use the macro QSMM_INSTR_CLASS_SET instead.


4.2.3.2 Event Handling

The event handler function of an instruction class set can process events with types represented by macros listed below. Event type is available in mehcall->evt, where mehcall is an argument of that event handler function.

Macro: QSMM_EVT_ENT_INIT

Instruction class set initialization. The function qsmm_reg_instr_class_set called to register the instruction class set sends this event if the instruction class set has an event handler function.

This event can trigger the following operations:

  1. Register individual instruction classes belonging to the instruction class set by the macros QSMM_REG_INSTR_CLASS and QSMM_REG_INSTR_CLASS_PARAM. See Registering Instruction Classes.
  2. Register controlled probability variables by the macro QSMM_REG_VAR_PROB. See Controlled Variables.
  3. Create nodes belonging to the node class by the function qsmm_node_create_v2 or macro QSMM_NODE_CREATE. See Creating Nodes.
  4. Associate user parameters with created nodes by the function qsmm_set_node_ptr. See Associating Parameters with a Model.

This event can also trigger initial assignments to variables and allocating resources used by the instruction class set for all model runs.

It might be convenient to perform the above operations outside of event handler function after calling qsmm_reg_instr_class_set.

Macro: QSMM_EVT_ENT_DONE

Instruction class set uninitialization. The function qsmm_destroy called to destroy the multinode model sends this event to all registered event handlers of instruction class sets.

This event can trigger deallocating resources allocated on preparing the multinode model or processing the event QSMM_EVT_ENT_INIT.

Macro: QSMM_EVT_ENGINE_INIT

Model instance initialization. The function qsmm_engine_create called to create the model instance sends this event to all registered event handlers of instruction class sets at the end of execution of that function.

This event can trigger the following operations:

  1. Set parameters of actors representing the environment state identification engine and instruction emitting engine. See Creating the Model Instance.
  2. Load assembler programs into nodes by the function qsmm_node_asm. See Loading a Parsed Program into a Node.
  3. Clone node probability profiles by the function qsmm_node_profile_clone. See Cloning the Probability Profile.
  4. Clone node probability profiles in deferred mode by the function qsmm_set_node_profile_source. See Memory Efficient Cloning the Probability Profile.

This event can also trigger initial assignments to variables and allocating resources used by the instruction class set for a current model run.

It might be convenient to perform the above operations outside of event handler function after calling qsmm_engine_create.

Macro: QSMM_EVT_ENGINE_DONE

Model instance uninitialization. The function qsmm_engine_destroy called to destroy the model instance sends this event to all registered event handlers of instruction class sets at the beginning of execution of that function in reverse order relative to the order of sending events QSMM_EVT_ENGINE_INIT. The function qsmm_engine_create calls qsmm_engine_destroy implicitly when recreating the model instance. The function qsmm_destroy calls qsmm_engine_destroy implicitly when destroying the multinode model.

This event can trigger accumulating statistics collected during a current model run and deallocating resources allocated on processing the event QSMM_EVT_ENGINE_INIT.

Macro: QSMM_EVT_NODE_ENTER

Transferring control to a node belonging to a node class represented by the instruction class set. The function qsmm_node_call_default sends this event on calling a node. The event handler receives a node identifier via mehcall->node and the user parameter of qsmm_node_call_default via mehcall->param_p. Before sending this event to the event handler, qsmm_node_call_default creates a frame in the node call stack comprised of a user frame if its size is positive and a system frame.

This event can trigger the initialization of the user frame and setting its fields according to mehcall->param_p.

Macro: QSMM_EVT_NODE_LEAVE

Returning control from a node belonging to a node class represented by the instruction class set. The function qsmm_node_call_default sends this event on finishing calling a node. The event handler receives a node identifier via mehcall->node and the user parameter of qsmm_node_call_default via mehcall->param_p. After sending this event to the event handler, qsmm_node_call_default discards a current frame in the node call stack comprised of a user frame if its size is positive and a system frame.

This event can trigger setting a value addressed by mehcall->param_p according to the fields of the user frame with its subsequent uninitialization.

On successful completion, the event handler function shall return a non-negative value. A specific non-negative value has no effect on model operation. On error, the event handler function shall return a negative value. This negative value causes the invocation of an error handler function with passing QSMM_ERR_EVTHNDLR to it if the model has an error handler set.

The name of an instruction class set and the name of its event handler function can differ. Use the function qsmm_get_mehcall_instr_class_set to get the name of an instruction class set while processing an event by the event handler of the instruction class set.


4.2.3.3 Registering the Set

If an instruction class set has an event handler function with the same name, you register the instruction class set by the following macro.

Macro: QSMM_REG_INSTR_CLASS_SET_PARAM (model, instr_class_set_name, paramp)

This macro registers an instruction class set instr_class_set_name for a multinode model. The event handler function of the instruction class set previously declared or defined by the macro QSMM_INSTR_CLASS_SET should have the name instr_class_set_name. The event handler function will be receiving a parameter paramp in mehcall->param_p on events QSMM_EVT_ENT_INIT, QSMM_EVT_ENT_DONE, QSMM_EVT_ENGINE_INIT, and QSMM_EVT_ENGINE_DONE, where mehcall is an argument of that event handler function.

The macro QSMM_REG_INSTR_CLASS_SET_PARAM expands to:

qsmm_reg_instr_class_set((model), #instr_class_set_name,
                         &instr_class_set_name, (paramp))

Below there is a description of a function called by the macro QSMM_REG_INSTR_CLASS_SET_PARAM. You can call the function explicitly with passing NULL as the event handler function pointer to register an instruction class set without an event handler function.

Function: int qsmm_reg_instr_class_set (qsmm_t model, const char *instr_class_set_name, qsmm_instr_class_set_func_t instr_class_set_func, void *paramp)

This function registers an instruction class set instr_class_set_name for a multinode model. A function instr_class_set_func will be the event handler of the instruction class set. The event handler will be receiving a parameter paramp in mehcall->param_p on events QSMM_EVT_ENT_INIT, QSMM_EVT_ENT_DONE, QSMM_EVT_ENGINE_INIT, and QSMM_EVT_ENGINE_DONE, where mehcall is an argument of that event handler. If instr_class_set_func is NULL, the function registers an instruction class set without an event handler.

After registering an instruction class set, the function sends the event QSMM_EVT_ENT_INIT to the event handler, and it can perform the initialization of the instruction class set.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_EXIST

A program has already registered an instruction class set or instruction meta-class named instr_class_set_name in the multinode model.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to get a pointer to the event handler of an instruction class set and a user parameter passed to that event handler in certain cases.

Function: int qsmm_get_instr_class_set_handler (qsmm_t model, const char *instr_class_set_name, qsmm_instr_class_set_func_t *instr_class_set_func_p, void **param_pp)

This function retrieves the parameters of the event handler of an instruction class set instr_class_set_name registered for a multinode model. If instr_class_set_func_p is not NULL, the function sets *instr_class_set_func_p to a pointer to that event handler or to NULL if the instruction class set does not have an event handler. If param_pp is not NULL, the function sets *param_pp to a parameter of the event handler passed in mehcall->param_p on events QSMM_EVT_ENT_INIT, QSMM_EVT_ENT_DONE, QSMM_EVT_ENGINE_INIT, and QSMM_EVT_ENGINE_DONE, where mehcall is an argument of that event handler.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name not found.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

If a node belonging to a node class represented by an instruction class set does not have an explicitly specified probability profile, the node uses a default uniform probability profile. Its number of states is equal to the number of node states. It cannot exceed the maximum number of node states specified for the instruction class set. The number of states set for a node does not affect explicit specification of a probability profile for the node by loading an assembler program into it or cloning a probability profile for the node in simple or deferred mode. The default maximum number of states for newly registered instruction class sets is 2.

Use the following functions to query or set the maximum number of node states for an instruction class set.

Function: int qsmm_get_nstate_max_v2 (qsmm_t model, const char *node_class_name, int rez1, unsigned int flags, qsmm_sig_t *nstate_p)

This function retrieves the maximum allowed number of states of nodes belonging to a node class represented by an instruction class set named node_class_name in a multinode model. A retrieved number may restrict the number of states of a default probability profile for a node but will not restrict the number of states of a custom probability profile set by loading an assembler program into a node or cloning a probability profile for it in simple or deferred mode. The maximum allowed number of states is also the default number of states for newly created nodes belonging to the node class.

If flags contain bitmask QSMM_EXCEPT_NOTFOUND, and the instruction class set does not exist, the function reports QSMM_ERR_NOTFOUND. If flags contain bitmask QSMM_EXCEPT_TYPE, and an entity named node_class_name is not an instruction class set, the function reports QSMM_ERR_TYPE. Bitmask QSMM_EXCEPT_ALL includes QSMM_EXCEPT_NOTFOUND and QSMM_EXCEPT_TYPE.

The argument rez1 is for future use and must be equal to 0.

On success, the function returns a non-negative value and sets *nstate_p if nstate_p is not NULL. If an entity named node_class_name exists and is an instruction class set, the function sets *nstate_p to the maximum allowed number of states for the instruction class set. If the entity does not exist, and flags do not contain QSMM_EXCEPT_NOTFOUND, the function sets *nstate_p to QSMM_SIG_INVALID. If the entity exists but is not an instruction class set, and flags do not contain QSMM_EXCEPT_TYPE, the function sets *nstate_p to QSMM_SIG_INVALID.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set node_class_name does not exist. The function reports this error if flags include bitmask QSMM_EXCEPT_NOTFOUND. Otherwise, the function sets *nstate_p to QSMM_SIG_INVALID (if nstate_p is not NULL) and returns a non-negative value.

QSMM_ERR_TYPE

An entity named node_class_name is not an instruction class set. The entity is an instruction meta-class. The function reports this error if flags include bitmask QSMM_EXCEPT_TYPE. Otherwise, the function sets *nstate_p to QSMM_SIG_INVALID (if nstate_p is not NULL) and returns a non-negative value.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_set_nstate_max (qsmm_t model, const char *node_class_name, qsmm_sig_t nstate)

This function sets to nstate the maximum allowed number of states of nodes belonging to a node class represented by an instruction class set named node_class_name in a multinode model. That number may restrict the number of states of a default probability profile for a node but will not restrict the number of states of a custom probability profile set by loading an assembler program into a node or cloning a probability profile for it in simple or deferred mode. The maximum allowed number of states is also the default number of states for newly created nodes belonging to the node class.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument nstate is less than 2 or greater than QSMM_SIG_MAX.

QSMM_ERR_NOTFOUND

The instruction class set node_class_name does not exist.

QSMM_ERR_TYPE

An entity named node_class_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_UNTIMELY

Increasing the maximum allowed number of states requires increasing the number of output signals of an existing environment state identification engine represented by a large actor, and it has created a default output signal choice tree. See Number of Output Signals, for cases when a large actor creates a default output signal choice tree.

QSMM_ERR_VIOLNODE

The argument nstate is less than the number of states of an already created node belonging to the node class. This number of states specifies the number of states of a default probability profile for the node and does not restrict the number of states of a custom probability profile.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.2.3.4 Registering Instruction Classes

An individual instruction class is a subclass of an instruction meta-class and is an element of an instruction class set. Identical subclasses of an instruction meta-class can be the elements of multiple instruction class sets. Registering an individual instruction class must not violate uniqueness constraints listed in Instruction Class Identifiers.

Along with individual instruction classes, QSMM 1.19 supports instruction class sequences consisting of multiple instruction classes. See Instruction Class Sequences, for how to register an instruction class sequence, get individual instruction classes comprising a registered instruction class sequence, and find a registered instruction class sequence by individual instruction classes it contains.

Use the following function to register an individual instruction class.

Function: int qsmm_reg_instr_class_v2 (qsmm_t model, const char *instr_meta_class_name, const char *instr_class_set_name, int rez1, size_t param_bin_sz, const void *param_bin_p, qsmm_sig_t *instr_class_p)

This function registers an individual instruction class of a multinode model. The instruction class becomes a subclass of instr_meta_class_name instruction meta-class and an element of instr_class_set_name instruction class set. The arguments param_bin_p and param_bin_sz specify the content and size in bytes of a buffer with binary instruction class parameters. The function copies the buffer to an internal structure. If param_bin_sz is 0, then param_bin_p can be NULL. The argument rez1 is for future use and must be equal to 0.

The function sends an event QSMM_EVT_INSTR_CLASS_INIT to an instruction meta-class event handler. The event can trigger setting text instruction class parameters by the function qsmm_set_mehcall_instr_param_f and the number of instruction outcomes by the function qsmm_set_mehcall_noutcome.

On success, the function returns a non-negative value and, if instr_class_p is not NULL, sets *instr_class_p to an instruction class index—a number that uniquely identifies a registered instruction class in the instruction class set. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction meta-class instr_meta_class_name or instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_meta_class_name is not an instruction meta-class, or an entity named instr_class_set_name is not an instruction class set.

QSMM_ERR_EXIST

The instruction class set instr_class_set_name already contains an individual instruction class derived from the instruction meta-class instr_meta_class_name with the same binary or text parameters. The arguments param_bin_p and param_bin_sz specify the binary parameters. The instruction meta-class event handler can set the text parameters by the function qsmm_set_mehcall_instr_param_f on processing an event QSMM_EVT_INSTR_CLASS_INIT sent by the function qsmm_reg_instr_class_v2.

QSMM_ERR_UNTIMELY

Registering an instruction class requires increasing the number of output signals of an existing instruction emitting engine represented by a large actor, and it has created a default output signal choice tree. See Number of Output Signals, for cases when a large actor creates a default output signal choice tree.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following macros to register an individual instruction class belonging to an instruction class set in its event handler function on processing the event QSMM_EVT_ENT_INIT. The macros expect that the name of the event handler function is the same as the name of the instruction class set, and the variable qsmm holding the handle of a multinode model is accessible in the event handler function. Normally, that variable is an event handler function argument.

Macro: QSMM_REG_INSTR_CLASS (meta_class_name)

This macro registers an individual instruction class derived from an instruction meta-class meta_class_name without binary parameters.

The macro expands to:

qsmm_reg_instr_class_v2((qsmm),#meta_class_name,__FUNCTION__,0,0,0,0)
Macro: QSMM_REG_INSTR_CLASS_PARAM (meta_class_name, param_bin)

This macro registers an individual instruction class derived from an instruction meta-class meta_class_name with binary parameters in a variable param_bin.

The macro expands to:

qsmm_reg_instr_class_v2((qsmm), #meta_class_name, __FUNCTION__, 0,
                        sizeof(param_bin), &(param_bin), 0)

The binary parameters of an individual instruction class to register by the macro QSMM_REG_INSTR_CLASS_PARAM must be a variable and not a constant. This is because the macro takes the address of a variable using ‘&’. If you need to specify a constant as the binary parameters, assign the constant to a variable of an appropriate type and pass the variable to QSMM_REG_INSTR_CLASS_PARAM.

For example, to use the element DIRECT_NORTH of direct_e enumeration mentioned in Accessing Binary Instruction Parameters as a binary parameter of an individual instruction class derived from the instruction meta-class ‘move’, write:

const enum direct_e direct=DIRECT_NORTH;
QSMM_REG_INSTR_CLASS_PARAM(move,direct);

The following lines register individual instruction classes derived from the instruction meta-class ‘move’ for all movement directions declared by the enumeration direct_e:

for (enum direct_e direct=0; direct<DIRECT_COUNT; direct++)
    QSMM_REG_INSTR_CLASS_PARAM(move,direct);

Use the following function to get the total number of instruction classes contained in an instruction class set. An instruction class index returned by the function qsmm_reg_instr_class_v2 never exceeds the size of an instruction class set.

Function: int qsmm_get_instr_class_set_sz_v2 (qsmm_t model, const char *instr_class_set_name, int rez1, unsigned int flags, qsmm_sig_t *n_instr_class_p)

This function retrieves the number of instruction classes contained in an instruction class set instr_class_set_name in a multinode model. The function counts individual instruction classes and instruction class sequences in the instruction class set.

If flags contain bitmask QSMM_EXCEPT_NOTFOUND, and the instruction class set does not exist, the function reports QSMM_ERR_NOTFOUND. If flags contain bitmask QSMM_EXCEPT_TYPE, and an entity named instr_class_set_name is not an instruction class set, the function reports QSMM_ERR_TYPE. Bitmask QSMM_EXCEPT_ALL includes QSMM_EXCEPT_NOTFOUND and QSMM_EXCEPT_TYPE.

The argument rez1 is for future use and must be equal to 0.

On success, the function returns a non-negative value and sets *n_instr_class_p if n_instr_class_p is not NULL. If an entity named instr_class_set_name exists and is an instruction class set, the function sets *n_instr_class_p to the number of instruction classes in the instruction class set. If the entity does not exist, and flags do not contain QSMM_EXCEPT_NOTFOUND, the function sets *n_instr_class_p to QSMM_SIG_INVALID. If the entity exists but is not an instruction class set, and flags do not contain QSMM_EXCEPT_TYPE, the function sets *n_instr_class_p to QSMM_SIG_INVALID.

If n_instr_class_p is not NULL, and *n_instr_class_p is 0 or QSMM_SIG_INVALID or would be set to one of these values if n_instr_class_p were not NULL, the function returns 0. If the instruction class set contains a single instruction class, the function returns 1. If the instruction class set contains multiple instruction classes, the function returns a value greater than 1.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist. The function reports this error if flags include bitmask QSMM_EXCEPT_NOTFOUND. Otherwise, the function sets *n_instr_class_p to QSMM_SIG_INVALID (if n_instr_class_p is not NULL) and returns 0.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class. The function reports this error if flags include bitmask QSMM_EXCEPT_TYPE. Otherwise, the function sets *n_instr_class_p to QSMM_SIG_INVALID (if n_instr_class_p is not NULL) and returns 0.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to get the index of an individual instruction class by its name.

Function: int qsmm_find_instr_class_in_set_f_v2 (qsmm_t model, qsmm_sig_t *instr_class_p, const char *instr_class_set_name, int rez1, unsigned int flags, const char *fmt, ...)
Function: int qsmm_find_instr_class_in_set_fv_v2 (qsmm_t model, qsmm_sig_t *instr_class_p, const char *instr_class_set_name, int rez1, unsigned int flags, const char *fmt, va_list ap)

The functions retrieve the index of an individual instruction class in an instruction class set instr_class_set_name in a multinode model by the name of the instruction class. The index or the name in canonical form uniquely identifies the instruction class in the instruction class set. Zero or more whitespace characters followed by an instruction meta-class name optionally followed by at least one whitespace character optionally followed by text instruction class parameters make up an instruction class name.

The function qsmm_find_instr_class_in_set_f_v2 formats an instruction class name according to the argument fmt and subsequent arguments similarly to the function printf. The function qsmm_find_instr_class_in_set_fv_v2 formats an instruction class name according to the arguments fmt and ap similarly to the function vprintf.

Before searching the instruction class in the set, the functions convert the formatted name to canonical form: they remove whitespace characters before the instruction meta-class name, replace whitespace characters after the instruction meta-class name with a single space character, and convert text instruction class parameters to their canonical form according to rules described in Setting Text Instruction Parameters.

If flags contain bitmask QSMM_EXCEPT_NOTFOUND, and the instruction class not found in the instruction class set, the functions report QSMM_ERR_NOTFOUND. The argument rez1 is for future use and must be equal to 0.

On success, the functions return a non-negative value and set *instr_class_p if instr_class_p is not NULL. If the instruction class found in the instruction class set, the functions set *instr_class_p to the index of the instruction class. If the instruction class set exists, but the instruction class not found in it, and flags do not contain QSMM_EXCEPT_NOTFOUND, the functions set *instr_class_p to QSMM_SIG_INVALID.

On failure, the functions return a negative error code. Currently, the functions can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist, or the instruction class not found in the instruction class set. In the latter case, the functions report this error if flags include bitmask QSMM_EXCEPT_NOTFOUND; otherwise, the functions set *instr_class_p to QSMM_SIG_INVALID (if instr_class_p is not NULL) and return a non-negative value.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_INVAL

An instruction class name has invalid format.

QSMM_ERR_ILSEQ

Unable to convert an instruction class name to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to get information about an individual instruction class specified by its index.

Function: int qsmm_get_instr_class_name (qsmm_t model, const char *instr_class_set_name, qsmm_sig_t instr_class, const char **instr_class_name_pp)

This function retrieves the canonicalized name of an individual instruction class specified by its index instr_class in an instruction class set instr_class_set_name in a multinode model. That canonicalized name is the name of an instruction meta-class optionally followed by the space character and text instruction class parameters in canonical form. The function sets *instr_class_name_pp to the canonicalized name if instr_class_name_pp is not NULL. A pointer returned in *instr_class_name_pp is valid until the next call to this function for the instruction class.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or instr_class specifies an instruction class sequence rather than an individual instruction class.

QSMM_ERR_ILSEQ

Unable to convert the canonicalized name of an individual instruction class to a multibyte string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_get_instr_class_meta_name (qsmm_t model, const char *instr_class_set_name, qsmm_sig_t instr_class, const char **instr_meta_class_name_pp)

This function retrieves the name of the instruction meta-class of an individual instruction class specified by its index instr_class in an instruction class set instr_class_set_name in a multinode model. The function sets *instr_meta_class_name_pp to the instruction meta-class name if instr_meta_class_name_pp is not NULL.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or instr_class specifies an instruction class sequence rather than an individual instruction class.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_get_instr_class_param_str (qsmm_t model, const char *instr_class_set_name, qsmm_sig_t instr_class, const char **param_str_pp)

This function retrieves the canonicalized text parameters of an individual instruction class specified by its index instr_class in an instruction class set instr_class_set_name in a multinode model. The function sets *param_str_pp to the canonicalized text parameters if param_str_pp is not NULL. If the instruction class does not have text parameters, or its canonicalized text parameters are the empty string, the function sets *param_str_pp to NULL. A pointer returned in *param_str_pp is valid until the next call to this function or the function qsmm_get_mehcall_instr_param_str for the instruction class.

If the canonicalized text parameters have positive length, the function returns a positive value. If the instruction class does not have text parameters, or its canonicalized text parameters are the empty string, the function returns 0. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or instr_class specifies an instruction class sequence rather than an individual instruction class.

QSMM_ERR_ILSEQ

Unable to convert the canonicalized text parameters of an individual instruction class to a multibyte string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_get_instr_class_param_bin (qsmm_t model, const char *instr_class_set_name, qsmm_sig_t instr_class, size_t *param_bin_sz_p, const void **param_bin_pp)

This function retrieves the binary parameters of an individual instruction class specified by its index instr_class in an instruction class set instr_class_set_name in a multinode model. If param_bin_sz_p is not NULL, the function sets *param_bin_sz_p to the size of the binary parameters in bytes. If param_bin_pp is not NULL, the function sets *param_bin_pp to a pointer to the binary parameters. If the instruction class does not have binary parameters (i.e. their size is 0), the function sets *param_bin_pp to NULL.

If the instruction class has binary parameters (i.e. their size is positive), the function returns a positive value. If the instruction class does not have binary parameters, the function returns 0. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or instr_class specifies an instruction class sequence rather than an individual instruction class.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The following function is applicable to individual instruction classes and instruction class sequences.

Function: int qsmm_get_instr_class_noutcome_v2 (qsmm_t model, const char *instr_class_set_name, int rez1, qsmm_sig_t instr_class, qsmm_sig_t *noutcome_p)

This function retrieves the number of outcomes of an instruction class specified by its index instr_class in an instruction class set instr_class_set_name in a multinode model. If instr_class specifies an instruction class sequence, its number of outcomes is equal to the number of outcomes of the last instruction class in the sequence.

If noutcome_p is not NULL, the function sets *noutcome_p to the number of outcomes. That number equal to 0 has special meaning described in Setting the Number of Instruction Outcomes. The argument rez1 is for future use and must be equal to 0.

If the instruction class has multiple outcomes, the function returns a value greater than 1. If the instruction class has a single outcome, the function returns 1. If the instruction class has special number of outcomes 0, the function returns 0. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.2.3.5 Instruction Class Sequences

An instruction class sequence is a special kind of instruction class. An instruction class sequence consists of two or more previously registered individual instruction classes. The number of outcomes of an instruction class sequence is equal to the number of outcomes of its last instruction class.

You can register an instruction class sequence by the function qsmm_reg_instr_class_seq described below. The node assembler uses that function to automatically register instruction class sequences found in an assembler program. See Loading a Parsed Program into a Node, for a description of qsmm_node_asm function implementing the node assembler.

Function: int qsmm_reg_instr_class_seq (qsmm_t model, const char *instr_class_set_name, int rez1, const qsmm_sig_t *elm_p, size_t n_elm, qsmm_sig_t *instr_class_p)

This function registers an instruction class sequence as an element of instr_class_set_name instruction class set in a multinode model. An array of instruction class indices elm_p containing n_elm elements specifies the instruction class sequence. The argument rez1 is for future use and must be equal to 0.

On success, the function returns a non-negative value and sets *instr_class_p to an instruction class index identifying a registered instruction class sequence if instr_class_p is not NULL. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument n_elm is less than 2, or an element of elm_p array is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or an element of elm_p array is the index of an instruction class sequence rather than an individual instruction class.

QSMM_ERR_EXIST

The instruction class set instr_class_set_name already contains the instruction class sequence.

QSMM_ERR_UNTIMELY

Registering an instruction class sequence requires increasing the number of output signals of an existing instruction emitting engine represented by a large actor, and it has created a default output signal choice tree. See Number of Output Signals, for cases when a large actor creates a default output signal choice tree.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to get a list of individual instruction classes comprising an instruction class sequence.

Function: int qsmm_get_instr_class_seq (qsmm_t model, const char *instr_class_set_name, unsigned int flags, qsmm_sig_t instr_class, const qsmm_sig_t **elm_pp, size_t *n_elm_p)

This function retrieves a list of individual instruction classes comprising an instruction class sequence in an instruction class set instr_class_set_name in a multinode model. An instruction class index instr_class identifies the instruction class sequence in the instruction class set.

The function sets *elm_pp to address an array of indices of individual instruction classes comprising the instruction class sequence and sets *n_elm_p to the number of elements in the array. If flags do not contain bitmask QSMM_EXCEPT_TYPE, and instr_class is the index of an individual instruction class rather than an instruction class sequence, the function sets *elm_pp to NULL and *n_elm_p to 0 and reports success. If elm_pp or n_elm_p is NULL, the function does not set *elm_pp or *n_elm_p respectively. If flags contain bitmask QSMM_EXCEPT_TYPE, and instr_class is the index of an individual instruction class rather than an instruction class sequence, the function reports QSMM_ERR_TYPE.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or flags contain bitmask QSMM_EXCEPT_TYPE, and instr_class is the index of an individual instruction class rather than an instruction class sequence.

Use the following function to find the index of an already registered instruction class sequence by a list of individual instruction classes it contains.

Function: int qsmm_find_instr_class_seq_in_set (qsmm_t model, const char *instr_class_set_name, unsigned int flags, const qsmm_sig_t *elm_p, size_t n_elm, qsmm_sig_t *instr_class_p)

This function finds an instruction class sequence in an instruction class set instr_class_set_name in a multinode model by an array of indices of individual instruction classes comprising the instruction class sequence. The arguments elm_p and n_elm specify the address of the array and the number of elements in it respectively.

If flags contain bitmask QSMM_EXCEPT_NOTFOUND, and the instruction class sequence not found in the instruction class set, the function reports QSMM_ERR_NOTFOUND.

On success, the function returns a non-negative value and sets *instr_class_p if instr_class_p is not NULL. If the instruction class sequence found in the instruction class set, the function sets *instr_class_p to an instruction class index identifying the sequence. If the instruction class set exists, but the instruction class sequence not found in it, and flags do not contain QSMM_EXCEPT_NOTFOUND, the function sets *instr_class_p to QSMM_SIG_INVALID.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument n_elm is less than 2, or an element of elm_p array is greater than or equal to the number of instruction classes in the instruction class set instr_class_set_name.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist, or the instruction class sequence not found in the instruction class set. In the latter case, the function reports this error if flags include bitmask QSMM_EXCEPT_NOTFOUND; otherwise, the function sets *instr_class_p to QSMM_SIG_INVALID (if instr_class_p is not NULL) and returns a non-negative value.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set—the entity is an instruction meta-class, or an element of elm_p array is the index of an instruction class sequence rather than an individual instruction class.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.2.3.6 Function Layout

Below there is a template for the event handler of an instruction class set. Its instruction classes use the node call stack. If instruction classes of an instruction class set do not use the node call stack, you can register the instruction class set without an event handler.

QSMM_INSTR_CLASS_SET(instr_class_set_name) {
    struct stack_frame_s *stack_frame_p=0;
        // structure "stack_frame_s" represents a user stack frame
    struct node_param_s *node_param_p;
        // structure "node_param_s" holds user parameters
        // associated with a node
    struct model_param_s *const model_param_p=qsmm_get_ptr(qsmm,0);
        // obtain model parameters specific to this model; a call
        // qsmm_set_ptr(qsmm,0,ptr_p) should have set a pointer ptr_p
        // addressing the parameters
    switch (mehcall->evt) {
        case QSMM_EVT_NODE_ENTER:
            node_param_p=qsmm_get_node_ptr(qsmm,mehcall->node,0);
                // obtain the parameters of an executed node; a call
                // qsmm_set_node_ptr(qsmm,node,0,ptr_p) should have set
                // a pointer ptr_p addressing the parameters
            qsmm_get_mehcall_stack_frame(
                mehcall, 0, (void **) &stack_frame_p);
                    // obtain a current user frame of node call stack
            // TODO: initialize *stack_frame_p, possibly according to
            //       *node_param_p, *model_param_p, and the content of a
            //       structure addressed by mehcall->param_p.
            break;
        case QSMM_EVT_NODE_LEAVE:
            node_param_p=qsmm_get_node_ptr(qsmm,mehcall->node,0);
                // obtain the parameters of an executed node; a call
                // qsmm_set_node_ptr(qsmm,node,0,ptr_p) should have set
                // a pointer ptr_p addressing the parameters
            qsmm_get_mehcall_stack_frame(
                mehcall, 0, (void **) &stack_frame_p);
                    // obtain a current user frame of node call stack
            // TODO: set the content of a structure addressed by
            //       mehcall->param_p according to *stack_frame_p and,
            //       possibly, *node_param_p* and *model_param_p* and
            //       uninitialize *stack_frame_p.
            break;
        case QSMM_EVT_ENT_INIT:
        case QSMM_EVT_ENT_DONE:
        case QSMM_EVT_ENGINE_INIT:
        case QSMM_EVT_ENGINE_DONE:
            // TODO: optionally handle the events.
            break;
    }
    return 0;
}

4.2.4 Node Parameters

A model node has the following basic parameters:

  1. A node identifier (index) in the scope of a multinode model. The function qsmm_node_create_v2 creates a node with a specified identifier or finds an unused identifier for a node to create. The macro QSMM_NODE_CREATE creates a node with a specified identifier. See Creating Nodes.
  2. The number of states for a default probability profile. The function qsmm_set_nstate_max called for a node class the node belongs to specifies the default number of node states for a default (uniform) probability profile. That number is also the maximum allowed number of node states for a default probability profile. The function qsmm_set_node_nstate can set the number of node states for a default probability profile to a lesser value. The number of node states for a default probability profile does not restrict the number of node states for a custom probability profile set by loading an assembler program into the node or cloning a probability profile for it in simple or deferred mode.
  3. An instruction class set specifying a node class for the node. The function qsmm_node_create_v2 has an argument for the name of an instruction class set. The macro QSMM_NODE_CREATE uses ‘__FUNCTION__’ as the name of an instruction class set.
  4. User parameters specified by pointers. The function qsmm_set_node_ptr associates a user pointer with a node. See Associating Parameters with a Model.
  5. A list of controlled probability variables taken from an instruction class set. The function qsmm_reg_var_prob or macro QSMM_REG_VAR_PROB registers a controlled probability variable for the instruction class set. Every list element includes the name of a controlled probability variable, its index, and a probability value. The function qsmm_set_node_var_prob sets the probability value for the node. The initial probability value is 0. See Controlled Variables.
  6. The weights of all instruction classes of an instruction class set. The functions qsmm_set_instr_class_weight and qsmm_set_instr_class_weight_by_name_f change the weights for the node. By default, all weights are equal to 1. See Setting Instruction Classes Weights.

The existence of model nodes is unrelated to the existence of model instance (see Creating the Model Instance). However, when the model instance exists, the node has extended parameters:

  1. The state transition matrix along with collected statistics for keeping the matrix up-to-date maintained by the environment state identification engine. Identifiers of rows of that matrix are quadruples consisting of a previous node state, the index of instruction class of last instruction invoked by the node, the outcome of this instruction, and the content of look-ahead signal segment. Identifiers of columns of that matrix are the indices of next node states. The cells of that matrix hold state transition probabilities with types declared by the enumeration qsmm_prob_e. See Dumping the State Transition Matrix.
  2. The action emission matrix along with collected statistics for keeping the matrix up-to-date maintained by the instruction emitting engine. Identifiers of rows of that matrix are the indices of node states. Identifiers of columns of that matrix are the indices of instruction classes. The cells of that matrix hold instruction emission probabilities with types declared by the enumeration qsmm_prob_e. See Dumping the Action Emission Matrix.
  3. A node probability profile written to the state transition matrix and action emission matrix by the function qsmm_node_asm or qsmm_node_profile_clone or copied from the state transition matrix and action emission matrix of another node in deferred mode by the function qsmm_set_node_profile_source.

    By default, the node has a uniform probability profile occupying all node states. In this profile, probabilities of transitions between all node states are equal, and probabilities of emitting all instructions in all node states are equal. A default uniform probability profile occupies the number of states less than or equal to the number of node states specified by the function qsmm_set_nstate_max for the instruction class set. The function qsmm_set_node_nstate can set the number of states of a default uniform probabilitiy profile to a lesser value for the node. Default uniform probability profiles do not exist for nodes in a model:

    • that restricts the state transition matrix of every node to define only deterministic state transitions (field engine_desc[QSMM_ENGINE_ENV].is_determ of qsmm_desc_s structure is non-zero); in this case, the node requires explicit specification of a probability profile;
    • that restricts the action emission matrix of every node to define deterministic choice of an assembler instruction emitted in every node state (field engine_desc[QSMM_ENGINE_IEE].is_determ of qsmm_desc_s is non-zero), and the number of instruction classes in the instruction class set is not 1; in this case, the node requires explicit specification of a probability profile;
    • with the maximum number of nodes (field nnode_max of qsmm_desc_s) greater than 1, a large actor representing the environment state identification engine (field engine_desc[QSMM_ENGINE_ENV].large_desc_p of qsmm_desc_s is not NULL) or the instruction emitting engine (field engine_desc[QSMM_ENGINE_IEE].large_desc_p of qsmm_desc_s is not NULL), and positive length of look-ahead signal segment (field ngram_env_la_sz of qsmm_desc_s is positive); in this case, the function qsmm_node_call_default cannot transfer control to a node, and all model nodes are unusable; this limitation can disappear in future QSMM versions.
  4. An indication whether the node is the source of a probability profile for other nodes or is a user of a probability profile provided by another node. The function qsmm_set_node_profile_source sets this mode. In this mode some operations on the node result in reporting QSMM_ERR_PROFSRCP or QSMM_ERR_PROFSRCU respectively. See Memory Efficient Cloning the Probability Profile.
  5. The initial values of controlled probability variables. If qsmm_node_asm loads an assembler program into the node, the assembler program specifies the initial values. If qsmm_node_profile_clone or qsmm_set_node_profile_source sets a probability profile for the node, a source node provides the initial values.
  6. Rules for recomputing profile probabilities in the cells of the state transition matrix and action emission matrix on changing values of controlled probability variables. Every element of the list of controlled probability variables additionally contains an indicator whether the value of a controlled probability variable set by the function qsmm_set_node_var_prob needs committing to the state transition matrix or action emission matrix by the function qsmm_node_var_realize according to the rules. See Controlled Variables.
  7. Optional names of node states corresponding to their indices. If qsmm_node_asm loads an assembler program into the node, the assembler program specifies the names. If qsmm_node_profile_clone or qsmm_set_node_profile_source sets a probability profile for the node, a source node provides the names. The function qsmm_get_node_state_name retrieves the name of a node state by its index. The function qsmm_get_node_state_by_name retrieves the index of a node state by its name.
  8. An assembler program template for disassembling the node by the function qsmm_node_disasm. If qsmm_node_asm loads an assembler program with the flag QSMM_ASM_TEMPLATE, the assembler program becomes the template. If qsmm_node_profile_clone or qsmm_set_node_profile_source specifies a probability profile for the node, a source node provides the template.
  9. Rules for calculating the values of output probability variables and arrays. If qsmm_node_asm loads an assembler program into the node, the assembler program defines output probability variables and arrays. If qsmm_node_profile_clone or qsmm_set_node_profile_source specifies a probability profile for the node, a source node defines output probability variables and arrays. See Output Variables.
  10. The cache of calculated probabilities of output probability variables and the cache of calculated probabilities of choice alternatives. The function qsmm_get_node_var_prob_out caches the calculated value of an output probability variable. Additionally, that function and the function qsmm_get_node_array_prob_out cache probabilities of all choice alternatives that include a choice alternative for a calculated output probability variable or array element. The function qsmm_node_var_out_forget called implicitly in certain cases or explicitly clears both caches.
  11. The number of times the function qsmm_node_call_default called the node and the number of times that function transferred control to the node but not yet returned control from it. The functions qsmm_get_node_fq and qsmm_get_node_recurs retrieve the numbers. The initial values are 0. See Calling a Node.

The node parameters tied to the model instance and listed above take the same initial values in case of creating the model instance after creating the node and in case of creating the node after creating the model instance.

The function qsmm_node_unload (see Unloading the Probability Profile) called for a node causes unsetting all node parameters tied to the model instance except for the parameters retrieved by the functions qsmm_get_node_fq and qsmm_get_node_recurs. The unset parameters take their initial values they have just after creating the model instance.


4.2.5 Creating Nodes

Use the following function to create a node belonging to a particular node class represented by an instruction class set.

Function: int qsmm_node_create_v2 (qsmm_t model, const char *node_class_name, int rez1, qsmm_sig_t *node_p)

This function creates a node of a multinode model. The node belongs to a node class represented by an instruction class set named node_class_name.

If node_p is NULL, or *node_p is QSMM_SIG_INVALID, the function finds the lowest unused identifier for a new node; if node_p is not NULL, the function returns that identifier in *node_p. If node_p is not NULL, and *node_p is not QSMM_SIG_INVALID, *node_p specifies an unused identifier for a node to create; in this case, *node_p remains unchanged on function completion. The argument rez1 is for future use and must be equal to 0.

The node takes initial values of basic parameters listed in Node Parameters. If the model instance exists, the node also takes initial values of extended parameters listed in that section.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument node_p is not NULL, and *node_p is not equal to QSMM_SIG_INVALID but is greater than or equal to the maximum number of nodes in the model specified using the field nnode_max of qsmm_desc_s structure when creating the model.

QSMM_ERR_NOTFOUND

The instruction class set node_class_name does not exist.

QSMM_ERR_TYPE

An entity named node_class_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_EXIST

The argument node_p is not NULL, *node_p is not equal to QSMM_SIG_INVALID, and a node with identifier *node_p already exists.

QSMM_ERR_MNODE

Creating a node would result in exceeding the maximum number of nodes in the model specified using the field nnode_max of qsmm_desc_s structure when creating the model.

QSMM_ERR_NOMEM

There was not enough memory to create a node.

Use the following macro to create a node from within the event handler function of an instruction class set where the name of that event handler function is the name of the instruction class set.

Macro: QSMM_NODE_CREATE (node)

This macro expands to:

do {                                                       \
    qsmm_sig_t sig_node=(node);                            \
    qsmm_node_create_v2((qsmm),__FUNCTION__,0,&sig_node);  \
}                                                          \
while (0)

The macro is for creating a model node with identifier node from within the event handler function of an instruction class set representing the node class of the node. The name of that event handler function must be the same as the name of the instruction class set. The variable qsmm holding a model handle must be accessible in the event handler function. Normally, that variable is an event handler function argument.

The function qsmm_destroy destroys a multinode model and all its nodes. The following function destroys a specific node.

Function: int qsmm_node_destroy (qsmm_t model, qsmm_sig_t node)

This function destroys a node with identifier node contained in a multinode model. The identifier becomes the unused one. The function destroys all parameters of the node listed in Node Parameters.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_PROFSRCP

A node with identifier node is the source of a probability profile for other nodes. See Memory Efficient Cloning the Probability Profile, for more information on this mode.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation. This error can leave the node in inconsistent state. If after removing a reason of this error a repeated call to this function succeeds, it completely destroys the node.

Use the following function to get the number of nodes in a model.

Function: qsmm_sig_t qsmm_get_nnode (qsmm_t model)

This function returns the number of existing nodes in a multinode model.

Use the function described below to get the name of node class of a node. You can also use this function to test whether a node with a particular identifier exists.

Function: const char * qsmm_get_node_class_name (qsmm_t model, qsmm_sig_t node)

This function returns the name of instruction class set of a node with identifier node contained in a multinode model. If the node does not exist, the function returns NULL.

If a node does not have an explicitly specified probability profile, the node uses a default uniform probability profile. In this case, a prerequisite for successful learning a state model by the node is that the default probability profile has a sufficient number of states. On the other hand, the more states the default probability profile has, the more instructions the node generally needs to execute to learn a state model.

The number of states of a default uniform probability profile for a just created node is equal to the maximum number of states specified for the instruction class set of the node. See Registering the Set, for the descriptions of qsmm_get_nstate_max_v2 and qsmm_set_nstate_max functions for retrieving and setting that maximum number of states.

After creating a node, you can use the function qsmm_set_node_nstate to change the number of states of a default probability profile for the node to a value less than maximum allowed one specified for the instruction class set if the environment state identification engine is a small actor, or the maximum number of nodes in the model is greater than 1.

If the environment state identification engine or instruction emitting engine is a large actor, the maximum number of nodes in the model is greater than 1, and the function qsmm_node_call_default already called the node, that function loaded a default uniform probability profile into the node. In this case, qsmm_set_node_nstate does not change the number of states of an already loaded default probability profile.

Use the following functions to retrieve or set the number of states for default uniform probability profile of a node.

Function: int qsmm_get_node_nstate_v2 (qsmm_t model, int rez1, unsigned int flags, qsmm_sig_t node, qsmm_sig_t *nstate_p)

This function retrieves the number of states of a default probability profile for a node with identifier node contained in a multinode model. A returned value is either default number of states equal to the maximum number of states specified for the instruction class set of the node or the number of states set for the node by the function qsmm_set_node_nstate.

The argument rez1 is for future use and must be equal to 0.

On success, the function returns a non-negative value and sets *nstate_p if nstate_p is not NULL. If the node exists, the function sets *nstate_p to the number of states of the default probability profile. If the node does not exist, and flags do not contain bitmask QSMM_EXCEPT_NOTFOUND, the function sets *nstate_p to QSMM_SIG_INVALID.

If the node does not exist, and flags contain QSMM_EXCEPT_NOTFOUND, the function returns negative error code QSMM_ERR_NOTFOUND.

Function: int qsmm_set_node_nstate (qsmm_t model, qsmm_sig_t node, qsmm_sig_t nstate)

This function sets to nstate the number of states of a default probability profile for a node with identifier node contained in a multinode model.

If the function qsmm_node_call_default already called the node and loaded into it an assembler program specifying a default probability profile, you need to call the function qsmm_node_unload to make it possible for qsmm_node_call_default to load into the node an assembler program specifying a default probability profile with a different number of states. See Unloading the Probability Profile, for more information about qsmm_node_unload.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument nstate is less than 2 or greater than the maximum allowed number of states specified for the instruction class set of the node.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_NOTSUP

The environment state identification engine is a large actor, and the maximum number of nodes specified using the field nnode_max of qsmm_desc_s structure when creating the model is 1. Use the function qsmm_set_nstate_max to set the number of states of the node before creating it.


4.2.6 Creating the Model Instance

A multinode model can have an instance holding model parameters specific to a single model run against input data or a single course of interaction with external entities. That is, a model represents the structure of a system, and a model instance is a system created to carry out a particular process of interaction or computation—a process of model execution. After finishing the process, a program can accumulate learned model parameters and recreate the instance for a new process of model execution. Multiple model runs would provide average values of learned model parameters.

Creating a model instance includes creating an environment state identification engine and instruction emitting engine. The function qsmm_destroy implicitly destroys a model instance if it exists.

When a model instance exists, nodes have extended parameters listed in Node Parameters. A node takes initial values of extended parameters on creating the model instance after creating the node and on creating the node after creating the model instance. All nodes lose their extended parameters on destroying the model instance.

Use the following function to create a model instance.

Function: int qsmm_engine_create (qsmm_t model)

This function creates the instance of a multinode model. A model instance holds parameters specific to a particular process of interaction or computation performed using a model with certain structure. If the model instance already exists, the function first destroys it. The function returns a non-negative value on success or negative error code QSMM_ERR_NOMEM on out of memory error.

Use the following function to destroy the model instance.

Function: void qsmm_engine_destroy (qsmm_t model)

This function destroys the instance of a multinode model. Destroying the model instance includes destroying the environment state identification engine and instruction emitting engine and removing all statistics they might have collected. If the model instance does not exist, the function has no effect.

An object called actor pair addressed by an actor pair handle is a container of an environment state identification engine and instruction emitting engine in the scope of a model instance.

Data type: qsmm_actpair_t

This is a type for an actor pair handle. It is a pointer, so variables of this type can be NULL. The function qsmm_get_actpair returns the handle of an actor pair for a model instance. That handle is valid until destroying the model instance.

Use the following function to get an actor pair associated with a model instance.

Function: qsmm_actpair_t qsmm_get_actpair (qsmm_t model)

This function returns the handle of an actor pair associated with the instance of a multinode model. That handle is valid until destroying the model instance. If the model instance does not exist, the function returns NULL.

Use the following function to get an actor representing an environment state identification engine or instruction emitting engine, which is a part of an actor pair. See Creating a Handle, for a description of qsmm_engine_e enumeration used by the function.

Function: qsmm_actor_t qsmm_get_actpair_actor (qsmm_actpair_t actpair, enum qsmm_engine_e engine_type)

This function returns the handle of an actor contained in an actor pair actpair. If engine_type is QSMM_ENGINE_ENV, the function returns the handle of an environment state identification engine. If engine_type is QSMM_ENGINE_IEE, the function returns the handle of an instruction emitting engine. For other values of engine_type, the function returns NULL.

To be confident that key parameters of an environment state identification engine and instruction emitting engine have expected values, you should explicitly set the parameters after creating the model instance. If the variable qsmm holds the handle of a multinode model, use the following lines of code to assign to the variable actor_env the handle of the environment state identification engine and assign to the variable actor_iee the handle of the instruction emitting engine:

const qsmm_actpair_t actpair=qsmm_get_actpair(qsmm);
const qsmm_actor_t actor_env=qsmm_get_actpair_actor(actpair,
                                                    QSMM_ENGINE_ENV),
    actor_iee=qsmm_get_actpair_actor(actpair,QSMM_ENGINE_IEE);

Some parameters are applicable to a small actor associated with a large actor representing the environment state identification engine. Use the following lines of code to assign the handle of this small actor to the variable actor_env_env:

const qsmm_actor_t actor_env_env=
    qsmm_get_actpair_actor(
        qsmm_get_actpair(qsmm_get_actor_large_model(actor_env)),
        QSMM_ENGINE_ENV);

Some parameters are applicable to a small actor associated with a large actor representing the instruction emitting engine. Use the following lines of code to assign the handle of this small actor to the variable actor_iee_env:

const qsmm_actor_t actor_iee_env=
    qsmm_get_actpair_actor(
        qsmm_get_actpair(qsmm_get_actor_large_model(actor_iee)),
        QSMM_ENGINE_ENV);

The table below summarizes parameters you can set for the aforementioned variables actor_env, actor_iee, actor_env_env, and actor_iee_env—an environment state identification engine and instruction emitting engine and their associated small actors (if applicable). The table shows initial parameter values for the actors. Consider explicit setting the initial value of a parameter if a corresponding cell contains “varies.”

Parameter and API Function for Setting Itactor_env / actor_ieeactor_env_env /
actor_iee_env
The mode of behavior: adaptive or random
qsmm_set_actor_random
adaptive
The index of a spur type for the automatic spur
qsmm_set_actor_auto_spur_type
−1−1
Discrete time
qsmm_set_actor_discrete_time
00
Continuous time
qsmm_actor_time_delta_v2
00
Temperature
qsmm_set_actor_ktemperature
1
Spur values
qsmm_actor_spur_delta
0
Spur weights
qsmm_set_actor_spur_weight
varies
The way of spur perception: normal or inverse
qsmm_set_actor_spur_perception
normal
The type of time for computing spur increment velocity
qsmm_set_actor_spur_time
varies
The type of a function returning the relative probability of an output signal and, for certain function types, a helper function for computing the relative probability of an output signal
qsmm_set_actor_relprob_type and
qsmm_set_actor_relprob_helper
QSMM_RELPROB_BUILTIN3
A function for intercepting updates of cycle type statistics
qsmm_set_storage_cycle_update_hook for a handle obtained by qsmm_get_actor_storage
NULLNULL

4.2.7 Associating Parameters with a Model

When creating a multinode model, you can declare custom model parameters as global variables and access them from event handler functions. However, when you create multiple models existing concurrently and sharing the same event handler functions, you may need to associate a number of variables with a particular model.

You can associate a number of pointers with a multinode model. They can address statically or dynamically allocated memory blocks. Every pointer has a unique index. In the simplest case, you can associate a single pointer with index 0 addressing an instance of a structure holding variables specific to a model.

Use the following functions to get a pointer associated with a multinode model or associate a pointer with the model.

Function: void * qsmm_get_ptr (qsmm_t model, int ptr_idx)

This function returns a pointer with index ptr_idx associated with a multinode model. If the model does not have a pointer with this index, or the pointer is NULL, the function returns NULL.

Function: int qsmm_set_ptr (qsmm_t model, int ptr_idx, void *ptr_p)

This function associates a pointer ptr_p with a multinode model. You can fetch the pointer later by index ptr_idx. If a pointer with this index already exists, the function overwrites it.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument ptr_idx is negative.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

It is possible to associate pointers not only with the entire multinode model but also with its particular nodes. Use the following functions to get a pointer associated with a node or associate a pointer with a node.

Function: void * qsmm_get_node_ptr (qsmm_t model, qsmm_sig_t node, int ptr_idx)

This function returns a pointer with index ptr_idx associated with a node of a multinode model. The argument node specifies the identifier of the node. If the node does not exist, or the node does not have a pointer with this index, or the pointer is NULL, the function returns NULL.

Function: int qsmm_set_node_ptr (qsmm_t model, qsmm_sig_t node, int ptr_idx, void *ptr_p)

This function associates a pointer ptr_p with a node of a multinode model. The argument node specifies the identifier of the node. You can fetch the pointer later by index ptr_idx. If a pointer with this index already exists, the function overwrites it.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument ptr_idx is negative.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


4.3 Executing a Multinode Model

Executing a multinode model is executing its nodes in a model instance scope. The function qsmm_node_call_default starts executing a node. An executed node can call other nodes or finish its own execution causing that function to return control. Executed nodes use a call stack similar to a function call stack. Stack frames can contain application-specific information usable in event handler functions.

The execution of a node consists of a series of assembler instruction invocations changing the current state of the node and performing custom operations as a side effect. The event handler function of an instruction meta-class processes the invocation of assembler instructions belonging to instruction classes derived from the instruction meta-class. An invoked instruction returns an outcome used by the environment state identification engine to select the next node state.

As a side effect of an instruction invocation, the event handler function of an instruction meta-class can increment continuous time, change spur tracked by the environment state identification engine or instruction emitting engine, or modify look-ahead signals taking part in selecting the next node state. If the multinode model operates correctly, state models of executed nodes adapt to achieve higher spur increment velocity.

To evaluate whether a model provides adaptive behavior, a developer can compare the efficiency of the model in adaptive mode of operation with the efficiency in random mode of operation.


4.3.1 Event Handler Call Parameters

The event handler function of an instruction meta-class and the event handler function of an instruction class set have the argument ‘qsmm_mehcall_t mehcall’ for retrieving and modifying the parameters of an event.

Data type: qsmm_mehcall_t

This is a type for a handle of container of parameters for a call to the event handler function of an instruction meta-class or instruction class set. The event handler functions have the argument mehcall for passing the handle. In the type name, “mehcall” is the abbreviation of “Model Event Handler CALL.” Functions belonging to the Model Event Handler Call API take an argument of qsmm_mehcall_t type for retrieving and setting various event parameters. The type is a pointer to the structure qsmm_mehcall_s and has the following definition:

typedef struct qsmm_mehcall_s *qsmm_mehcall_t;

You can dereference the variables of this type. They can have the NULL value.

Below there is a description of a structure pointed to by the type qsmm_mehcall_t.

Structure: qsmm_mehcall_s

This structure holds the parameters of a call to the event handler of an instruction meta-class or instruction class set. The structure contains the following fields.

Field: int evt

Event type. See Event Handling, for a description of events sent to the event handler of an instruction meta-class. See Event Handling, for a description of events sent to the event handler of an instruction class set.

Field: qsmm_sig_t node

The identifier of a node associated with the event. For an event QSMM_EVT_ACTIVATE sent to the event handler of an instruction meta-class, it is the identifier of a node that invoked an instruction. For an event QSMM_EVT_NODE_ENTER sent to the event handler of an instruction class set, it is the identifier of a node that receives control. For an event QSMM_EVT_NODE_LEAVE sent to the event handler of an instruction class set, it is the identifier of a node that returns control. For other events, the identifier is equal to QSMM_SIG_INVALID.

Field: void *param_p

A user parameter. For the event handler of an instruction meta-class, it is a user parameter passed to the function qsmm_reg_instr_meta_class or macro QSMM_REG_INSTR_META_CLASS_PARAM when registering the instruction meta-class. For events QSMM_EVT_NODE_ENTER and QSMM_EVT_NODE_LEAVE sent to the event handler of an instruction class set, it is a user parameter passed to the function qsmm_node_call_default. For other events sent to the event handler of an instruction class set, it is a user parameter passed to the function qsmm_reg_instr_class_set or macro QSMM_REG_INSTR_CLASS_SET_PARAM when registering the instruction class set.

Field: void *priv_p

Opaque parameters. Functions belonging to the Model Event Handler Call API listed in this section can access them.

The following table lists the parameters of a model event handler call, functions for querying and setting them, and references to manual sections describing the functions.

ParameterFunction and Applicable EventsReference to a Section
The flag indicating whether to return control from a nodeQuerying:
qsmm_get_mehcall_return
(instruction meta-class –
QSMM_EVT_ACTIVATE,
instruction class set –
QSMM_EVT_NODE_ENTER)

Setting:
qsmm_set_mehcall_return
(instruction meta-class –
QSMM_EVT_ACTIVATE,
instruction class set –
QSMM_EVT_NODE_ENTER)
Returning Control from a Node
The number of frames in the node call stackQuerying:
qsmm_get_mehcall_stack_sz
Working with the Node Call Stack
The identifier of a node in the node call stackQuerying:
qsmm_get_mehcall_stack_node
Working with the Node Call Stack
The index of a current node state in the node call stackQuerying:
qsmm_get_mehcall_stack_state
Working with the Node Call Stack
The index of an instruction class in the node call stackQuerying:
qsmm_get_mehcall_stack_instr_class
Working with the Node Call Stack
A user frame in the node call stackRetrieving:
qsmm_get_mehcall_stack_frame
Working with the Node Call Stack
Instruction meta-class nameQuerying:
qsmm_get_mehcall_instr_meta_class
(instruction meta-class – all events)
Instruction Class Identifiers
Instruction class set nameQuerying:
qsmm_get_mehcall_instr_class_set
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT,
QSMM_EVT_INSTR_CLASS_DONE,
QSMM_EVT_ACTIVATE,
instruction class set – all events)
Instruction Class Identifiers
Binary parameters of an instruction classQuerying:
qsmm_get_mehcall_instr_param_bin
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT,
QSMM_EVT_INSTR_CLASS_DONE,
QSMM_EVT_ACTIVATE)
Accessing Binary Instruction Parameters
Text parameters of an instruction classQuerying:
qsmm_get_mehcall_instr_param_str
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT,
QSMM_EVT_INSTR_CLASS_DONE,
QSMM_EVT_ACTIVATE)

Setting:
qsmm_set_mehcall_instr_param_f,
qsmm_set_mehcall_instr_param_fv
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT)
Registering Instruction Classes
The number of instruction outcomesQuerying:
qsmm_get_mehcall_noutcome
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT,
QSMM_EVT_INSTR_CLASS_DONE,
QSMM_EVT_ACTIVATE)

Setting:
qsmm_set_mehcall_noutcome,
(instruction meta-class –
QSMM_EVT_INSTR_CLASS_INIT)
Setting the Number of Instruction Outcomes
Instruction outcomeQuerying:
qsmm_get_mehcall_outcome
(instruction meta-class –
QSMM_EVT_ACTIVATE)

Setting:
qsmm_set_mehcall_outcome
(instruction meta-class –
QSMM_EVT_ACTIVATE)
Handling Instruction Invocation
The probability of last state transition performedRetrieving:
qsmm_get_mehcall_prob_goto
Handling Instruction Invocation
The probability of last instruction invoked in a stateRetrieving:
qsmm_get_mehcall_prob_action
Handling Instruction Invocation
Multinode model handleRetrieving:
qsmm_get_mehcall_model
This section

The handle of a multinode model associated with a call to the event handler of an instruction meta-class or instruction class set is available via the argument qsmm of that event handler and via the function described below.

Function: qsmm_t qsmm_get_mehcall_model (qsmm_mehcall_t mehcall)

This function returns the handle of a multinode model associated with an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. The function never returns NULL.


4.3.2 Transferring Control between Nodes

The function qsmm_node_call_default transfers control to a node. That function exits when node execution finishes. The event handler of an instruction meta-class can call that function to transfer control to another node in a nested manner while processing an instruction invocation.

To finish the execution of a node, call the function qsmm_set_mehcall_return with flag equal to 1 while handling an instruction invocation for the node.

To terminate the execution of a model, for example, after processing all input data, call the macro QSMM_TERMINATE or the function qsmm_set_continue with flag equal to 0 while handling an instruction invocation. They cause finishing the execution of all nodes in the node call stack. Event handlers of instruction meta-classes may need to analyze a flag returned by the function qsmm_get_continue after a call to qsmm_node_call_default to perform exit from the event handlers as soon as possible on terminating model execution.


4.3.2.1 Calling a Node

Use the following function to call a node.

Function: int qsmm_node_call_default (qsmm_t model, qsmm_sig_t node, void *paramp)

This function transfers control to a node with identifier node in a multinode model, resets current node state, executes the node, and exits when node execution finishes. While processing instruction invocations, event handlers of instruction meta-classes can call this function recursively, including multiple times for the same node.

At the beginning of its execution, the function creates a model instance if it does not exist and checks the flag retrievable by the function qsmm_get_continue (see Terminating Model Execution). If that flag indicates terminating model execution, qsmm_node_call_default exits.

Transferring control to the node begins with sending an event QSMM_EVT_NODE_ENTER to the instruction class set of the node with passing a parameter paramp to the event handler. If after sending the event, the flag retrievable by qsmm_get_continue indicates terminating model execution, or the flag retrievable by the function qsmm_get_mehcall_return (see Returning Control from a Node) indicates terminating node execution, or the node no longer exists, qsmm_node_call_default exits.

If the node does not have a probability profile specified, the environment state identification engine or instruction emitting engine is a large actor, and the maximum number of nodes specified using the field nnode_max of qsmm_desc_s structure when creating the model is greater than 1, the function loads into the node an assembler program defining a default uniform probability profile with the number of states retrievable by the function qsmm_get_node_nstate_v2 (see Creating Nodes).

After possible loading a default uniform probability profile, the function qsmm_node_call_default saves the first four signals of a tuple encoding a current action choice state of the environment state identification engine. See Figure 4.2, for the structure of this tuple. The function restores the saved four signals in the tuple at the end of function execution.

The function then enters a loop where it identifies a current node state by the environment state identification engine, selects an instruction class by the instruction emitting engine, and invokes an individual instruction or instruction sequence. On invoking an individual instruction, the function sends an event QSMM_EVT_ACTIVATE to the instruction meta-class of the individual instruction class. On invoking an instruction sequence, the function sends events QSMM_EVT_ACTIVATE to instruction meta-classes of individual instruction classes comprising the sequence. The function exits the loop if the flag retrievable by qsmm_get_continue indicates terminating model execution, or the flag retrievable by qsmm_get_mehcall_return indicates terminating node execution, or the node no longer exists.

Note: on deterministic identification (selection) of a current node state or deterministic selection of an individual instruction or instruction sequence, qsmm_node_call_default updates the fields sig_cycle_next and tmd0 in the structure qsmm_state_s but does not call the functions qsmm_actor_reg_ngram_in, qsmm_actor_calc_action_prob, and qsmm_get_actor_sig_action for the environment state identification engine or instruction emitting engine leaving discrete time tracked by the engine unchanged.

Before returning control to a caller, if qsmm_node_call_default sent the event QSMM_EVT_NODE_ENTER to the instruction class set, qsmm_node_call_default sends an event QSMM_EVT_NODE_LEAVE to the instruction class set with passing paramp to the event handler.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_OUTCOME

While processing an instruction invocation, the event handler of an instruction meta-class set an invalid instruction outcome or did not set an instruction outcome when it was necessary to do so. This error leaves the multinode model in inconsistent state.

QSMM_ERR_STACKOVR

The number of frames in the node call stack would exceed a value specified in the field stack_sz_max of qsmm_desc_s structure when creating the multinode model. The function qsmm_get_stack_sz_max returns the value.

QSMM_ERR_NGRAM

The content of a signal array encoding a current action choice state of the environment state identification engine accessible by the function qsmm_get_actor_sig_ngram is invalid.

QSMM_ERR_NOCHOICE

All instruction classes have zero weights, or weights of output signals of the environment state identification engine or instruction emitting engine are unexpectedly zero, or the probability profile of the environment state identification engine or instruction emitting engine is inconsistent.

QSMM_ERR_NOIC

The instruction class set does not contain instruction classes.

QSMM_ERR_NOPROF

The function cannot generate a uniform probability profile for the node, because state transition matrices of all nodes have the restriction to define only deterministic state transitions (field engine_desc[QSMM_ENGINE_ENV].is_determ of qsmm_desc_s structure is non-zero), or the instruction class set contains multiple instruction classes on condition that action emission matrices of all nodes have the restriction to define only deterministic action emissions (field engine_desc[QSMM_ENGINE_IEE].is_determ of qsmm_desc_s is non-zero). It is necessary to load a probability profile into the node explicitly.

QSMM_ERR_NOTSUP

The function cannot load a default uniform probability profile into the node, because the multinode model has positive length of look-ahead signal segment. The field ngram_env_la_sz of qsmm_desc_s structure specifies this length when creating a multinode model.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal assigned to the environment state identification engine or instruction emitting engine reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function. This error leaves the multinode model in inconsistent state.

QSMM_ERR_INFIN

The function qsmm_actor_reg_ngram_in or qsmm_get_actor_sig_action called for the environment state identification engine or instruction emitting engine reported QSMM_ERR_INFIN. This error leaves the multinode model in inconsistent state.

QSMM_ERR_UNTIMELY

A handler of QSMM_EVT_NODE_ENTER event sent to the instruction class set or a handler of QSMM_EVT_ACTIVATE event sent to the instruction meta-class destroyed the model instance.

QSMM_ERR_STORAGE

A Storage API function reported storage failure. This error can leave the multinode model in inconsistent state.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected. This error can leave the multinode model in inconsistent state.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale. This error can leave the multinode model in inconsistent state.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation. This error can leave the multinode model in inconsistent state.

Use the following function to get the number of calls of a node since creating the model instance.

Function: int qsmm_get_node_fq (qsmm_t model, qsmm_sig_t node, long *fq_p)

This function retrieves the number of calls to a node with identifier node in a multinode model by the function qsmm_node_call_default since creating the model instance. If the model instance does not exist, the retrieved number of calls is 0. If fq_p is not NULL, the function sets *fq_p to a retrieved number of calls.

On success, the function returns a non-negative value. If the node does not exist, the function returns negative error code QSMM_ERR_NOTFOUND.

Use the function described below to get the number of nested calls to a node. You can use this function to prevent recursive calling a node if the model does not support recursive node calls.

Function: int qsmm_get_node_recurs (qsmm_t model, qsmm_sig_t node)

On success, this function returns a non-negative number of nested calls to a node with identifier node in a multinode model by the function qsmm_node_call_default. If the node does not exist, the function qsmm_get_node_recurs returns negative error code QSMM_ERR_NOTFOUND.


4.3.2.2 Returning Control from a Node

An event QSMM_EVT_NODE_ENTER sent to an instruction class set and an event QSMM_EVT_ACTIVATE sent to an instruction meta-class have an associated flag indicating whether the function qsmm_node_call_default should finish node execution and exit after the call to an event handler. That function resets the flag before calling the event handler. On finishing node execution, the function sends an event QSMM_EVT_NODE_LEAVE to the instruction class set.

Use the following functions in an event handler to query or set the flag causing to return from the last nested call to qsmm_node_call_default. In case of setting the flag while processing an event QSMM_EVT_ACTIVATE by the event handler of an instruction meta-class, qsmm_node_call_default ignores a set instruction outcome.

Function: int qsmm_get_mehcall_return (qsmm_mehcall_t mehcall)

This function returns the flag indicating whether the function qsmm_node_call_default should exit after processing an event, where mehcall is an event handler function argument.

A positive flag value means “true,” and zero flag value means “false.” If the context of calling qsmm_get_mehcall_return is not the event handler of an instruction class set on processing an event QSMM_EVT_NODE_ENTER and not the event handler of an instruction meta-class on processing an event QSMM_EVT_ACTIVATE, the function returns negative error code QSMM_ERR_UNTIMELY.

Function: int qsmm_set_mehcall_return (qsmm_mehcall_t mehcall, int flag)

This function sets the flag indicating whether the function qsmm_node_call_default should exit after processing an event, where mehcall is an event handler function argument. A positive value of flag means “true,” and zero value of flag means “false.”

On success, the function returns a non-negative value. If the context of calling qsmm_set_mehcall_return is not the event handler of an instruction class set on processing an event QSMM_EVT_NODE_ENTER and not the event handler of an instruction meta-class on processing an event QSMM_EVT_ACTIVATE, the function returns negative error code QSMM_ERR_UNTIMELY.


4.3.2.3 Terminating Model Execution

Model execution terminates after processing all input data or performing a course of interaction with external entities—all nodes return control, and the node call stack becomes empty.

The model instance has a flag indicating whether or not to continue model execution: the flag set to “true” indicates to continue model execution, and the flag set to “false” indicates to terminate model execution with reporting success. The function qsmm_engine_create initializes the flag to “true” when creating the model instance.

Use the following functions to query or set the flag.

Function: int qsmm_get_continue (qsmm_t model)

This function returns the flag specifying whether or not to continue the execution of a multinode model.

A positive flag value means “true,” and zero flag value means “false.” If the model instance does not exist, the function returns negative error code QSMM_ERR_UNTIMELY.

Function: int qsmm_set_continue (qsmm_t model, int flag)

This function sets the flag specifying whether or not to continue the execution of a multinode model. A positive value of flag means “true,” and zero value of flag means “false.”

On success, the function returns a non-negative value. If the model instance does not exist, the function returns negative error code QSMM_ERR_UNTIMELY.

The flag set to “false” causes returning from all nested calls to the function qsmm_node_call_default as after calling the function qsmm_set_mehcall_return with a non-zero flag in event handlers of instruction meta-classes on processing events QSMM_EVT_ACTIVATE for all nodes in the node call stack. The function qsmm_node_call_default checks the flag at the beginning of its execution, and, if the flag is “false,” the function exits immediately. This function also checks the flag (and possibly exits) after sending an event QSMM_EVT_NODE_ENTER to the instruction class set and after sending an event QSMM_EVT_ACTIVATE to an instruction meta-class. The event handler of an instruction meta-class can analyze the flag explicitly by calling the function qsmm_get_continue after a call to qsmm_node_call_default while processing an event QSMM_EVT_ACTIVATE to perform immediate exit from the event handler in case of terminating model execution.

Use the following macro to set the flag to “false.”

Macro: QSMM_TERMINATE ()

This macro expands to:

qsmm_set_continue((qsmm), 0)

You can use this macro to terminate the execution of a multinode model from within an event handler, where its argument qsmm is equal to the handle of the multinode model.

For example, you can call this macro in a block of code handling the invocation of an instruction (in the event handler of an instruction meta-class on processing an event QSMM_EVT_ACTIVATE) to terminate the execution of a multinode model when the instruction fetched all input data of the multinode model.


4.3.3 Handling Instruction Invocation

During the execution of a multinode model, its nodes execute instructions. When a node has to invoke an instruction, the node triggers an event QSMM_EVT_ACTIVATE of the instruction meta-class of the instruction.

On triggering the event QSMM_EVT_ACTIVATE, the function qsmm_node_call_default passes the identifier of the node to the event handler of that instruction meta-class via mehcall->node, where mehcall is the argument of that event handler. The event handler can fetch binary instruction class parameters for the instruction by calling the function qsmm_get_mehcall_instr_param_bin. The function qsmm_get_mehcall_instr_class_set retrieves the name of an instruction class set containing the instruction class. Use the following call to fetch from the current frame of node call stack (see Working with the Node Call Stack) index idx that uniquely identifies the instruction class in the instruction class set:

qsmm_get_mehcall_stack_instr_class(mehcall,0,&idx);

While processing an event QSMM_EVT_ACTIVATE, the event handler of an instruction meta-class can perform custom effective work or:

  1. Set an instruction outcome by the function qsmm_set_mehcall_outcome. This operation is mandatory in certain cases.
  2. Increment current values of spur and continuous time by the functions qsmm_actor_spur_delta and qsmm_actor_time_delta_v2 called for the environment state identification engine or instruction emitting engine.
  3. Call nodes by the function qsmm_node_call_default. See Calling a Node.
  4. Return control to a caller node by the function qsmm_set_mehcall_return. See Returning Control from a Node.
  5. Terminate model execution by the function qsmm_set_continue or macro QSMM_TERMINATE. See Terminating Model Execution.
  6. Access user frames in the node call stack obtained by the function qsmm_get_mehcall_stack_frame. See Working with the Node Call Stack.
  7. Change look-ahead signals by the function qsmm_set_la_sig. See Setting Look-Ahead Signals.
  8. Change weights of instruction classes by the functions qsmm_set_instr_class_weight and qsmm_set_instr_class_weight_by_name_f. See Setting Instruction Classes Weights.

An instruction outcome affects the selection of next node state after an instruction invocation. Use the following functions to query or set an instruction outcome.

Function: int qsmm_get_mehcall_outcome (qsmm_mehcall_t mehcall, qsmm_sig_t *outcome_p)

This function retrieves an instruction outcome associated with an event QSMM_EVT_ACTIVATE sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. If outcome_p is not NULL, the function sets *outcome_p to a retrieved outcome.

An instruction outcome associated with the event is the last instruction outcome set by the function qsmm_set_mehcall_outcome while handling the event. If there was no call to qsmm_set_mehcall_outcome, and the instruction class has a positive number of outcomes, the instruction outcome returned is QSMM_SIG_INVALID. If there was no call to qsmm_set_mehcall_outcome, and the instruction class has zero number of outcomes, instruction outcome returned is the outcome of the previous instruction invoked by the node after transferring control to it or 0 if there was no such instruction.

On success, the function returns a non-negative value. If the context of calling the function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_ACTIVATE, the function returns negative error code QSMM_ERR_UNTIMELY.

Function: int qsmm_set_mehcall_outcome (qsmm_mehcall_t mehcall, qsmm_sig_t outcome)

This function sets to outcome instruction outcome associated with an event QSMM_EVT_ACTIVATE sent to the event handler of an instruction meta-class, where mehcall is an argument of that event handler passing information about the event. The function performs only a preliminary check on the validity of that outcome. The function qsmm_node_call_default performs final checks after a return from the event handler, and, if the outcome is invalid, that function reports QSMM_ERR_OUTCOME.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument outcome is greater than or equal to QSMM_SIG_MAX and is not QSMM_SIG_INVALID.

QSMM_ERR_UNTIMELY

The context of calling the function is not the event handler of an instruction meta-class on processing an event QSMM_EVT_ACTIVATE.

The function qsmm_set_mehcall_noutcome specifies the number of instruction outcomes during instruction class initialization (on processing an event QSMM_EVT_INSTR_CLASS_INIT by the event handler of an instruction meta-class). The default number of instruction outcomes used in case of omitting a call to that function is equal to 1. The number of instruction outcomes equal to 0 has special meaning.

Before calling the event handler of an instruction meta-class to process an event QSMM_EVT_ACTIVATE, the function qsmm_node_call_default sets instruction outcome associated with the event to QSMM_SIG_INVALID if the instruction class has a positive number of outcomes. If the instruction class has zero number of outcomes, qsmm_node_call_default sets instruction outcome associated with the event to the outcome of the previous instruction invoked by the node after transferring control to it or to 0 if there was no such instruction.

After calling the event handler of an instruction meta-class to process an event QSMM_EVT_ACTIVATE, if node execution continues, instruction outcome associated with the event is QSMM_SIG_INVALID, and the number of outcomes of the instruction class is equal to 1, qsmm_node_call_default uses outcome 0 to select the next node state. This behavior makes it possible to omit calls to the function qsmm_set_mehcall_outcome for instruction classes with only one possible instruction outcome.

If after calling the event handler node execution continues, instruction outcome associated with the event is QSMM_SIG_INVALID, and the number of outcomes of the instruction class is not equal to 1, qsmm_node_call_default reports QSMM_ERR_OUTCOME. This check compels to set an instruction outcome by qsmm_set_mehcall_outcome if the number of outcomes of the instruction class is greater than 1.

If the instruction class has zero number of outcomes, the event handler of a corresponding instruction meta-class can call the function qsmm_get_mehcall_outcome on processing an event QSMM_EVT_ACTIVATE to analyze the outcome of the previous instruction invoked by the node after transferring control to it. The event handler can leave that outcome intact or change it to a value less than the maximum number among numbers of outcomes of instruction classes in the instruction class set of that node.

The functions described below return the probability of the last state transition for a currently executed node and the probability of the last instruction emission in a current node state. The probabilities have the type QSMM_PROB_AGGR and are in the cells of the state transition matrix and action emission matrix of the node. You can call the functions while processing an event QSMM_EVT_ACTIVATE by the event handler of an instruction meta-class, for example, to compute the time when an instruction has to take effect.

Function: double qsmm_get_mehcall_prob_goto (qsmm_mehcall_t mehcall)

This function returns the probability of the last state transition performed just before the last instruction invocation. That probability has the type QSMM_PROB_AGGR and is in a cell of a state transition matrix. You should call the function from within an event handler, where mehcall is its argument. If a model instance does not exist, or model nodes did not yet invoke instructions, the function returns 0. A returned value is always in the range 0 to 1 inclusive.

Function: double qsmm_get_mehcall_prob_action (qsmm_mehcall_t mehcall)

This function returns the probability of the last instruction emission in a current node state just after performing the last state transition. That probability has the type QSMM_PROB_AGGR and is in a cell of an action emission matrix. You should call the function from within an event handler, where mehcall is its argument. If a model instance does not exist, or model nodes did not yet invoke instructions, the function returns 0. A returned value is always in the range 0 to 1 inclusive.

To make it possible for a multinode model to adapt and improve its behavior, a program supplies spur and continuous time increments to the environment state identification engine or instruction emitting engine while handling instruction invocations.

Use the following lines of code to supply a spur increment and continuous time increment to the environment state identification engine from within an event handler function, where qsmm is its argument.

int rc;
const qsmm_actpair_t actpair=qsmm_get_actpair(qsmm);
const qsmm_actor_t actor_env=qsmm_get_actpair_actor(actpair,
                                                    QSMM_ENGINE_ENV);
if ((rc=
     qsmm_actor_spur_delta(actor_env, spur_type,
                           spur_delta))<0)
    REPORT_ERROR(rc);
if ((rc=
     qsmm_actor_time_delta_v2(actor_env, time_type, 0,
                              time_delta))<0)
    REPORT_ERROR(rc);

Use similar lines of code to supply a spur increment and continuous time increment to an instruction emitting engine.

const qsmm_actor_t actor_iee=qsmm_get_actpair_actor(actpair,
                                                    QSMM_ENGINE_IEE);
if ((rc=
     qsmm_actor_spur_delta(actor_iee, spur_type,
                           spur_delta))<0)
    REPORT_ERROR(rc);
if ((rc=
     qsmm_actor_time_delta_v2(actor_iee, time_type, 0,
                              time_delta))<0)
    REPORT_ERROR(rc);

4.3.4 Setting Look-Ahead Signals

Look-ahead signals are signals that along with the previous node state, an instruction class index, and an instruction outcome take part in selecting the next node state after an instruction invocation. The adjective “look-ahead” indicates that in some situations the signals can convey look-ahead information. For example, when processing a sequence of symbols from left to right, a multinode model can analyze look-ahead symbols as look-ahead signals. In other situations, the signals can pass even look-back information to the model.

When creating a multinode model by the function qsmm_create, the fields ngram_env_la_sz, nsig_ngram_env_la, and range_sig_env_la_p of qsmm_desc_s structure specify look-ahead signal segment length and ranges of signals assignable to segment elements. You can retrieve the mentioned parameters later by the functions qsmm_get_ngram_env_la_sz and qsmm_get_nsig_ngram_env_la called for the multinode model and by the function qsmm_get_actor_range_sig called for the environment state identification engine.

An important limitation imposed on a multinode model when its look-ahead signal segment has positive length is that the function qsmm_node_asm cannot load assembler programs into the nodes of the model. The limitation also prevents loading default uniform probability profiles into the nodes using implicitly generated assembler programs when the maximum number of nodes in the model specified by the field nnode_max of qsmm_desc_s is greater than 1 and the environment state identification engine or instruction emitting engine is a large actor—in this case, the model is unusable. Therefore, if you need to use a look-ahead signal segment with positive length for a model with the environment state identification engine or instruction emitting engine represented by a large actor, set the maximum number of nodes in the model to 1 when creating it.

Use functions described below to query or set signals in the look-ahead signal segment at specific positions. You can call the functions at any point after creating a multinode model. For example, you can call them while processing an event QSMM_EVT_NODE_ENTER by the event handler of an instruction class set or an event QSMM_EVT_ACTIVATE by the event handler of an instruction meta-class.

If a model instance exists, the functions access look-ahead signals in a buffer holding an array of signals encoding current action choice state of environment state identification engine. The buffer is accessible by the function qsmm_get_actor_sig_ngram. If a model instance does not exist, the functions access another buffer initialized on creating a multinode model. On creating a model instance, the function qsmm_engine_create copies the latter buffer to the former one. On destroying a model instance, the function qsmm_engine_destroy copies the former buffer to the latter one.

Function: int qsmm_get_la_sig (qsmm_t model, int pos, qsmm_sig_t *sigp)

If sigp is not NULL, this function sets *sigp to an element of look-ahead signal segment of a multinode model at position pos.

On success, the function returns a non-negative value. If pos is negative or greater than or equal to the length of look-ahead signal segment, the function returns negative error code QSMM_ERR_INVAL.

Function: int qsmm_set_la_sig (qsmm_t model, int pos, qsmm_sig_t sig)

This function sets an element of look-ahead signal segment of a multinode model at position pos to sig.

On success, the function returns a non-negative value. If pos is negative or greater than or equal to the length of look-ahead signal segment, or sig does not fall into a range of allowed signal identifiers at position pos in the look-ahead signal segment, the function returns negative error code QSMM_ERR_INVAL.

If the field range_sig_env_la_p of qsmm_desc_s structure is NULL, the function qsmm_create initializes the elements of look-ahead signal segment to 0. If that field is not NULL, qsmm_create initializes the elements of look-ahead signal segment to the values of first field in the corresponding elements of range_sig_env_la_p array.

See the file tests/lookup2.c for an example program that uses the look-ahead signal segment.


4.3.5 Setting Instruction Classes Weights

If the field dont_use_instr_class_weights of qsmm_desc_s structure passed to the function qsmm_create when creating a multinode model is zero, and the instruction emitting engine is a small actor, you can assign weights to instruction classes executed3 by a node. The weights are multipliers for calculated probabilities of selection of the instruction classes by the instruction emitting engine assigned to its output signals by the function qsmm_set_actor_sig_weight. The function qsmm_node_create_v2 initializes to 1 weights of all instruction classes executable by a node.

Warning: changing weights of instruction classes leads to ill-defined behavior of built-in functions for computing the relative probability of an output signal by the instruction emitting engine. Therefore, avoid changing weights of instruction classes if you use the built-in functions. See Number of Output Signals, for the explanation why the behavior becomes ill-defined.

You can use the following functions to query or set the weight of an instruction class specified by its index uniquely identifying the instruction class in an instruction class set.

Function: int qsmm_get_instr_class_weight (qsmm_t model, qsmm_sig_t node, qsmm_sig_t instr_class, double *weight_p)

This function retrieves the weight of an instruction class executable by a node of a multinode model. The argument node specifies the identifier of the node. The argument instr_class specifies the index of the instruction class in the instruction class set of the node. If weight_p is not NULL, the function sets *weight_p to retrieved weight.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_INVAL

The argument instr_class is greater than or equal to the number of instruction classes in the instruction class set of the node.

QSMM_ERR_NOTSUP

The multinode model does not support assigning weights to instruction classes.

Function: int qsmm_set_instr_class_weight (qsmm_t model, qsmm_sig_t node, qsmm_sig_t instr_class, double weight)

This function sets to weight the weight of an instruction class executable by a node of a multinode model. The argument node specifies the identifier of the node. The argument instr_class specifies the index of the instruction class in the instruction class set of the node.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_INVAL

The argument weight is negative or not finite, or instr_class is greater than or equal to the number of instruction classes in the instruction class set of the node.

QSMM_ERR_NOTSUP

The multinode model does not support assigning weights to instruction classes.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to query or set the weight of an instruction class specified by its name consisting of an instruction meta-class name and optional text parameters of the instruction class.

Function: int qsmm_get_instr_class_weight_by_name_f (qsmm_t model, qsmm_sig_t node, double *weight_p, const char *fmt, ...)
Function: int qsmm_set_instr_class_weight_by_name_f (qsmm_t model, qsmm_sig_t node, double weight, const char *fmt, ...)

The function qsmm_get_instr_class_weight_by_name_f retrieves the weight of an instruction class executable by a node of a multinode model. If weight_p is not NULL, the function sets *weight_p to retrieved weight. The function qsmm_set_instr_class_weight_by_name_f sets to weight the weight of an instruction class executable by a node of a multinode model.

The argument node specifies the identifier of the node. The argument fmt and subsequent arguments interpreted similarly to the function printf specify an instruction class name: a sequence of zero or more whitespace characters, an instruction meta-class name optionally followed by a sequence of one or more whitespace characters and text instruction class parameters, and a sequence of zero or more whitespace characters.

Before searching an instruction class in an instruction class set, the functions convert a formatted instruction class name to the canonical form: an instruction meta-class name optionally followed by the space character and text instruction class parameters converted to their canonical form according to rules described in Setting Text Instruction Parameters.

The functions return a non-negative value on success or a negative error code on failure. Currently, the functions can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist, or the instruction class not found in the instruction class set of the node.

QSMM_ERR_INVAL

The argument weight is negative or not finite, or an instruction class name has invalid format.

QSMM_ERR_NOTSUP

The multinode model does not support assigning weights to instruction classes.

QSMM_ERR_ILSEQ

Unable to convert an instruction class name to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The following call sets the weight of ‘move north’ instruction class to 0 to disable moving an agent in the north direction:

qsmm_set_instr_class_weight_by_name_f(qsmm,node,0,"move north");

A node has an internal array holding weights of instruction classes executable by the node. On transferring control to the node (calling it or returning control to it from another node), the function qsmm_node_call_default sets weights of output signals of instruction emitting engine equal to weights stored in the internal array. The aforementioned functions for setting weights of instruction classes immediately update weights of corresponding output signals of instruction emitting engine if the model instance exists, the node call stack is not empty, and the identifier of a currently executed node is equal to node. Otherwise, the functions update the weights in the internal array.


4.3.6 Working with the Node Call Stack

An event sent to the event handler of an instruction meta-class or instruction class set has an associated reference to a node call stack containing information about nodes that received control but have not yet returned it. A node can occur in multiple stack frames if calls to it are recursive. The field stack_sz_max of qsmm_desc_s structure specifies a limit on the number of frames in the stack. The function qsmm_get_stack_sz_max returns the limit. The following function returns the current number of frames in the stack.

Function: int qsmm_get_mehcall_stack_sz (qsmm_mehcall_t mehcall)

This function returns the current number of frames in a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. A returned value is always non-negative.

A system stack frame is system part of a frame of node call stack. Each system stack frame contains the following information:

  • The identifier of a called node.
  • The index of the current state of a called node.

    For all stack frames except for the last one, the current state is a state where the event handler of an instruction meta-class called the function qsmm_node_call_default on processing an instruction class invocation to transfer control to a node described by the next stack frame.

    For the last stack frame, the current state is a state where the instruction emitting engine selected the last instruction class.

  • The index of an invoked instruction class. For all stack frames except for the last one, processing an instruction class invocation led to calling the function qsmm_node_call_default, and that function transferred control to a node described by the next stack frame.

Use the following functions to fetch the aforementioned pieces of information from system part of a node call stack frame at specified depth.

Function: int qsmm_get_mehcall_stack_node (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *node_p)

This function fetches the identifier of a called node from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event.

If node_p is not NULL, the function sets *node_p to a fetched node identifier. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

Function: int qsmm_get_mehcall_stack_state (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *state_p)

This function fetches the index of a node state from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. The environment state identification engine has identified the node state.

If state_p is not NULL, the function sets *state_p to a fetched node state or 0 if state is yet unknown (this is the case when the event handler of an instruction class set called this function on processing an event QSMM_EVT_NODE_ENTER). The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

Function: int qsmm_get_mehcall_stack_instr_class (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *instr_class_p)

This function fetches the index of the instruction class of the last invoked instruction from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. The instruction emitting engine has selected that instruction class.

If instr_class_p is not NULL, the function sets *instr_class_p to a fetched instruction class index or QSMM_SIG_INVALID if a called node has not yet invoked any instruction since creating the stack frame. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

See Registering Instruction Classes, for the means of obtaining information about an instruction class specified by its index.

A user stack frame is user part of a frame of node call stack. A user stack frame contains application-specific information associated with a called node for handling instruction invocations—execution context of the node.

A user stack frame is typically an instance of a structure declared in an application program. The purpose of functions described below is to query or set the size of user stack frame. You should set the size of user stack frame before creating a model instance by the function qsmm_engine_create.

Function: size_t qsmm_get_stack_frame_sz (qsmm_t model)

This function returns the size (in bytes) of user part of each frame in the node call stack of a multinode model. If the model does not use the user part, the function returns 0.

Function: int qsmm_set_stack_frame_sz (qsmm_t model, size_t sz)

This function sets the size of user part of each frame in the node call stack of a multinode model to sz bytes. Size 0 means that the model does not use the user part.

The function returns a non-negative value on success or negative error code QSMM_ERR_UNTIMELY if a model instance already exists.

The function qsmm_create initializes to 0 the size of user stack frame.

On calling a node, the function qsmm_node_call_default creates a new frame in the node call stack and initializes user part of the frame with zero bytes. The new frame becomes the current stack frame. The function qsmm_get_mehcall_stack_sz returns the number of used frames in the node call stack.

After creating a current stack frame, qsmm_node_call_default sends an event QSMM_EVT_NODE_ENTER to the instruction class set of a called node. The event handler of that instruction class set can process the event to perform application-specific initialization of the stack frame. For example, the event handler may allocate dynamic arrays or copy the parameters of calling the node to the frame. A pointer to the parameters is an argument of qsmm_node_call_default function, and it passes the pointer to the event handler via mehcall->param_p, where mehcall is an event handler argument.

While executing a node, qsmm_node_call_default sends events QSMM_EVT_ACTIVATE to instruction meta-classes of instructions selected for invocation by the instruction emitting engine. The event handler of an instruction meta-class can call the function qsmm_set_mehcall_return with a non-zero flag to return control from the node. The event handler can also call the function qsmm_set_continue with zero flag or the macro QSMM_TERMINATE to return control from all nodes in the node call stack.

On returning control from a node, qsmm_node_call_default sends an event QSMM_EVT_NODE_LEAVE to the instruction class set of the node. The event handler of that instruction class set can use the content of a current stack frame to compute the results of node invocation and return them via a memory block addressed by a pointer mehcall->param_p passed as an argument to qsmm_node_call_default. If necessary, the event handler performs application-specific uninitialization of the stack frame—for example, frees allocated dynamic arrays.

After sending the event QSMM_EVT_NODE_LEAVE, qsmm_node_call_default discards the current stack frame and exits. If after discarding the stack frame the node call stack is not empty, the previous frame in the stack becomes the current frame.

Use the following function to get a pointer to user part of a frame in the node call stack.

Function: int qsmm_get_mehcall_stack_frame (qsmm_mehcall_t mehcall, int depth, void **frame_pp)

This function retrieves a pointer to user part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event.

If frame_pp is not NULL, the function sets *frame_pp equal to the pointer. A program can access a memory block with size in bytes returned by the function qsmm_get_stack_frame_sz addressed by the pointer. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOUSTACK

The model does not have user part in the frames of node call stack. Use the function qsmm_set_stack_frame_sz to specify positive user part size before creating the model instance.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

If the structure stack_frame_s holds a user stack frame, use the following call to set its size:

qsmm_set_stack_frame_sz(qsmm,sizeof(struct stack_frame_s));

To get a pointer to a current stack frame, use these lines in an event handler function:

struct stack_frame_s *stack_frame_p=0;
qsmm_get_mehcall_stack_frame(mehcall,0,(void **) &stack_frame_p);

4.3.7 Switching Adaptive or Random Behavior

A multinode model has either a random number generator provided via the field rng of qsmm_desc_s structure when creating the multinode model or an instance of default random number generator allocated automatically if that field was NULL. The environment state identification engine and instruction emitting engine use that random number generator. The purpose of the following function is to obtain random number generator of a multinode model.

Function: qsmm_rng_t qsmm_get_rng (qsmm_t model)

This function returns the handle of a random number generator used by the environment state identification engine and instruction emitting engine of a multinode model. The function never returns NULL.

You can use returned handle of a random number generator to seed the generator after creating the multinode model or model instance. See Random Number Generators, for how to seed a random number generator and perform other operations on it.

A useful approach to determine the amount of contribution of optimization mechanism provided by QSMM to the optimality of behavior of a multinode model is comparing a measure of optimality for the multinode model behaving adaptively versus a measure of optimality for the model behaving randomly. The greater the difference is between the two values the more contribution the optimization mechanism provided by QSMM makes to the optimality of multinode model behavior.

Use the following function to switch a model instance to random or adaptive (normal) behavior mode.

Function: int qsmm_set_random (qsmm_t model, int flag)

This function switches current mode of behavior of instance of a multinode model to random or adaptive (normal) mode. If flag is non-zero, the function switches the current mode to random mode. If flag is zero, the function switches the current mode to adaptive mode.

The function is a short cut to setting current mode of behavior for the environment state identification engine and instruction emitting engine of a model instance by the function qsmm_set_actor_random.

On success, the function returns a non-negative value. If the model instance does not exist, the function returns negative error code QSMM_ERR_UNTIMELY.

The function qsmm_engine_create initializes current mode of behavior of model instance to adaptive (normal) mode.


4.3.8 Tracing Model Execution

QSMM provides facilities for tracing events related to a multinode model. You can specify types of events dumped to a trace log using a bitmask defined as a subset of the following macros merged by bitwise “or.”

Macro: QSMM_TRACE_API

Multinode model API calls entry and exit. API functions with a model handle argument dump a function name, names and values of function arguments, and a returned value.

Macro: QSMM_TRACE_EVT

The beginning and end of processing every model event by event handlers with dumping event parameters.

Macro: QSMM_TRACE_CTRL

Calling nodes, returning control from nodes, instruction invocations, and their outcomes.

Use the following functions to query or set a bitmask of types of events dumped to a trace log.

Function: unsigned int qsmm_get_trace_flags (qsmm_t model)

This function returns the bitmask of types of events dumped to trace log of a multinode model. The model is the originator of the events. This function returns a bitmask set by the function qsmm_set_trace_flags or a default bitmask (see a remark below) if the latter function not yet called.

Function: void qsmm_set_trace_flags (qsmm_t model, unsigned int flags)

This function sets to flags the bitmask of types of events dumped to trace log of a multinode model. The model is the originator of the events. The function does not check whether the bitmask is correct.

The function qsmm_create initializes the bitmask of types of events dumped to a trace log to 0.

A multinode model does not dump information to a trace log unless the multinode model has an assigned stream for the trace log. Use the following functions to get or set the stream.

Function: FILE * qsmm_get_trace_stream (qsmm_t model)

This function returns a stream for trace log of a multinode model. If the model does not have an assigned stream, the function returns NULL.

Function: void qsmm_set_trace_stream (qsmm_t model, FILE *filep)

This function sets to filep the stream for trace log of a multinode model. The NULL stream disables dumping log messages.

Use the following functions to write a custom formatted message to the trace log.

Function: void qsmm_trace_f (qsmm_t model, const char *fmt, ...)
Function: void qsmm_trace_fv (qsmm_t model, const char *fmt, va_list ap)

The functions write a formatted message to trace log of a multinode model. They append the character ‘\n’ to the message and flush the stream buffer. If the trace stream not set, the functions have no effect. The meaning of fmt argument and subsequent arguments of qsmm_trace_f function is similar to the function printf. The meaning of fmt and ap arguments of qsmm_trace_fv function is similar to the function vprintf.


4.4 Listing a Multinode Model

You can dump the state transition matrix or action emission matrix of a node or all nodes of a multinode model.

To enumerate instruction meta-classes, instruction class sets, and nodes in a multinode model, you use datatypes for entity references.


4.4.1 Dumping the State Transition Matrix

The state transition matrix of a node contains transition probabilities of supported types along with other numeric information. The rows of that matrix biuniquely correspond to quadruples where each quadruple consists of a source transition state, a sequence of one or more user or mixed-type instructions invoked in the source transition state, an instruction sequence outcome, and the content of look-ahead signal segment. The columns of that matrix biuniquely correspond to target transition states. Use the following function to dump a state transition matrix to a stream.

Function: int qsmm_mat_goto_dump_v2 (qsmm_t model, int rez1, qsmm_sig_t node, struct qsmm_dump_mat_goto_desc_s *desc_p, FILE *filep)

This function dumps the state transition matrix of a node of a multinode model to a stream filep according to parameters specified in *desc_p. The argument node specifies the identifier of the node. If node is equal to QSMM_SIG_INVALID, the function dumps state transition matrices of all nodes of the multinode model. If desc_p is NULL, the function uses default dumping parameters. The argument rez1 is for future use and must be equal to 0.

In the current implementation the function does not modify *desc_p if desc_p is not NULL. However, in a future implementation the function may modify *desc_p, for example, to store there statistics on the dumping process.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The argument node is not QSMM_SIG_INVALID, and a node with identifier node does not exist.

QSMM_ERR_INVAL

The argument desc_p is not NULL, and parameters in *desc_p are invalid.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal assigned to the environment state identification engine reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The description of a structure specifying dumping parameters is below.

Structure: qsmm_dump_mat_goto_desc_s

This structure specifies the parameters of dumping the state transition matrix of a node. The structure contains the following fields.

Field: char do_print_prob[QSMM_PROB_COUNT]

An array specifying types of probabilities to dump. Array indices are the elements of qsmm_prob_e enumeration (except for its last element QSMM_PROB_COUNT) described in Emitting an Output Signal. If an array element is non-zero, the function qsmm_mat_goto_dump_v2 dumps probabilities with a corresponding type. The default is to dump probabilities of all types.

Field: int indent

Left indent—the number of spaces to print at the beginning of each line of output. Must be a non-negative value. The default is to use indent 0.

Field: int prob_prec

The number of digits after the decimal point to print for probabilities. If that number is positive, use fixed-point notation. If that number is negative, use exponential notation with the number of digits after the decimal point equal to the absolute value of this field. If that number is zero, use exponential notation with 15 digits after the decimal point; this is the default mode.

Field: long fq_min

The minimum value of fq field of an instance of qsmm_cycle_s structure for a matrix cell. The function qsmm_mat_goto_dump_v2 does not output information on instances with lesser values of fq field (i.e. with lesser frequency). The default is to use minimum frequency 0.

To improve compatibility with future versions of QSMM library, zero by the function memset an instance of qsmm_dump_mat_goto_desc_s structure before setting its fields.

Below there is an example dump fragment. When generating the dump, the element QSMM_PROB_LEARNED of do_print_prob field of qsmm_dump_mat_goto_desc_s structure passed to the function qsmm_mat_goto_dump_v2 was non-zero, and all other elements of this array were zero. The fragment contains truncated fractional parts of numbers in exponential notation to make lines shorter.

* State  83

  A0  |mn| O7 L0 : tmd0=183117, state_next=45,  spur[0].val0=-4E+5, time[0].val0=5E+3

    S45  : pl=1.0E+00,  spur[0].ds=-3E+05, time[0].ds=2E+03,  fq=376, ps_d=148416
    S79  : pl=4.2E-267, spur[0].ds=-4E+04, time[0].ds=3E+03,  fq=3,   ps_d=23976
    S92  : pl=9.1E-283, spur[0].ds=-2E+04, time[0].ds=2E+03,  fq=2,   ps_d=9516

  A0  |mn| O7 L1 : tmd0=183219, state_next=120, spur[0].val0=-3E+5, time[0].val0=1E+4

    S63  : pl=2.2E-245, spur[0].ds=-4E+04, time[0].ds=3E+03,  fq=5,   ps_d=22740
    S87  : pl=2.0E-292, spur[0].ds=-3E+02, time[0].ds=2E+03,  fq=1,   ps_d=156
    S120 : pl=1.0E+00,  spur[0].ds=-3E+05, time[0].ds=3E+03,  fq=119, ps_d=160185

Below there are descriptions of output pieces of information. See Structures for Accessing Storage, for details about referenced structure fields.

Ai

An instruction class invoked by the node in a source transition state. Index i uniquely identifies the instruction class in the instruction class set of the node. For an individual instruction class, its name enclosed between the characters ‘|’ follows the token Ai. For an instruction class sequence, a column of names of individual instruction classes comprising the sequence enclosed between two columns of ‘|’ characters follows the token Ai.

Li

Look-ahead signal i that was in the look-ahead signal segment when the node was in a source transition state. The number of Li tokens is equal to look-ahead signal segment length. Positions of Li tokens are the positions of elements in the look-ahead signal segment.

Oi

Outcome i of an instruction class invoked by the node in a source transition state.

Si

The description of a transition to target state i. If the state has a name assigned by the argument of stt assembler instruction, the name enclosed in double quotes follows the token Si.

RST

This keyword can replace the tokens ‘Ax |name| Oy’ for source transition state 0. The keyword indicates that specified transitions to target states are initial transitions performed just after transferring control to the node. In this situation, the node did not yet invoke instructions, so values x and y are unknown.

fq

The value of fq field of qsmm_cycle_s structure.

pa

Probability of QSMM_PROB_AGGR type.

pf

Probability of QSMM_PROB_FQ type.

pl

Probability of QSMM_PROB_LEARNED type.

pp

Probability of QSMM_PROB_PROFILE type.

ps_d

The value of period_sum_d field of qsmm_cycle_s structure.

spur[i].ds

The value of delta_sum field of qsmm_cspval_s structure for spur type i.

spur[i].val0

The value of val0 field of qsmm_sspval_s structure for spur type i.

State

The index of a source transition state. If the state has a name assigned by the argument of stt assembler instruction, the name enclosed in double quotes follows that index.

state_next

The index of target state of the last transition made from a source state. The field sig_cycle_next of qsmm_state_s structure contains that index. The special value ‘N’ corresponds to the value QSMM_SIG_INVALID of that field.

time[i].ds

The value of delta_sum field of qsmm_cspval_s structure for continuous time type i.

time[i].val0

The value of val0 field of qsmm_sspval_s structure for continuous time type i.

tmd0

The value of tmd0 field of qsmm_state_s structure.

The function qsmm_mat_goto_dump_v2 dumps only descriptions of state transitions that have some information in statistics storage. This approach helps reduce the length of output when dumping a sparse state transition matrix.

When descriptions of some state transitions are absent in the output because of a positive value of fq_min field of qsmm_dump_mat_goto_desc_s structure or because statistics storage does not contain information on some state transitions, the sum of state transition probabilities with a specific type may be less than 1 in a matrix row. If the field fq_min is zero, every not dumped transition has probability (1−p)/n, where p is the sum of probabilities of dumped transitions, and n is the number of not dumped transitions.


4.4.2 Dumping the Action Emission Matrix

The action emission matrix of a node contains the probabilities of emitting all instruction classes belonging to the instruction class set of the node in all its states. The rows of that matrix biuniquely correspond to node states. The columns of that matrix biuniquely correspond to instruction classes in the instruction class set. Use the following function to dump an action emission matrix to a stream.

Function: int qsmm_mat_action_dump_v2 (qsmm_t model, int rez1, qsmm_sig_t node, struct qsmm_dump_mat_action_desc_s *desc_p, FILE *filep)

This function dumps the action emission matrix of a node of a multinode model to a stream filep according to parameters specified in *desc_p. The argument node specifies the identifier of the node. If node is equal to QSMM_SIG_INVALID, the function dumps action emission matrices of all nodes of the multinode model. If desc_p is NULL, the function uses default dumping parameters. The argument rez1 is for future use and must be equal to 0.

In the current implementation the function does not modify *desc_p if desc_p is not NULL. However, in a future implementation the function may modify *desc_p, for example, to store there statistics on the dumping process.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The argument node is not QSMM_SIG_INVALID, and a node with identifier node does not exist.

QSMM_ERR_INVAL

The argument desc_p is not NULL, and parameters in *desc_p are invalid.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal assigned to the instruction emitting engine reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The description of a structure specifying dumping parameters is below.

Structure: qsmm_dump_mat_action_desc_s

This structure specifies the parameters of dumping the action emission matrix of a node. The structure contains the following fields.

Field: char do_print_prob[QSMM_PROB_COUNT]

An array specifying types of probabilities to dump. Array indices are the elements of qsmm_prob_e enumeration (except for its last element QSMM_PROB_COUNT) described in Emitting an Output Signal. If an array element is non-zero, the function qsmm_mat_action_dump_v2 dumps probabilities with a corresponding type. The default is to dump probabilities of all types.

Field: int indent

Left indent—the number of spaces to print at the beginning of each line of output. Must be a non-negative value. The default is to use indent 0.

Field: int prob_prec

The number of digits after the decimal point to print for probabilities. If that number is positive, use fixed-point notation. If that number is negative, use exponential notation with the number of digits after the decimal point equal to the absolute value of this field. If that number is zero, use exponential notation with 15 digits after the decimal point; this is the default mode.

Field: long fq_min

The minimum value of fq field of an instance of qsmm_cycle_s structure for a matrix cell. The function qsmm_mat_action_dump_v2 does not output information on instances with lesser values of fq field (i.e. with lesser frequency). The default is to use minimum frequency 0.

To improve compatibility with future versions of QSMM library, zero by the function memset an instance of qsmm_dump_mat_action_desc_s structure before setting its fields.

Below there is an example dump fragment. When generating the dump, the element QSMM_PROB_LEARNED of do_print_prob field of qsmm_dump_mat_action_desc_s structure passed to the function qsmm_mat_action_dump_v2 was non-zero, and all other elements of this array were zero. The fragment contains truncated fractional parts of numbers in exponential notation to make lines shorter.

* State 1 : tmd0=2711, action_next=0, spur[0].val0=4.00...E+00, time[0].val0=1.20...E+03

  A0 |me| : pl=9.9...E-01, spur[0].ds=4.0...E+00, time[0].ds=8.2...E+02, fq=43, ps_d=1965
  A1 |ms| : pl=3.4...E-03, spur[0].ds=0.0...E+00, time[0].ds=9.8...E+01, fq=49, ps_d=147
  A2 |mw| : pl=3.4...E-03, spur[0].ds=0.0...E+00, time[0].ds=7.2...E+01, fq=36, ps_d=108

Below there are descriptions of output pieces of information. See Structures for Accessing Storage, for details about referenced structure fields.

Ai

Information on an instruction class emitted in a node state. Index i uniquely identifies the instruction class in the instruction class set of the node. For an individual instruction class, its name enclosed between the characters ‘|’ follows the token Ai. For an instruction class sequence, a column of names of individual instruction classes comprising the sequence enclosed between two columns of ‘|’ characters follows the token Ai.

action_next

The index of the last instruction class emitted in a node state. The field sig_cycle_next of qsmm_state_s structure contains that index. The special value ‘N’ corresponds to the value QSMM_SIG_INVALID of that field.

fq

The value of fq field of qsmm_cycle_s structure.

pa

Probability of QSMM_PROB_AGGR type.

pf

Probability of QSMM_PROB_FQ type.

pl

Probability of QSMM_PROB_LEARNED type.

pp

Probability of QSMM_PROB_PROFILE type.

ps_d

The value of period_sum_d field of qsmm_cycle_s structure.

spur[i].ds

The value of delta_sum field of qsmm_cspval_s structure for spur type i.

spur[i].val0

The value of val0 field of qsmm_sspval_s structure for spur type i.

State

The description of a state with a specific index. If the state has a name assigned by the argument of stt assembler instruction, the name enclosed in double quotes follows the index.

time[i].ds

The value of delta_sum field of qsmm_cspval_s structure for continuous time type i.

time[i].val0

The value of val0 field of qsmm_sspval_s structure for continuous time type i.

tmd0

The value of tmd0 field of qsmm_state_s structure.

The function qsmm_mat_action_dump_v2 lists only instruction classes that have some information in statistics storage. This approach helps reduce the length of output when dumping a sparse action emission matrix.

When information on some instruction classes is absent in the output because of a positive value of fq_min field of qsmm_dump_mat_action_desc_s structure or because statistics storage does not contain information on some instruction classes for some node states, the sum of action emission probabilities with a specific type may be less than 1 in a matrix row. If the field fq_min is zero, every not dumped instruction class has emission probability (1−p)/n, where p is the sum of emission probabilities of instruction classes dumped for a node state, and n is the number of instruction classes not dumped for the node state.


4.4.3 Entity References

Entity references identify entities existing in a multinode model. This identification is necessary when enumerating entities in a multinode model and when passing information about entities associated with an occurred error to a model error handler. See Error Handling for a Multinode Model, for information about model error handlers. The header file refe.h contains declarations related to entity references. The notion of an entity referred to by an entity reference has nothing to do with virtual or logical entities represented by state models of nodes of a multinode model.

The basic type of an entity reference is local entity reference. A local entity reference identifies an entity within some known context. The following enumeration declares types of local entity references.

Enumeration: qsmm_lref_e

This enumeration categorizes entities that are parts of a multinode model. The enumeration contains the following elements.

QSMM_LREF_INVALID

Invalid entity type. This element indicates unknown entity type or the type of a nonexistent entity.

QSMM_LREF_INSTR_CLASS_SET

An instruction class set.

QSMM_LREF_INSTR_META_CLASS

An instruction meta-class.

QSMM_LREF_NODE

A node.

QSMM_LREF_PROB_VAR_CTRL

A controlled probability variable. See Controlled Variables.

QSMM_LREF_PROB_VAR_OUT

An output probability variable. See Output Variables.

QSMM_LREF_PROB_ARR_OUT

An output probabilities array. See Output Arrays.

QSMM_LREF_INSTR_CLASS

An individual instruction class.

QSMM_LREF_INSTR_CLASS_SEQ

An instruction class sequence.

QSMM_LREF_COUNT

The number of supported types of local entity references.

The following union represents a local entity identifier for a local entity reference.

Union: qsmm_lref_u

This union holds a local entity identifier for a local entity reference with the type specified by an element of qsmm_lref_e enumeration. The union contains the following fields.

Field: char *name

An entity name. It is applicable to local entity references of QSMM_LREF_INSTR_CLASS_SET, QSMM_LREF_INSTR_META_CLASS, QSMM_LREF_PROB_VAR_CTRL, QSMM_LREF_PROB_VAR_OUT, and QSMM_LREF_PROB_ARR_OUT types.

Field: qsmm_sig_t sig

A local entity identifier represented by a signal. It is applicable to local entity references of QSMM_LREF_NODE type.

Field: struct qsmm_instr_class_s instr_class

An individual instruction class descriptor. It is applicable to local entity references of QSMM_LREF_INSTR_CLASS type.

Field: struct qsmm_instr_class_seq_s instr_class_seq

An instruction class sequence descriptor. It is applicable to local entity references of QSMM_LREF_INSTR_CLASS_SEQ type.

The following structure holds an individual instruction class descriptor stored in the field instr_class of qsmm_lref_u union for local entity references of QSMM_LREF_INSTR_CLASS type.

Structure: qsmm_instr_class_s

This structure holds a descriptor identifying an individual instruction class. The structure contains the following fields.

Field: char *meta_class_name

An instruction meta-class name.

Field: char *param_str_p

Text instruction class parameters in the canonical form (see Setting Text Instruction Parameters). An empty string means empty text parameters. The NULL value means that the text parameters are unknown.

Field: qsmm_sig_t idx

An instruction class index. It uniquely identifies the individual instruction class in an instruction class set. The value QSMM_SIG_INVALID means that the index is unknown.

Field: size_t param_bin_sz

The size of binary instruction class parameters. If binary parameters are unknown, this field must be equal to 0.

Field: void *param_bin_p

Binary instruction class parameters. If this field is not NULL, it must address a memory block with size in bytes specified by the field param_bin_sz. If this field is NULL, then binary parameters are unknown, and the field param_bin_sz must be equal to 0.

The following structure holds an instruction class sequence descriptor stored in the field instr_class_seq of qsmm_lref_u union for local entity references of QSMM_LREF_INSTR_CLASS_SEQ type.

Structure: qsmm_instr_class_seq_s

This structure holds a descriptor identifying an instruction class sequence. The structure contains the following fields.

Field: qsmm_sig_t idx

An instruction class index. It uniquely identifies the instruction class sequence in an instruction class set. The value QSMM_SIG_INVALID means that the index is unknown.

Field: size_t n_elm

The number of individual instruction classes in the instruction class sequence.

Field: struct qsmm_instr_class_s *elm_p

Descriptors of individual instruction classes comprising the instruction class sequence. The field n_elm of this structure specifies the number of elements in the sequence.

The following structure represents a complete local entity reference.

Structure: qsmm_lref_s

This structure holds the type of a local entity reference along with a local entity identifier. The structure contains the following fields.

Field: enum qsmm_lref_e type

The type of a local entity reference.

Field: union qsmm_lref_u val

The value of a local entity reference depending on its type. For the type QSMM_LREF_INVALID, must be a block of zero bytes.

A global entity reference identifies an entity in the address space of a running process. The error handler of a multinode model receives global references to entities related to errors. The type of a global entity reference specifies a method of identifying an entity. The following enumeration declares the types of global entity references.

Enumeration: qsmm_gref_e

This enumeration specifies a method of identification of an entity in the address space of a running process. The enumeration contains the following elements.

QSMM_GREF_INVALID

Invalid global entity reference, including the absence of an entity to identify.

QSMM_GREF_HANDLE_LREF

An object handle and local entity reference. This method of identification is applicable to local entity references of QSMM_LREF_INSTR_CLASS_SET, QSMM_LREF_INSTR_META_CLASS, and QSMM_LREF_NODE types. The object handle has the type QSMM_HANDLE_MODEL and refers to a multinode model containing an instruction class set, instruction meta-class, or node.

QSMM_GREF_HANDLE_LREF2

An object handle, the local entity reference of a container, and the local entity reference of a contained entity. This method of identification is applicable to local entity references of QSMM_LREF_PROB_VAR_CTRL, QSMM_LREF_PROB_VAR_OUT, QSMM_LREF_PROB_ARR_OUT, QSMM_LREF_INSTR_CLASS, and QSMM_LREF_INSTR_CLASS_SEQ types for contained entities. The object handle has the type QSMM_HANDLE_MODEL and refers to a multinode model with the container. The local entity reference of the container has the type QSMM_LREF_NODE for a controlled probability variable, output probability variable, or output probabilities array contained in a node or the type QSMM_LREF_INSTR_CLASS_SET for an individual instruction class or instruction class sequence contained in an instruction class set.

The following union represents a global entity identifier for a global entity reference.

Union: qsmm_gref_u

This union holds a global entity identifier for a global entity reference with the type specified by an element of qsmm_gref_e enumeration. The union contains the following fields.

Field: struct qsmm_handle_lref_s handle_lref

An object handle and local entity reference. This field is for a global entity reference of QSMM_GREF_HANDLE_LREF type.

Field: struct qsmm_handle_lref2_s handle_lref2

An object handle, the local entity reference of a container, and the local entity reference of a contained entity. This field is for a global entity reference of QSMM_GREF_HANDLE_LREF2 type.

The following structure holds an object handle and local entity reference stored in the field handle_lref of qsmm_gref_u union for global entity references of QSMM_GREF_HANDLE_LREF type.

Structure: qsmm_handle_lref_s

This structure holds the handle of an object and a local entity reference for an entity contained in the object. The structure contains the following fields.

Field: struct qsmm_handle_s handle

The handle of a containing object. At present, can only be a handle of QSMM_HANDLE_MODEL type.

Field: struct qsmm_lref_s lref

A local entity reference for an entity contained in an object. At present, can be a local entity reference of QSMM_LREF_INSTR_CLASS_SET, QSMM_LREF_INSTR_META_CLASS, or QSMM_LREF_NODE type, where the containing object is a multinode model.

The following structure holds an object handle, the local entity reference of a container, and the local entity reference of a contained entity. The field handle_lref2 of qsmm_gref_u union holds this triple for global entity references of QSMM_GREF_HANDLE_LREF2 type.

Structure: qsmm_handle_lref2_s

This structure holds the handle of an object, the local entity reference of a container in the object, and a local entity reference for an entity in the container. The structure contains the following fields.

Field: struct qsmm_handle_s handle

The handle of an object. At present, can only be a handle of QSMM_HANDLE_MODEL type.

Field: struct qsmm_lref_s container

The local entity reference of a container in an object. At present, can be a local entity reference of QSMM_LREF_NODE or QSMM_LREF_INSTR_CLASS_SET type, where the containing object is a multinode model.

Field: struct qsmm_lref_s lref

A local entity reference for an entity in a container. At present, can be:

  • a local entity reference of QSMM_LREF_PROB_VAR_CTRL, QSMM_LREF_PROB_VAR_OUT, or QSMM_LREF_PROB_ARR_OUT type for a container specified by a local entity reference of QSMM_LREF_NODE type;
  • a local entity reference of QSMM_LREF_INSTR_CLASS or QSMM_LREF_INSTR_CLASS_SEQ type for a container specified by a local entity reference of QSMM_LREF_INSTR_CLASS_SET type.

The following structure represents a complete global entity reference.

Structure: qsmm_gref_s

This structure holds the type of a global entity reference along with a global entity identifier. The structure contains the following fields.

Field: enum qsmm_gref_e type

The type of a global entity reference.

Field: union qsmm_gref_u val

The value of a global entity reference depending on its type. For the type QSMM_GREF_INVALID, must be a block of zero bytes.


4.4.4 Enumerating Entities

Local entity references of QSMM_LREF_INSTR_META_CLASS and QSMM_LREF_INSTR_CLASS_SET types identify instruction meta-classes and instruction class sets in a multinode model by names. The names are unique in a model context making it possible to use them as names of event handler functions of instruction meta-classes and instruction class sets by default.

Use the following function to enumerate instruction meta-classes, instruction class sets, or nodes in a multinode model.

Function: int qsmm_enum_ent (qsmm_t model, enum qsmm_lref_e ent_type, qsmm_enum_ent_callback_func_t callback_func, void *paramp)

This function enumerates all entities of ent_type type stored in a multinode model. The process of enumeration is repeated calling a callback function callback_func receiving the type of a local entity reference, a local entity identifier, and a user parameter paramp. If the callback function returns a positive value, qsmm_enum_ent continues enumeration. If the callback function returns zero, qsmm_enum_ent terminates enumeration and reports success. If the callback function returns a negative value, qsmm_enum_ent terminates enumeration and reports failure.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument ent_type is not QSMM_LREF_INSTR_META_CLASS, QSMM_LREF_INSTR_CLASS_SET, and QSMM_LREF_NODE.

QSMM_ERR_CALLBACK

The callback function reported an error.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The type of a pointer to a callback function called for every enumerated entity is below.

Data type: qsmm_enum_ent_callback_func_t

This is a type of a callback function pointer with the following declaration:

typedef int
(*qsmm_enum_ent_callback_func_t)(
    qsmm_t model,
    enum qsmm_lref_e lref_type,
    const union qsmm_lref_u *lref_p,
    void *paramp
);

An enumeration function calls the callback function for every enumerated entity of a multinode model. The argument lref_type specifies enumerated entity type as local entity reference type. The argument lref_p specifies an entity identifier as a local entity reference identifier. The argument paramp is a user parameter passed to the enumeration function.

The callback function shall return a positive value to continue the process of enumeration, zero to terminate the process of enumeration, or a negative value on error.

The function qsmm_enum_var_prob uses a callback function of qsmm_enum_ent_callback_func_t type for enumerating controlled probability variables of an instruction class set. The function qsmm_enum_var_prob_out uses this callback function for enumerating output probability variables of a node.

Use the following function to query the type of an entity by its name.

Function: enum qsmm_lref_e qsmm_get_ent_type_by_name (qsmm_t model, const char *ent_name)

This function returns the type of a local entity reference for an entity named ent_name stored in a multinode model. The function only supports local entity references of QSMM_LREF_INSTR_META_CLASS and QSMM_LREF_INSTR_CLASS_SET types. If the entity does not exist or is not an instruction meta-class and instruction class set, the function returns QSMM_LREF_INVALID.


4.5 Error Handling for a Multinode Model

A multinode model can have an error handler assigned to it. The error handler is a function called in the case of a failure in any QSMM API function that takes an argument of qsmm_t type and can return an error code of int type. The default error handler of a multinode model prints information on an occurred error to stderr and calls exit(2). The output consists of the name of that default error handler function followed by an indented description of an error as object content in JSON format. If a multinode model does not have an error handler assigned (including the default error handler), or an error handler assigned to the multinode model does not terminate program execution and returns, a failed API function returns a corresponding error code.

Use the following functions to query or set an error handler for a multinode model.

Function: void qsmm_get_err_handler (qsmm_t model, qsmm_err_handler_func_t *func_p, void **param_pp)

This function retrieves information on an error handler assigned to a multinode model. If func_p is not NULL, the function sets *func_p to the pointer to the error handler function or to NULL if the model does not have an error handler function assigned. If param_pp is not NULL, the function sets *param_pp to the user parameter of that error handler function.

Function: void qsmm_set_err_handler (qsmm_t model, qsmm_err_handler_func_t func, void *paramp)

This function assigns an error handler to a multinode model. The argument func specifies an error handler function. The argument paramp specifies the user parameter of the error handler function. If func is NULL, the model does not use an error handler.

An error handler function receives extended information on some types of errors. The header file err.h included in qsmm.h contains a declaration for the type of an error handler function. The Side API also uses that type for the error handler of an interaction side (see Error Handling, for more information).

Data type: qsmm_err_handler_func_t

This is a type of an error handler function pointer with the following declaration:

typedef void
(*qsmm_err_handler_func_t)(
    void *rez1,
    struct qsmm_except_s *except_p,
    void *paramp
);

The argument except_p passes information on an occurred error. The argument paramp is a user parameter specified when setting the error handler function for a multinode model. You should not access the reserved argument rez1.

The description of a structure containing information on an occurred error is below. The header file err.h contains the structure declaration.

Structure: qsmm_except_s

This structure is for passing information about an occurred error to an error handler function. The structure contains the following fields.

Field: const char * func_name

The name of a QSMM library function where the error occurred. That name might be the name of an internal library function (i.e. not an API function).

Field: int code

An error code to return by a failed QSMM API function after returning from the error handler function.

Field: union qsmm_except_u ee

Extended information about the occurred error interpreted depending on the field code of this structure. A list of error codes with extended error information always provided in this field is in the description of qsmm_except_u union.

The description of a union containing extended error information depending on an error code is below. The header file err.h contains the union declaration.

Union: qsmm_except_u

This union contains fields corresponding to error codes that can have associated extended error information.

Field: char * noic

Extended information for error code QSMM_ERR_NOIC. The error code description is “instruction class set is empty.” This field contains the name of an instruction class set without instruction classes.

Field: int callback

Extended information for error code QSMM_ERR_CALLBACK. The error code description is “callback function reported an error.” This field contains an error code returned by a callback function.

Field: qsmm_sig_t noprof

Extended information for error code QSMM_ERR_NOPROF. The error code description is “node has no probability profile specified.” This field contains the identifier of a node without a probability profile specified.

Field: qsmm_sig_t violnode

Extended information for error code QSMM_ERR_VIOLNODE. The error code description is “change violates the parameters of an already created node.” This field contains the identifier of a node that prevents making a change because it would violate node parameters.

Field: qsmm_sig_t mnode

Extended information for error code QSMM_ERR_MNODE. The error code description is “too many nodes.” This field contains the maximum allowed number of nodes.

Field: qsmm_mehcall_t stackovr

Extended information for error code QSMM_ERR_STACKOVR. The error code description is “stack overflow.” This field refers to the parameters of a model event handler call. They include stack content.

Field: qsmm_msglist_t prg

Extended information for error code QSMM_ERR_PRG. The error code description is “invalid program.” This field contains a message list that hands over information on errors in an assembler program.

Field: qsmm_storage_t storage

Extended information for error code QSMM_ERR_STORAGE. The error code description is “storage failure.” This field refers to failed storage.

Field: struct qsmm_except_notfound_s notfound

Extended information for error code QSMM_ERR_NOTFOUND. The error code description is “entity not found.”

Field: struct qsmm_except_type_s type

Extended information for error code QSMM_ERR_TYPE. The error code description is “invalid entity type.”

Field: struct qsmm_except_exist_s exist

Extended information for error code QSMM_ERR_EXIST. The error code description is “entity already exists.”

Field: struct qsmm_except_outcome_s outcome

Extended information for error code QSMM_ERR_OUTCOME. The error code description is “invalid instruction outcome.”

Field: struct qsmm_except_evthndlr_s evthndlr

Extended information for error code QSMM_ERR_EVTHNDLR. The error code description is “event handler function reported an error.”

Field: struct qsmm_except_noeqclas_s noeqclas

Extended information for error code QSMM_ERR_NOEQCLAS. The error code description is “node classes are different.”

Field: struct qsmm_except_profsrcp_s profsrcp

Extended information for error code QSMM_ERR_PROFSRCP. The error code description is “node is a probability profile source for other nodes.”

Field: struct qsmm_except_profsrcu_s profsrcu

Extended information for error code QSMM_ERR_PROFSRCU. The error code description is “node is a user of a source probability profile provided by another node.”

Field: struct qsmm_except_psumgt1_s psumgt1

Extended information for error code QSMM_ERR_PSUMGT1. The error code description is “sum of probabilities would exceed 1.”

Use the following function to dump the content of qsmm_except_s structure to a stream in JSON format.

Function: void qsmm_except_dump (void *rez1, int indent, const struct qsmm_except_s *except_p, FILE *filep)

This function dumps error information in *except_p to a stream filep in JSON format as object content. The argument indent must be non-negative. It specifies left indent—the number of spaces to print at the beginning of each line of output. You should pass 0 for the reserved argument rez1.

The rest of this section contains descriptions of structures that are the fields of qsmm_except_u union. The header file err.h contains the structure declarations. Some of them have fields of enum qsmm_lref_e, struct qsmm_gref_s, and struct qsmm_instr_class_s types. See Entity References, for descriptions of the types.

Structure: qsmm_except_notfound_s

This structure provides extended information for error code QSMM_ERR_NOTFOUND. The error code description is “entity not found.” The structure contains the following field.

Field: struct qsmm_gref_s gref

A reference to a not found entity.

Structure: qsmm_except_type_s

This structure provides extended information for error code QSMM_ERR_TYPE. The error code description is “invalid entity type.” The structure contains the following fields.

Field: enum qsmm_lref_e type_required

A required type for the entity.

Field: struct qsmm_gref_s gref

A reference to the entity that has an invalid type.

Structure: qsmm_except_exist_s

This structure provides extended information for error code QSMM_ERR_EXIST. The error code description is “entity already exists.” The structure contains the following field.

Field: struct qsmm_gref_s gref

A reference to an already existing entity.

Structure: qsmm_except_outcome_s

This structure provides extended information for error code QSMM_ERR_OUTCOME. The error code description is “invalid instruction outcome.” The structure contains the following fields.

Field: qsmm_sig_t node

The identifier of a node invoked the assembler instruction.

Field: qsmm_sig_t outcome

An invalid instruction outcome. If an event handler did not set an instruction outcome when it was necessary to do so, this field is equal to QSMM_SIG_INVALID.

Field: qsmm_sig_t noutcome

The number of outcomes of the assembler instruction.

Field: qsmm_t model

A multinode model containing a node invoked the assembler instruction.

Field: qsmm_mehcall_t mehcall

The parameters of a model event handler call that should have set a valid instruction outcome.

Field: struct qsmm_instr_class_s instr_class

The descriptor of an instruction class for the assembler instruction.

Structure: qsmm_except_evthndlr_s

This structure provides extended information for error code QSMM_ERR_EVTHNDLR. The error code description is “event handler function reported an error.” The structure contains the following fields.

Field: int rc

A negative return value of the event handler function.

Field: int evt

An event type passed to the event handler function—one of constants defined by the QSMM_EVT_* macros.

Field: qsmm_mehcall_t mehcall

The parameters of the event handler function call.

Field: struct qsmm_gref_s gref

A reference to an entity emitting events processed by the event handler function.

Structure: qsmm_except_noeqclas_s

This structure provides extended information for error code QSMM_ERR_NOEQCLAS. The error code description is “node classes are different.” The structure contains the following fields.

Field: char * node_class_name_1

The name of the first node class, that is, the first instruction class set.

Field: char * node_class_name_2

The name of the second node class, that is, the second instruction class set.

Field: qsmm_sig_t node1

The identifier of a node belonging to the first node class. If that identifier is QSMM_SIG_INVALID, this parameter is not applicable.

Field: qsmm_sig_t node2

The identifier of a node belonging to the second node class. If that identifier is QSMM_SIG_INVALID, this parameter is not applicable.

Field: qsmm_t model

A multinode model containing the node classes.

Structure: qsmm_except_profsrcp_s

This structure provides extended information for error code QSMM_ERR_PROFSRCP. The error code description is “node is a probability profile source for other nodes.” The structure contains the following fields.

Field: qsmm_sig_t node_provider

The identifier of a node acting as a probability profile source for other nodes.

Field: qsmm_sig_t nnode_user

The number of nodes acting as probability profile users.

Field: qsmm_t model

A multinode model containing the nodes.

Structure: qsmm_except_profsrcu_s

This structure provides extended information for error code QSMM_ERR_PROFSRCU. The error code description is “node is a user of a source probability profile provided by another node.” The structure contains the following fields.

Field: qsmm_sig_t node_provider

The identifier of a node acting as a probability profile source.

Field: qsmm_sig_t node_user

The identifier of a node acting as a probability profile user.

Field: qsmm_t model

A multinode model containing the nodes.

Structure: qsmm_except_psumgt1_s

This structure provides extended information for error code QSMM_ERR_PSUMGT1. The error code description is “sum of probabilities would exceed 1.” The structure contains the following fields.

Field: char * var_name

The name of a controlled probability variable with an assigned value. This assignment causes the sum of probabilities of case instructions in a choice instruction block to exceed 1.

Field: qsmm_sig_t node

The identifier of a node containing a state corresponding to a choice instruction block.

Field: qsmm_sig_t state

The index of a node state corresponding to a choice instruction block.

Field: qsmm_t model

A multinode model containing the node.


5 Assembler Programs

QSMM assembler programs are the means of:

The use of assembler programs relies heavily on instruction meta-classes, instruction classes, and instruction class sets registered for a multinode model. The name of an instruction meta-class and the text parameters of an instruction class derived from the instruction meta-class identify assembler instructions belonging to the instruction class in assembler programs. Assembler instructions defined by instruction classes can be user instructions with custom names or mixed-type instructions with fixed names. There is also a set of built-in assembler instructions with fixed names.

A handle of qsmm_prg_t type refers to a memory representation of a plain assembler program specifying a probability profile for a single node or to a memory representation of a compound assembler program consisting of multiple plain assembler programs specifying probability profiles for multiple nodes. A memory representation is convertible to an assembler program text and vice versa. Information on assembler instructions is accessible by their indices in a memory representation of a plain assembler program.

Disassembling a node is converting its state model to a plain assembler program. Assembling a node is converting a plain assembler program to a probability profile for the state model. A special mode of assembling a node is storing its assembler program as a template for subsequent disassembling. In this case, a learned disassembled program is a template assembler program with learned probabilities replacing profile probabilities specified in the template program.

A plain assembler program can declare probability variables and specify profile probabilities as their initial values. A probability variable can be a controlled probability variable or output probability variable. The instruction class set of a node specifies a set of allowed names of controlled probability variables. Changing the value of a controlled probability variable of a node results in changing one or more profile probabilities for its state model. Output probability variables are the means of fetching particular probabilities from a learned state model of a node. Output probabilities arrays hand over learned probabilities for case branches of choice instruction blocks.

Cloning a probability profile is helpful if multiple nodes have the same probability profile. It is faster to clone a probability profile from a node to other nodes than to assemble all the nodes using the same assembler program. A special cloning mode is deferred cloning a probability profile. This mode can decrease memory consumption by a multinode model.

Unloading the probability profile of a node additionally clears learned state model of the node and breaks its correspondence with a node providing a source probability profile cloned in deferred mode.

The assembler preprocessor can preprocess an assembler program text before parsing it. The preprocessor provides capabilities for including other assembler source files in a preprocessed source file, defining and expanding basic macros, and generating unique location labels to produce a correct assembler program when expanding the same macro multiple times.


5.1 Syntax and Semantics

An assembler program must be syntactically correct and contain valid assembler instructions. They should carry the meaning of the assembler program.

For easier interpretation of a plain assembler program and its more straightforward conversion to a probability profile held in the state transition matrix and action emission matrix of a node, the structure of the plain assembler program should adhere to certain rules.


5.1.1 Assembler Program Syntax

An assembler program can be plain or compound one. A plain assembler program is the content of a single assembler procedure. A compound assembler program consists of multiple procedures possibly intended for loading into distinct model nodes.

By default, the assembler program parser reads comments contained in an assembler program and saves them in its memory representation. For the identification of comments to be correct, their arrangement must adhere to certain rules.

When expanding macros or including other files in an assembler source file, the assembler preprocessor inserts line directives in preprocessed output for handing over source file, macro, and line number information to the assembler program parser for inclusion in its error, warning, and note messages and for inclusion in error, warning, and note messages of node assembler.


5.1.1.1 Plain Program

A plain assembler program can consist of:

  • assembler instructions (see Assembler Instructions);
  • location labels;
  • data labels for prob, jprob, case, choice, and end choice instructions;
  • comments (see Comments);
  • line directives (see line Directive);
  • empty lines; you can use them to decorate an assembler program.

Example:

L1:     stt
pa1     jprob   0.5, L2         ; jump with probability 0.5
        foo     4               ; user instruction
        jmp     L1

L2:     bar     r3, 5           ; user instruction
        jmp     L1

Splitting Assembler Instructions into Multiple Lines

An assembler instruction can occupy multiple lines if split just after ‘,’ in its text outside of comments and string literals.

Example:

        point   1000, 2000, 3000,
                0.5, black, "star",
                path "a, b, c"

Location Labels

A location label always ends with ‘:’. The first character of a location label must be an English letter or the character ‘_’; every subsequent character except for the last character ‘:’ must be an English letter, digit, or ‘_’.

A location label can be on the same line as an assembler instruction.

Example:

finish: ret

A location label can precede a line with an assembler instruction.

Example:

error_exit:
        ret

An assembler instruction can have multiple location labels.

Examples:

skip_current_item:
move_to_next_item:
        skip

error_exit:

finish: ret

Data Labels

A data label always starts at column 1 and does not end with ‘:’. The first character of a data label must be an English letter or the character ‘_’; every subsequent character must be an English letter, digit, or ‘_’. An assembler instruction always follows a data label on the same line.

Example:

p_a1    jprob   0.5, L1

5.1.1.2 Compound Program

A compound assembler program consists of procedures. Every procedure has a unique name. A line starting with a procedure name followed by ‘proc’ marks the beginning of a procedure. A line optionally starting with a procedure name followed by ‘end proc’ marks the end of a procedure.

Example:

proc1   proc
        content of procedure 1
proc1   end     proc

proc2   proc
        content of procedure 2
        end     proc

The content of every procedure is a plain assembler program. Location labels, data labels, and state names defined in every procedure are local to it.


5.1.1.3 Comments

Comments begin with the character ‘;’ and continue until the end of line. Comments must adhere to certain rules for their correct identification and assignment to commented entities. If a comment occupies multiple lines, the character ‘;’ starting each comment line should be (approximately) at the same column. A commented entity can be:

  • an assembler instruction;
  • the beginning of a procedure;
  • the end of a program.

An assembler instruction can have a comment above the instruction and a comment to the right of the instruction.

A comment above an assembler instruction should start at a column where an instruction name starts.

Example:

        ; Beginning of a PCFG production.
        ;
        ; The first argument is a nonterminal symbol at the
        ; left-hand side. The second argument is the index
        ; of a production right-hand side for the nonterminal
        ; symbol at the left-hand side.

        prod    "S", 1

A comment to the right of an assembler instruction begins to the right of a line of instruction parameters or a line just beneath them and can continue on the next lines and beyond the last instruction line.

Examples:

        rd      "E", 1,  ; spur update
                0, 3     ; [ "a" "b" ]
                         ; [^ "c" ]
                         ; [ "b" "c" "d" ]

        rd      "Long_nonterminal_symbol_name",
                1, 0, 3  ; spur update
                         ; [ "a" "b" ]
                         ; [^ "c" ]
                         ; [ "b" "c" "d" ]

        call    long_procedure_name
                         ; call another node to process
                         ; a symbol subsequence

A comment at the beginning of a procedure should precede a line with the proc keyword and start at a column where the proc keyword starts.

Example:

        ; Consume a terminal symbol sequence for the nonterminal
        ; symbol `S' representing the entire parse unit

S       proc
        procedure content
S       end     proc

A comment at the end of a program begins after the last instruction of a plain assembler program or after the last procedure of a compound assembler program.

Examples:

        ret

        ; Control returns to a calling node or application if there
        ; was no calling node.

S       end     proc

        ; The end of a program
        ;
        ; Seeing this comment means that the program is complete.

5.1.1.4 line Directive

The assembler program parser supports the ‘line’ directive and uses information changed by it when printing error, warning, and note messages. You can put that directive in an assembler program explicitly, or the assembler preprocessor (see Using the Assembler Preprocessor) may generate it. The ‘line’ directive can change the current line number in the source file, the name of that source file, the stack of include locations, and the stack of macro expansion locations tracked by the assembler program parser.

The directive must be on a single line after at least one whitespace character at the beginning of the line and should have one of the following formats:

        line    line_number
        line    line_number, file_name
        line    line_number, file_name, push_file
        line    line_number, file_name, pop_file
        line    line_number, file_name, push_macro, macro_name
        line    line_number, file_name, pop_macro, macro_name

Below there are descriptions of the formats.

line line_number

This directive changes tracked number of the next line in the current source file to line_number.

Example:

        line    10

This example sets the number of the next line in the current source file to 10. By default, subsequent lines will have numbers 11, 12, and so on.

line line_number, file_name

This directive changes tracked number of the next line to line_number and changes tracked name of the current source file to file_name. The argument file_name must be a (quoted) string literal. If file_name is an empty string (""), the current source file is the outermost source file processed by the assembler program parser.

Example:

        line    10, "grammar.rg"

This example sets the number of the next line in the current source file to 10 and the name of the current source file to ‘grammar.rg’.

line line_number, file_name, push_file

This directive changes tracked number of the next line to line_number, changes tracked name of the current source file to file_name, and notifies about the beginning of processing that file as an include file. The argument file_name must be a (quoted) string literal.

Example:

        line    1, "incl.asm", push_file

This example notifies about the beginning of processing the include file ‘incl.asm’. The next line after this directive will be line 1 of that include file.

line line_number, file_name, pop_file

This directive changes tracked number of the next line to line_number, changes tracked name of the current source file to file_name, and notifies about the end of processing an include file. The argument file_name must be a (quoted) string literal and must be equal to the name of a file containing the include file. If file_name is an empty string (""), the containing file is the outermost source file processed by the assembler program parser.

Example:

        line    3, "", pop_file

This example notifies about the end of processing an include file and continuing processing the outermost source file at line 3.

line line_number, file_name, push_macro, macro_name

This directive changes tracked number of the next line to line_number, changes tracked name of the current source file to file_name, and notifies about the beginning of processing an expansion of a macro macro_name. The arguments file_name and macro_name must be quoted string literals. If file_name is an empty string (""), the current source file is the outermost source file processed by the assembler program parser.

Example:

       line    15, "", push_macro, "m1"

This example notifies about the beginning of processing an expansion of ‘m1’ macro defined in the outermost source file. The first line of the expansion is file line 15 located in the macro definition.

line line_number, file_name, pop_macro, macro_name

This directive changes tracked number of the next line to line_number, changes tracked name of the current source file to file_name, and notifies about the end of expanding a macro called from a macro macro_name. The arguments file_name and macro_name must be quoted string literals. The argument file_name must be equal to the name of a source file containing the definition of a macro macro_name. If file_name is an empty string (""), the current source file is the outermost source file processed by the assembler program parser. If macro_name is an empty string (""), the containing macro is the outermost assembler program.

Example:

        line   25, "", pop_macro, "m0"

This example notifies about the end of expanding a macro from the macro ‘m0’ defined in the outermost source file. The next line after the macro expansion in ‘m0’ is line 25.


5.1.2 Assembler Instructions

In QSMM, there are three categories of assembler instructions: built-in instructions, user instructions, and mixed-type instructions.

The built-in instructions are case, choice, end, jmp, joe, jprob, prob, and stt. The assembler understands the built-in instructions without a prior definition of instruction classes and meta-classes. The built-in instructions do not necessarily induce code for execution by some kind of a machine; they can be the control words affecting the structure of a machine.

User instructions are assembler instructions with application-specific behavior. You declare a custom set of user instructions in an application program by registering instruction classes and meta-classes. You implement the execution of actions associated with the user instructions in the event handlers of instruction meta-classes.

The mixed-type instructions are abort, lookup, and nop1. The disassembler can generate them, but their assembling requires defining the corresponding instruction classes and meta-classes. Their implementation can be specific to an application program.


5.1.2.1 jmp Instruction

The instruction has the syntax

        jmp     loc_label

and specifies transferring control to a location label loc_label. The location label should have the following definition elsewhere in the assembler program:

loc_label:

5.1.2.2 prob Instruction

The instruction has the syntax

var_def prob    number

and defines a probability variable var_def with initial value number. Here var_def is a data label. The parameter number must be in the range 0 to 1 inclusive.


5.1.2.3 jprob Instruction

This instruction has the following forms:

        jprob   number, loc_label
var_def jprob   number, loc_label
        jprob   var_use, loc_label

The instruction specifies control transfer to a location label loc_label with probability number or with profile probability stored in a previously defined variable var_use. A data label var_def defines a probability variable var_def with initial value number. The parameter number must be in the range 0 to 1 inclusive. The assembler supports fixed-point and exponential notation for number.

The jprob instruction effectively sets a profile probability in the action emission matrix or at least one profile probability in the state transition matrix:

  • if an stt instruction precedes a contiguous block of jprob instructions, they set profile probabilities in the action emission matrix;
  • if an stt instruction does not precede a contiguous block of jprob instructions, and the state transition matrix has the restriction to define only deterministic state transitions, the jprob instructions set profile probabilities in the action emission matrix;
  • if an stt instruction does not precede a contiguous block of jprob instructions, and the state transition matrix does not have the restriction to define only deterministic state transitions, the jprob instructions set profile probabilities in the state transition matrix.

Let us consider a block of jprob instructions like this:

        jprob   prob1, L1
        jprob   prob2, L2
        jprob   prob3, L3

The probabilities of jumps to various destinations are the following:

Jump DestinationProbability Value
The location label L1prob1
The second jprob instruction1−prob1
The location label L2(1−prob1)*prob2
The third jprob instruction(1−prob1)*(1−prob2)
The location label L3(1−prob1)*(1−prob2)*prob3
An instruction following the third jprob instruction(1−prob1)*(1−prob2)*(1−prob3)

5.1.2.4 choice Instruction Block

This instruction block has the format

        choice
        case    ...
        case    ...
        ...
        end     choice

or

arr_def choice
        case    ...
        case    ...
        ...
        end     choice

or

arr_def choice
        case    ...
        case    ...
        ...
arr_def end     choice

It consists of a choice instruction, at least one case instruction, and an end choice instruction. The instruction block can declare a probabilities array arr_def, where arr_def is a data label. The instructions case and end choice must not have location labels assigned.

Each case instruction must have one of the following forms:

        case    number, loc_label
var_def case    number, loc_label
        case    var_use, loc_label

The case instructions specify control transfer to a location label loc_label with probability number or with profile probability stored in a previously defined variable var_use. A data label var_def defines a probability variable var_def with initial value number. The parameter number must be in the range 0 to 1 inclusive. The assembler supports fixed-point and exponential notation for number. If a choice instruction has a location label assigned, you must not use the location label as the second argument of case instructions in the choice instruction block.

The choice instruction block effectively sets profile probabilities in the action emission matrix or state transition matrix:

  • if an stt instruction precedes a particular choice instruction block, it sets profile probabilities in the action emission matrix;
  • if an stt instruction does not precede a particular choice instruction block, and the state transition matrix has the restriction to define only deterministic state transitions, the instruction block sets profile probabilities in the action emission matrix;
  • if an stt instruction does not precede a particular choice instruction block, and the state transition matrix does not have the restriction to define only deterministic state transitions, the instruction block sets profile probabilities in the state transition matrix.

In contrast to a contiguous block of jprob instructions, a choice instruction block allows you to specify jump probabilities in a direct way. Let us consider a choice instruction block like this:

        choice
        case    prob1, L1
        case    prob2, L2
        case    prob3, L3
        end     choice

The probabilities of jumps to various destinations are the following:

Jump DestinationProbability Value
The location label L1prob1
The location label L2prob2
The location label L3prob3
An instruction following the choice instruction block1−prob1prob2prob3

Compare this example to the example with a block of jprob instructions in jprob Instruction.


5.1.2.5 joe Instruction

This instruction has the syntax

        joe     outcome, loc_label

and specifies control transfer to a location label loc_label if the outcome of the last invoked user or mixed-type instruction is equal to outcome. The event handler of an instruction meta-class sets the number of outcomes of instructions belonging to an instruction class derived from the instruction meta-class on initialization of the instruction class.


5.1.2.6 stt Instruction

This instruction has the forms

        stt
        stt     state_name

equivalent to the notation

        stt     [state_name]

The instruction marks the beginning of a state of a plain assembler program. The state biuniquely corresponds to a state of a node with the assembler program loaded. The former state and the latter state can have a name specified by a (quoted) string literal state_name. A plain assembler program must not contain states with duplicate names. See Loading a Parsed Program into a Node, for the description of qsmm_get_node_state_name and qsmm_get_node_state_by_name functions retrieving the name of a node state by its index and retrieving the index of a node state by its name.

The stt instruction selects the action emission matrix to hold profile probabilities specified by subsequent jprob or case instructions in a plain assembler program. Without the stt instruction, the subsequent jprob or case instructions would specify profile probabilities held in the state transition matrix on condition that it did not have the restriction to define only deterministic state transitions.

If the state transition matrix has the restriction to define only deterministic state transitions, or the action emission matrix has the restriction to define only deterministic action emissions, specifying stt instructions to mark beginnings of states is not necessary unless stt instructions assign names to states. If the state transition matrix has the restriction to define only deterministic state transitions, all jprob and case instructions in a plain assembler program specify profile probabilities held in the action emission matrix. If the action emission matrix has the restriction to define only deterministic action emissions, all jprob and case instructions in a plain assembler program specify profile probabilities held in the state transition matrix. If both matrices have the mentioned restrictions, a plain assembler program must not contain jprob and case instructions at all.

If both matrices do not have the mentioned restrictions, the best practice is to specify stt instructions for all states in a plain assembler program to know exactly where each state begins. To support this approach, the assembler generates a warning for every location where a state begins, but an stt instruction is missing there. Note that inserting stt instructions into a plain assembler program may require rearranging it.

There are three types of places where you can insert an stt instruction.

  1. Before a user or mixed-type instruction or a sequence of such instructions:
            stt     [state_name]
            user or mixed-type instruction 1
            user or mixed-type instruction 2
            ...
            user or mixed-type instruction N
    

    This instruction arrangement means that in a state marked by the stt instruction the instruction emitting engine emits a specified individual user or mixed-type instruction or a specified sequence of user or mixed-type instructions.

    As a result of assembling the instruction arrangement, the action emission matrix defines deterministic choice of the individual user or mixed-type instruction or the sequence of user or mixed-type instructions in the state. The action emission matrix contains profile probability 1 for the state and the individual instruction or instruction sequence and profile probability 0 for the state and all other individual instructions and instruction sequences.

    If you need to mark the beginning of a state, but there is no effective user or mixed-type instruction to insert beneath the stt instruction, you can insert the nop1 instruction there (see nop1 Instruction).

  2. Before a block of jprob instructions:
            stt     [state_name]
            jprob   prob1, L1
            jprob   prob2, L2
            ...
            jprob   probN, LN
            user or mixed-type instruction 0/1
            user or mixed-type instruction 0/2
            ...
            user or mixed-type instruction 0/M0
            ...
    
    L1:     user or mixed-type instruction 1/1
            user or mixed-type instruction 1/2
            ...
            user or mixed-type instruction 1/M1
            ...
    L2:     user or mixed-type instruction 2/1
            user or mixed-type instruction 2/2
            ...
            user or mixed-type instruction 2/M2
            ...
    LN:     user or mixed-type instruction N/1
            user or mixed-type instruction N/2
            ...
            user or mixed-type instruction N/MN
            ...
    

    This instruction arrangement means that in a state marked by the stt instruction the instruction emitting engine emits one of specified individual instructions or instruction sequences. The individual instructions must belong to different instruction classes, that is, have different combinations of an instruction name and instruction parameters. The instruction sequences must be different too.

    As a result of assembling the instruction arrangement, the action emission matrix contains profile probabilities of emitting all specified individual instructions and instruction sequences in the state and contains profile probability 0 for emitting all other individual instructions and instruction sequences in the state. However, in the general case, the profile probabilities of emitting specified individual instructions and instruction sequences will be different from profile probabilities indicated in the corresponding jprob instructions. For more information, see an example block of jprob instructions in jprob Instruction.

  3. Before a choice instruction block:
            stt     [state_name]
    
            choice
            case    prob1, L1
            case    prob2, L2
            ...
            case    probN, LN
            end     choice
    
            user or mixed-type instruction 0/1
            user or mixed-type instruction 0/2
            ...
            user or mixed-type instruction 0/M0
            ...
    
    L1:     user or mixed-type instruction 1/1
            user or mixed-type instruction 1/2
            ...
            user or mixed-type instruction 1/M1
            ...
    L2:     user or mixed-type instruction 2/1
            user or mixed-type instruction 2/2
            ...
            user or mixed-type instruction 2/M2
            ...
    LN:     user or mixed-type instruction N/1
            user or mixed-type instruction N/2
            ...
            user or mixed-type instruction N/MN
            ...
    

    This instruction arrangement means that in a state marked by the stt instruction the instruction emitting engine emits one of specified individual instructions or instruction sequences. The individual instructions must belong to different instruction classes, that is, have different combinations of an instruction name and instruction parameters. The instruction sequences must be different too.

    As a result of assembling the instruction arrangement, the action emission matrix contains profile probabilities of emitting all specified individual instructions and instruction sequences in the state and contains profile probability 0 for emitting all other individual instructions and instruction sequences in the state. The profile probabilities of emitting specified individual instructions and instruction sequences excluding the profile probability of emitting an individual instruction or instruction sequence beneath the choice instruction block are equal to profile probabilities indicated in the corresponding case instructions.

See Recommended Assembler Program Structure, for recommended program structure after individual user or mixed-type instructions and sequences of user or mixed-type instructions in the stt instruction arrangements listed above.


5.1.2.7 nop1 Instruction

The mixed-type instruction nop1 should have the corresponding instruction meta-class registered for a multinode model. The instruction should have single outcome 0 it always returns. The instruction should not have any side effect. You can define the instruction meta-class by the following code block:

static QSMM_INSTR_META_CLASS(nop1) {
    return 0;
}

The disassembler can generate the nop1 instruction at the beginning of a plain assembler program.

You can define the user instruction nop that preserves the outcome of the previous instruction invoked by a node, as opposed to the nop1 instruction always returning outcome 0. You can define the instruction meta-class for the nop instruction by the following code block:

static QSMM_INSTR_META_CLASS(nop) {
    switch (mehcall->evt) {
        case QSMM_EVT_INSTR_CLASS_INIT:
            qsmm_set_mehcall_noutcome(mehcall,0);
            break;
    }
    return 0;
}

If possible, use the nop1 instruction instead of nop instruction—reduce the number of profile probabilities written to the state transition matrix to make it simpler and decrease the amount of memory needed to store the matrix.


5.1.2.8 lookup Instruction

This instruction is a mixed-type instruction. The disassembler can generate lookup instructions when disassembling a node of a multinode model with positive length of look-ahead signal segment. The field ngram_env_la_sz of qsmm_desc_s structure passed to the function qsmm_create specifies the length when creating a multinode model. The function qsmm_get_ngram_env_la_sz returns the length for an existing multinode model.

The instruction has the syntax

        lookup  position

and sets the outcome equal to a look-ahead signal at zero-based position in the look-ahead signal segment.

The assembler does not support loading assembler programs into the nodes of a multinode model with positive length of look-ahead signal segment. Therefore, if you need to assemble a program (e.g. generated by the disassembler) containing lookup instructions, you can do the following:

  1. Create a multinode model with zero-length look-ahead signal segment.
  2. Register the instruction meta-class ‘lookup’.
  3. Register instruction classes derived from the instruction meta-class ‘lookup’ for possible values of position. Every instruction class has the number of outcomes equal to maximum look-ahead signal identifier plus one at position. Instructions belonging to the instruction classes fetch signals at specified positions from an array used as a substitute for the look-ahead signal segment.
  4. Modify the elements of the array where you would modify the elements of look-ahead signal segment.

5.1.2.9 abort Instruction

This instruction is a mixed-type instruction. The disassembler can generate it after a user instruction or another mixed-type instruction when there is no information about instructions following the user or mixed-type instruction. This is the case when the instruction emitting engine emitted the user or mixed-type instruction once and that instruction has not returned control, or when the disassembler discarded subsequent instructions according to disassembling parameters.

You can use the following approach to assemble programs generated by the disassembler containing abort instructions. First, make the disassembler generate a single abort instruction at the end of an assembler program by setting the field use_abort_1 of qsmm_disasm_desc_s structure to a non-zero value. In this case, an assembler program contains jumps to this abort instruction from other locations where the disassembler would insert abort instructions in default mode. The disassembler additionally generates a jump to the beginning of the assembler program beneath the abort instruction. Second, implement the abort instruction as the nop1 instruction (without any side effect). After you have done these two things, the environment state identification engine transfers control to the beginning of the assembler program when the next instruction to execute is unknown. This looping may be appropriate in your situation.


5.1.2.10 User Instructions

User instructions are application-specific and can perform operations listed in Handling Instruction Invocation. The instruction class set of a node contains instruction classes for user and mixed-type instructions an assembler program loaded into the node can contain. To find an instruction class for a user instruction, the assembler converts its parameters to canonical form according to the rules described in Setting Text Instruction Parameters.

You can split the parameters of a user instruction into multiple lines at positions of commas located outside of string literals. To indicate a continuation of instruction parameters on the next line, finish the previous line just after a comma following an instruction parameter.


5.2 Basic Datatypes

A program handle refers to a memory representation of a plain or compound assembler program.

Data type: qsmm_prg_t

This is a type for a program handle. It is a pointer, so variables of this type can be NULL. The functions qsmm_prg_create, qsmm_node_disasm, qsmm_parse_asm_source_buf, qsmm_parse_asm_source_stream, and qsmm_parse_asm_source_file allocate a new program handle. The function qsmm_prg_destroy frees an existing program handle. You can pass a program handle to API functions taking an argument of qsmm_prg_t type until freeing the handle.

Use the following function if you need to create a memory representation of a compound assembler program for subsequent adding memory representations of plain assembler programs to it.

Function: int qsmm_prg_create (qsmm_prg_t *prg_p)

This function creates an empty memory representation of an assembler program and stores its allocated program handle to *prg_p. If prg_p is NULL, the function has no effect.

The function returns a non-negative value on success or negative error code QSMM_ERR_NOMEM on out of memory error.

Use the following function to destroy a memory representation of a plain or compound assembler program.

Function: void qsmm_prg_destroy (qsmm_prg_t prg)

This function destroys a memory representation of an assembler program specified by a handle prg. You must not use the handle after destroying the memory representation. If prg is NULL, the function has no effect.

Use the function described below to add a memory representation of a plain assembler program to a memory representation of a compound assembler program, for example, created by qsmm_prg_create.

Function: int qsmm_prg_add_nested (qsmm_prg_t prg_compound, const char *nested_name, qsmm_prg_t prg_nested)

This function adds a memory representation of a plain assembler program prg_nested to a memory representation of a compound assembler program prg_compound as an assembler procedure named nested_name. The compound assembler program becomes the owner of the plain assembler program, so destroying prg_nested happens on destroying prg_compound, and you must not destroy prg_nested by passing it to qsmm_prg_destroy.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The handle prg_compound refers to a memory representation of a plain assembler program, or the handle prg_nested refers to a memory representation of a compound assembler program.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

QSMM provides limited capabilities for working with assembler instructions contained in a memory representation of a plain assembler program. An instruction handle refers to an assembler instruction.

Data type: qsmm_instr_t

This is a type for an instruction handle. It is a pointer, so variables of this type can be NULL. The functions qsmm_get_prg_instr and qsmm_get_instr_nested (see Inspecting an Assembler Program) return the handle of an existing instruction.


5.3 Disassembling a Node

You can convert the state transition matrix and action emission matrix of a node to an assembler program—disassemble the node. You typically disassemble a node after executing or training it.

Before executing a node, you can load into it an assembler program specifying a probability profile for the state transition matrix and action emission matrix. To simplify the analysis of results of training a node by disassembling the node, it might be desirable to obtain a disassembled program as an assembler program previously loaded into the node, but with profile probabilities in jprob and case instructions changed to probabilities learned while training the node. To turn on this mode—disassembling using an assembler program template,—pass the QSMM_ASM_TEMPLATE flag to the function qsmm_node_asm when loading an assembler program into a node you are going to disassemble later (see Loading a Parsed Program into a Node). If a node does not have an assembler program loaded, or the node has an assembler program loaded without specifying the QSMM_ASM_TEMPLATE flag, you disassemble the node without using an assembler program template.

Use the following function to disassemble a node.

Function: int qsmm_node_disasm (qsmm_t model, qsmm_sig_t node, struct qsmm_disasm_desc_s *desc_p, qsmm_prg_t *prg_p)

This function disassembles a node of a multinode model and stores the allocated handle of a disassembled program in *prg_p if prg_p is not NULL. The argument node specifies the identifier of the node. If desc_p is not NULL, *desc_p specifies disassembling parameters. If desc_p is NULL, the function uses default disassembling parameters.

If the function qsmm_node_asm previously assembled the node with the QSMM_ASM_TEMPLATE flag, or the node uses a source probability profile provided by another node assembled with the QSMM_ASM_TEMPLATE flag, the disassembled program is a template assembler program with replaced probabilities in jprob and case instructions. If desc_p is not NULL, probabilities of desc_p->prob_type type replace profile probabilities in the jprob and case instructions. If desc_p is NULL, probabilities of QSMM_PROB_AGGR type replace the profile probabilities.

In the current implementation the function does not modify *desc_p if desc_p is not NULL. However, in a future implementation the function may modify *desc_p, for example, to store there statistics on the disassembling process.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_INVAL

The argument desc_p is not NULL, and parameters in *desc_p are invalid.

QSMM_ERR_UNTIMELY

The model instance does not exist.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_CALLBACK, QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the model instance in inconsistent state. If after removing a reason of an error a repeated call to this function succeeds, the instance’s state becomes consistent.

The description of a structure passed to the function qsmm_node_disasm is below.

Structure: qsmm_disasm_desc_s

This structure specifies the parameters of disassembling. The structure contains the following fields.

Field: char use_stt_start

If not 0, generate an stt instruction at the beginning of an assembler program if it started with a lookup instruction, and generate stt and nop1 instructions at the beginning of an assembler program if it started with a jprob instruction or choice instruction block. The default is not to generate. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char use_stt_state

If not 0, generate an stt instruction at the beginning of each state. The default is not to generate. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char use_stt_lookup

If not 0, generate stt instructions before lookup instructions. The default is not to generate. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char use_stt_abort

If not 0, generate stt instructions before abort instructions. This is not very useful unless there is not more than one abort instruction in an assembler program (the field use_abort_1 sets this mode). The default is not to generate. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char use_choice

If not 0, generate choice instruction blocks instead of contiguous blocks of jprob instructions when the number of jprob instructions in a block is greater than one. The default is to generate. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char use_abort_1

If is 0, and there is no information what to execute after an individual user or mixed-type instruction or a sequence of user or mixed-type instructions, generate an abort instruction at this location. If not 0, generate a jump at this location to a single abort instruction at the end of an assembler program and generate a jump to its start after the abort instruction. If not 0, and there are no jumps to the abort instruction at program end, skip generating that abort instruction followed by a jump to program start. The default is to generate an abort instruction after an individual user or mixed-type instruction or a sequence of user or mixed-type instructions. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char comment_state_idx

[New in QSMM 1.19] If not 0, add a comment containing a state index above the beginning of each state. If is 0, do not add the comments. The default is to add the comments. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char comment_fq

[New in QSMM 1.19] If not 0, add (where possible) comments containing numbers of state activations, instruction invocations, and jumps performed. If is 0, do not add the comments. The default is to add the comments. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: char do_calc_prob[QSMM_PROB_COUNT]

An array specifying additional types of probabilities to calculate for jprob and case instructions optionally printed in comments to the right of them. Array indices are the elements of qsmm_prob_e enumeration (except for its last element) described in Emitting an Output Signal. If an array element is non-zero, the disassembler calculates probabilities of a corresponding type and stores them in the instructions. The disassembler calculates probabilities of a type specified in the field prob_type regardless of do_calc_prob field. The default is not to calculate probabilities of additional types.

Field: long fq_goto_min

The minimum number of nondeterministic transitions to a target state for a quadruple consisting of a source state, an individual user or mixed-type instruction or a sequence of user or mixed-type instructions emitted in the source state, an instruction outcome, and the content of look-ahead signal segment. The disassembler discards nondeterministic transitions performed lesser numbers of times. The default minimum number of nondeterministic transitions is 0. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: long fq_action_min

The minimum number of nondeterministic invocations of an individual user or mixed-type instruction or a sequence of user or mixed-type instructions in a state. The disassembler discards individual user or mixed-type instructions or sequences of user or mixed-type instructions nondeterministically invoked lesser numbers of times. The default minimum number of nondeterministic invocations is 0. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: double prob_goto_min

A minimum probability for jprob and case instructions corresponding to the state transition matrix. The disassembler removes instructions containing lesser probabilities from a disassembled program. The field prob_type specifies the type of analyzed probabilities. The default minimum probability is 0.

When disassembling a node without using an assembler program template, the disassembler removes the instructions after discarding nondeterministic state transitions with lesser frequencies according to the field fq_goto_min and renormalizing state transition probabilities.

Field: double prob_action_min

A minimum probability for jprob and case instructions corresponding to the action emission matrix. The disassembler removes instructions containing lesser probabilities from a disassembled program. The field prob_type specifies the type of analyzed probabilities. The default minimum probability is 0.

When disassembling a node without using an assembler program template, the disassembler removes the instructions after discarding nondeterministic instruction invocations with lesser frequencies according to the field fq_action_min and renormalizing instruction invocation probabilities.

Field: qsmm_sig_t n_retain_goto_max

[New in QSMM 1.19] The retained number of most probable transitions to target states for a quadruple consisting of a source state, an individual user or mixed-type instruction or a sequence of user or mixed-type instructions emitted in the source state, an instruction outcome, and the content of look-ahead signal segment. The disassembler discards less probable state transitions after discarding nondeterministic state transitions with lesser frequencies according to the field fq_goto_min and renormalizing state transition probabilities. The field prob_type specifies the type of analyzed probabilities. If n_retain_goto_max is equal to 0, the disassembler retains all state transitions. The default is to retain all state transitions. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: qsmm_sig_t n_retain_action_max

[New in QSMM 1.19] The retained number of most probable invocations of individual user or mixed-type instructions or sequences of user or mixed-type instructions in a state. The disassembler discards less probable instruction invocations after discarding nondeterministic instruction invocations with lesser frequencies according to the field fq_action_min and renormalizing instruction invocation probabilities. The field prob_type specifies the type of analyzed probabilities. If n_retain_action_max is equal to 0, the disassembler retains all instruction invocations. The default is to retain all instruction invocations. The disassembler ignores this field when disassembling a node using an assembler program template.

Field: enum qsmm_prob_e prob_type

The type of state transition and instruction invocation probabilities for discarding less probable state transitions and instruction invocations according to the fields n_retain_goto_max and n_retain_action_max. The type of probabilities to calculate for jprob and case instructions.

The disassembler compares the probabilities in jprob and case instructions with probabilities in the fields prob_goto_min and prob_action_min to determine whether to discard specific jprob and case instructions. When disassembling a node without using an assembler program template, this field specifies the type of probabilities for sorting jprob and case instructions in descending order within corresponding instruction blocks.

See Emitting an Output Signal, for the description of elements of qsmm_prob_e enumeration. The default type of probabilities is QSMM_PROB_AGGR.

Zero by the function memset an instance of qsmm_disasm_desc_s structure before setting its fields.

See below for a list of types of comments generated when disassembling a node without using an assembler program template. Note that the disassembler cannot obtain numbers of deterministic instruction invocations and deterministic state transitions for putting in comments because the function qsmm_node_call_default does not increment the numbers on deterministic selection of instructions and target states.

State index

The disassembler generates this comment if the field comment_state_idx of qsmm_disasm_desc_s structure is non-zero.

The number of state activations

If all invocations of individual user or mixed-type instructions or sequences of user or mixed-type instructions in a state are nondeterministic, the number of state activations is equal to the sum of numbers of all invocations. If there is a deterministic invocation, and all transitions from the state are nondeterministic, the number of state activations is equal to the sum of numbers of all transitions from the state. If there is a deterministic invocation, and there is at least one deterministic transition from the state, the disassembler does not add this comment.

The disassembler generates the comment only if the field comment_fq of qsmm_disasm_desc_s structure is non-zero.

The number of invocations (calls) of an individual user or mixed-type instruction or a sequence of individual or mixed-type instructions

If the invocation is nondeterministic, the disassembler uses available number of invocations. If the invocation is deterministic, and all transitions from the state after the invocation are nondeterministic, the number of invocations is equal to the sum of numbers of transitions from the state. If the invocation is deterministic, and there is at least one deterministic state transition, the disassembler does not add this comment.

The disassembler generates the comment only if the field comment_fq of qsmm_disasm_desc_s structure is non-zero.

The number of jumps performed by a joe instruction or a jmp instruction after analyzing an instruction outcome

The disassembler generates this comment if the field comment_fq of qsmm_disasm_desc_s structure is non-zero, and the joe or jmp instruction transfers control to a block of jprob instructions or a choice instruction block performing nondeterministic transitions to target states.

The number of jumps performed by a jprob or case instruction

The disassembler generates this comment if the field comment_fq of qsmm_disasm_desc_s structure is non-zero.

The number of jumps performed by a jmp instruction at the end of a block of jprob instructions or a choice instruction block transferring control to target states

The disassembler generates this comment if the field comment_fq of qsmm_disasm_desc_s structure is non-zero.

Note: numbers of state activations, instruction invocations, and jumps performed may be inconsistent among themselves if the disassembler discarded some instructions according to disassembling parameters.

To generate the most probable completely deterministic program when disassembling a node without using an assembler program template, set to 1 the fields n_retain_goto_max and n_retain_action_max of qsmm_disasm_desc_s structure.

Below there is an example of calling the function qsmm_node_disasm to generate a program for subsequent assembling. A disassembled node does not have an assembler program loaded.

qsmm_prg_t prg=0;
struct qsmm_disasm_desc_s disasm_desc;
memset(&disasm_desc,0,sizeof(disasm_desc));
// Insert `stt' instructions in appropriate places.
disasm_desc.use_stt_start=1;
disasm_desc.use_stt_state=1;
disasm_desc.use_stt_lookup=1;
disasm_desc.use_stt_abort=1;
// Improve the readability of probabilistic jumps.
disasm_desc.use_choice=1;
// Simplify handling unexplored control paths.
disasm_desc.use_abort_1=1;
// Do not generate never executed code.
disasm_desc.fq_goto_min=1;
disasm_desc.fq_action_min=1;
// Remove `jprob' and `case' instructions with
// rounded probabilities less than 1%.
disasm_desc.prob_goto_min=0.005;
disasm_desc.prob_action_min=0.005;
qsmm_node_disasm(qsmm,node,&disasm_desc,&prg);

An example of calling the function qsmm_node_disasm for a node assembled with the QSMM_ASM_TEMPLATE flag occupies a lesser number of lines because the disassembler uses a small subset of fields of qsmm_disasm_desc_s structure in this mode.

qsmm_prg_t prg=0;
struct qsmm_disasm_desc_s disasm_desc;
memset(&disasm_desc,0,sizeof(disasm_desc));
// Remove `jprob' and `case' instructions with
// rounded probabilities less than 1%.
disasm_desc.prob_goto_min=0.005;
disasm_desc.prob_action_min=0.005;
qsmm_node_disasm(qsmm,node,&disasm_desc,&prg);

Refer to the files tests/disasm2.c and tests/lookup2.c for the methods of assembling a previously disassembled program.


5.4 Inspecting an Assembler Program

An assembler program can have a name. If an assembler program is a procedure in a compound assembler program, the assembler program and the procedure have the same name.

Use the following function to get the name of an assembler program.

Function: const char * qsmm_get_prg_name (qsmm_prg_t prg)

This function returns the name of a program prg. That name is the name of an assembler procedure contained in a compound assembler program. If prg does not represent a plain assembler program contained in a compound assembler program, the function returns NULL.

The function qsmm_prg_add_nested adds a plain assembler program to a compound assembler program as an assembler procedure. Use the following function to get the number of procedures contained in a compound assembler program.

Function: size_t qsmm_get_prg_nnested (qsmm_prg_t prg)

This function returns the number of plain assembler programs contained in a program prg (as procedures). If prg is not a compound assembler program, the function returns 0.

Use the following function to fetch a plain assembler program from a compound assembler program. The function qsmm_get_prg_name described earlier in this section returns the name of a procedure for the plain assembler program.

Function: qsmm_prg_t qsmm_get_prg_nested (qsmm_prg_t prg, size_t nested_idx)

This function returns a procedure contained in a program prg at zero-based index nested_idx. If prg is not a compound assembler program, or nested_idx is greater than or equal to the number of procedures in prg, the function returns NULL.

Use the following function to get the number of instructions contained in an assembler program.

Function: size_t qsmm_get_prg_ninstr (qsmm_prg_t prg)

This function returns the number of instructions contained in a program prg. If prg is not a plain assembler program, the function returns 0.

Use the following function to get an instruction contained in an assembler program.

Function: qsmm_instr_t qsmm_get_prg_instr (qsmm_prg_t prg, size_t instr_idx)

This function returns an instruction contained in a program prg at zero-based index instr_idx. If prg is not a plain assembler program, or instr_idx is greater than or equal to the number of instructions in prg, the function returns NULL.

The following enumeration specifies the type of an assembler instruction.

Enumeration: qsmm_instr_e

This enumeration represents the type of an assembler instruction. The enumeration contains the following elements.

QSMM_INSTR_USER

A user or mixed-type instruction.

QSMM_INSTR_JMP

A jmp instruction.

QSMM_INSTR_JPROB

A jprob instruction.

QSMM_INSTR_CASE

A case instruction (in a choice instruction block).

QSMM_INSTR_CHOICE

A choice instruction.

QSMM_INSTR_JOE

A joe instruction.

QSMM_INSTR_STT

An stt instruction.

QSMM_INSTR_PROB

A prob instruction.

QSMM_INSTR_END

An end choice instruction (at the end of a choice instruction block).

Use the following function to get the type of an assembler instruction.

Function: enum qsmm_instr_e qsmm_get_instr_type (qsmm_instr_t instr)

This function returns the type of an instruction instr.

The function qsmm_get_prg_instr does not return instructions with the types QSMM_INSTR_CASE and QSMM_INSTR_END. Instead, it can return an instruction with the type QSMM_INSTR_CHOICE representing a choice instruction block containing nested case instructions and a nested end choice instruction. Use the following function to get the number of instructions nested in a choice instruction block.

Function: size_t qsmm_get_instr_nnested (qsmm_instr_t instr)

This function returns the number of instructions nested in an instruction instr of QSMM_INSTR_CHOICE type. For instructions of other types, the function returns 0.

Use the following function to get a nested case or end choice instruction.

Function: qsmm_instr_t qsmm_get_instr_nested (qsmm_instr_t instr, size_t nested_idx)

This function returns an instruction nested in an instruction instr with the type QSMM_INSTR_CHOICE. The argument nested_idx specifies zero-based index of a nested instruction.

If the instruction instr does not have the type QSMM_INSTR_CHOICE, or nested_idx is greater than or equal to the number of instructions nested in the instruction instr, the function returns NULL.

An instruction can have location labels placed to the left of the instruction or before it. Use the following function to get the number of location labels assigned to an instruction.

Function: size_t qsmm_get_instr_nlabel (qsmm_instr_t instr)

This function returns the number of location labels assigned to an instruction instr.

Use the following function to get a data label or location label.

Function: const char * qsmm_get_instr_label (qsmm_instr_t instr, size_t label_idx)

This function returns a data label or location label assigned to an instruction instr. If label_idx is (size_t) -1, the function returns a data label. If label_idx is not (size_t) -1, the function returns a location label at zero-based index label_idx. If the instruction does not have the data label or location label, the function returns NULL.


5.5 Printing an Assembler Program

Use the following function to get a string representation of an assembler instruction.

Function: int qsmm_instr_str (char *bufp, size_t bufsz, qsmm_instr_t instr, struct qsmm_dump_instr_desc_s *desc_p)

This function stores in a buffer bufp with size bufsz bytes a string representation of an instruction instr. If desc_p is not NULL, the function generates the string representation according to input parameters in *desc_p. If desc_p is NULL, the function generates the string representation according to default parameters. The function returns output parameters in either *desc_p or default parameters.

On success, the function returns a non-negative number of bytes required to store the string representation not counting finalizing byte 0 or returns INT_MAX if that number is greater than or equal to INT_MAX. The required number of bytes is also available in the field out_sz of qsmm_dump_instr_desc_s structure.

The required number of bytes greater than or equal to bufsz indicates the truncation of a string representation. In this case, if bufsz is positive, the function stores in bufp a truncated string representation with length bufsz–1 bytes and terminates the representation with byte 0. The function supports passing 0 for both bufp and bufsz to determine the length of a string representation.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument bufsz is positive, but bufp is NULL.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The QSMM library contains an instance of qsmm_dump_instr_desc_s structure holding default parameters of generating string representations of assembler instructions. Use the following function to get a pointer to the instance.

Function: struct qsmm_dump_instr_desc_s * qsmm_get_default_dump_instr_desc ()

This function returns a pointer to default parameters of generating string representations of assembler instructions. You can change the parameters via the pointer. The function never returns NULL.

The description of a structure specifying the parameters of generating string representations of instructions is below.

Structure: qsmm_dump_instr_desc_s

This structure specifies the parameters of generating a string representation of an assembler instruction. The structure contains the following fields.

Field: char is_line_after_comment_above

If this field is not 0, the field do_print_comment_above is not 0, and the instruction has a comment above itself, insert an empty line after the comment and before the instruction. The function qsmm_prg_dump uses this field in a similar way to determine whether to insert an empty line after a comment above a procedure. The default is to insert an empty line.

Field: char is_line_after_multiline_comment_right

If this field is not 0, and the field do_print_comment_right is not 0, insert an empty line after an instruction with a comment to the right ending below the first line of instruction text if the next instruction has an adjacent comment to the right. The default is to insert an empty line.

Field: char is_space_after_comma

If not 0, insert a space after every comma outside string literals in instruction parameters. The default is to insert a space.

Field: char do_print_label

If not 0 and the instruction has a location label assigned, print the location label to the left of the instruction. If the instruction has multiple location labels assigned, print all labels except for the last one on separate lines. If there is no room between the last label and an instruction name, print the last label on a separate line too. The default is to print location labels.

Field: char do_print_name

If not 0, print an instruction name. The default is to print.

Field: char do_print_param

If not 0, print instruction parameters. The default is to print.

Field: char do_print_comment_above

If not 0 and the instruction has a comment above itself, print the comment. The default is to print.

Field: char do_print_comment_right

If not 0 and the instruction has a comment to the right, print the comment. If is 1, start printing the comment on a line with an instruction name. If is greater than 1, start printing the comment at a column specified by the field col_comment starting on the first line of instruction text satisfying the condition: a comment on that line and all subsequent lines of instruction text would not interfere with an instruction name and instruction parameters. If there are no lines satisfying that condition, print the comment at column col_comment just beneath the instruction text. The default is to print the comment at column col_comment without interfering with an instruction name and instruction parameters.

Field: char do_print_var

If not 0, a jprob or case instruction uses the name of a variable for a probability, and the field prob_type is equal to QSMM_PROB_PROFILE, print that name instead of a numeric probability in the instruction. Otherwise, print a numeric probability. The default is to print a variable name instead of a numeric probability where possible.

Field: char do_print_state_name

If this field is not 0, the field do_print_param is not 0, and an stt instruction has an associated state name, print the state name in the stt instruction. The default is to print a state name.

Field: char do_print_prob[QSMM_PROB_COUNT]

An array specifying additional types of probabilities to print in a comment for a jprob or case instruction to the right. Array indices are the elements of qsmm_prob_e enumeration (except for its last element) described in Emitting an Output Signal. If the field do_print_comment_right is not 0, an element of the array is not 0, and the index of the element is not equal to the field prob_type, qsmm_instr_str prints a probability of a corresponding type in the comment. When printing an instruction of a program disassembled using an assembler program template, if the instruction has ambiguous context in the template, qsmm_instr_str prints ‘?’ for probabilities in the comment. The default is not to print probabilities in the comment.

Field: int prob_prec

The number of digits after the decimal point to print for a probability in a prob instruction, for a probability in a jprob or case instruction according to the field prob_type, and for probabilities in a comment to the right of a jprob or case instruction according to the field do_print_prob. If this field is non-negative, use fixed-point notation. If this field is negative, use exponential notation with the number of digits after the decimal point equal to the absolute value of this field. The default number of digits to print after the decimal point is 2.

Field: long col_name

If this field is positive, it specifies a column to align an instruction name and a comment above the instruction. This field also specifies a column for the function qsmm_prg_dump to align directive names, comments above procedures, tail comments in procedures, and a tail comment in an assembler program. If this field is not positive, do not align an instruction name, directive names, and the comments. The default alignment column is 9.

Field: long col_param

If this field is positive, it specifies a column to align instruction parameters on their first line and, if instruction parameters occupy multiple lines, a column to indent them on the following lines. If this field is not positive, do not align or indent the instruction parameters. The default alignment column is 17.

Field: long col_comment

If this field is positive, it specifies a column to align a comment to the right of an instruction. If the field do_print_comment_right is greater than 1, the comment starts exactly at the column and does not interfere with an instruction name or instruction parameters. If this field is not positive, do not align the comment. The default alignment column is 33.

Field: long margin_right

If this field is positive, it specifies a right margin column for comments. The functions qsmm_instr_str and qsmm_prg_dump split longer comments into multiple lines. If this field is not positive, do not split comments into multiple lines based on a right margin column. The default is not to split.

Field: long margin_right_param

If this field is positive, it specifies a right margin column for the parameters of a user instruction. The function qsmm_instr_str splits longer parameters into multiple lines and uses positions of commas outside string literals as allowed split positions. If this field is not positive, do not split the parameters into multiple lines based on a right margin column. The default right margin column is 30.

Field: long line_comment_right_start

Output parameter. [New in QSMM 1.19] The function qsmm_instr_str stores here a zero-based index of a line of instruction text containing the first line of a comment printed to the right of the instruction. If the index is equal to the field nline_param, qsmm_instr_str has printed the comment just beneath the instruction. If this field is negative, qsmm_instr_str has not printed the comment. The function qsmm_prg_dump reads this field to insert an empty line after an instruction with a comment to the right ending below the first line of instruction text if the next instruction has an adjacent comment to the right.

Field: long nline_comment_right

Output parameter. The function qsmm_instr_str stores here the number of lines in a comment to the right of an instruction. If an instruction name or instruction parameters are too long, qsmm_instr_str may put the comment below the first line of instruction text. If qsmm_instr_str has not printed the comment, it sets this field to 0. The function qsmm_prg_dump reads this field to insert an empty line after an instruction with a comment to the right ending below the first line of instruction text if the next instruction has an adjacent comment to the right.

Field: long nline_param

Output parameter. The function qsmm_instr_str stores here the number of printed lines containing an instruction name and instruction parameters. The function qsmm_prg_dump reads this field to determine whether to insert empty lines around multi-line instructions and whether a comment to the right of an instruction ends on the last line of instruction text or beneath the instruction text and, therefore, can be adjacent to a comment of the next instruction.

Field: size_t out_sz

Output parameter. [New in QSMM 1.17] The number of bytes not counting finalizing byte 0 occupied by a string representation that would be printed by the function qsmm_instr_str. That number does not depend on buffer size passed to qsmm_instr_str.

Field: enum qsmm_prob_e prob_type

The type of a probability to print in a jprob or case instruction. See Emitting an Output Signal, for the description of elements of qsmm_prob_e enumeration. When printing an instruction of a program disassembled using an assembler program template, if the instruction has ambiguous context in the template, the function qsmm_instr_str prints ‘?’ for a probability. The default probability type is QSMM_PROB_AGGR.

Note: when converting a disassembled program or its specific instructions to a string representation, be sure to set the fields do_print_prob and prob_type of qsmm_dump_instr_desc_s structure to values consistent with the fields do_calc_prob and prob_type of qsmm_disasm_desc_s structure passed when creating the disassembled program. Otherwise, the function qsmm_instr_str or qsmm_prg_dump may print zero probabilities.

Use the following function to dump a program to a stream.

Function: int qsmm_prg_dump (qsmm_prg_t prg, struct qsmm_dump_prg_desc_s *desc_p, FILE *filep)

This function dumps a program prg to a stream filep. If desc_p is not NULL, the function dumps the program according to parameters in *desc_p. If desc_p is NULL, the function dumps the program according to default parameters.

In the current implementation the function does not modify *desc_p or default parameters (but can modify a structure instance addressed by the field dump_instr_desc_p of qsmm_dump_prg_desc_s structure). However, in a future implementation the function may modify them, for example, to store there statistics on the dumping process.

This function calls the function qsmm_instr_str to obtain string representations of individual assembler instructions and passes to the latter function the field dump_instr_desc_p of qsmm_dump_prg_desc_s structure referencing input and output parameters of generating the string representations.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The QSMM library contains an instance of qsmm_dump_prg_desc_s structure holding default parameters of dumping a program. Use the following function to get a pointer to the instance.

Function: struct qsmm_dump_prg_desc_s * qsmm_get_default_dump_prg_desc ()

This function returns a pointer to default parameters of dumping an assembler program. You can change the parameters via the pointer. The function never returns NULL.

The description of a structure specifying the parameters of dumping a program is below.

Structure: qsmm_dump_prg_desc_s

This structure specifies the parameters of dumping an assembler program. The structure contains the following fields.

Field: char is_line_before_label

If not 0, insert an empty line before a line with a location label definition. If an instruction has multiple location labels assigned (dumped on separate lines), the function qsmm_prg_dump inserts an empty line only before the first location label definition. The default is to insert.

Field: char is_line_before_isolated_comment

If not 0, insert an empty line before a comment above an instruction. If not 0 and the field do_print_comment_head is not 0, insert an empty line before a comment above a procedure. If not 0 and the field do_print_comment_tail is not 0, insert an empty line before a comment at procedure end and before a comment at program end. The default is to insert.

Field: char are_lines_around_choice

If not 0, insert an empty line before a choice instruction block and insert an empty line after the block. The default is to insert.

Field: char are_lines_around_multiline_param

If not 0, insert an empty line before an instruction with a name and parameters occupying multiple lines and insert an empty line after the instruction. The default is to insert.

Field: char are_lines_inset_proc

[New in QSMM 1.19] If not 0, insert an empty line after a line with a ‘proc’ directive and insert an empty line before a line with an ‘end proc’ directive. The default is to insert.

Field: char do_print_comment_head

[New in QSMM 1.19] If not 0 and a procedure has a comment above itself, dump the comment. The default is to dump.

Field: char do_print_comment_tail

If not 0 and a procedure or the program contains a comment at its end, dump the comment. The default is to dump.

Field: int nline_around_proc

[New in QSMM 1.19] The number of empty lines to insert around a procedure. The default number of empty lines to insert is 2.

Field: struct qsmm_dump_instr_desc_s * dump_instr_desc_p

If this field is not NULL, it specifies input and output parameters of dumping assembler instructions by the function qsmm_instr_str. If this field is NULL, qsmm_instr_str uses default dumping parameters returned by the function qsmm_get_default_dump_instr_desc.


5.6 Parsing an Assembler Program

QSMM supports parsing an assembler program supplied in a string buffer, input stream, or file. A parsing result is a memory representation you can inspect, print, or load into a node.

Functions that parse an assembler program take the argument flags specifying parsing modes. That argument is a bitmask defined as a subset of macros described below merged by bitwise “or.”

Macro: QSMM_PARSE_ASM_PREPROCESS

Preprocess an assembler program text by the assembler preprocessor before parsing the text.

The functions qsmm_parse_asm_source_buf and qsmm_parse_asm_source_stream described further on in this section take the argument cwd_p specifying the name of a current working directory used when resolving ‘include’ directives. If cwd_p is NULL, the functions use an actual current working directory when resolving ‘include’ directives. The function qsmm_parse_asm_source_file described further on in this section always uses an actual current working directory when resolving ‘include’ directives.

Macro: QSMM_PARSE_ASM_STRIP_COMMENTS

[New in QSMM 1.19] Do not save comments encountered in an assembler program text to a memory representation of an assembler program.

Macro: QSMM_PARSE_ASM_COMPOUND

[New in QSMM 1.19] Treat an assembler program as compound one consisting of procedures bounded by ‘proc’ and ‘end proc’ directives. In this mode an assembler program must not contain instructions outside of procedures.

You cannot load a memory representation of a compound assembler program into the nodes of a multinode model directly. Instead, you can use the functions qsmm_get_prg_name, qsmm_get_prg_nnested, and qsmm_get_prg_nested to fetch individual procedures from a compound assembler program for loading them into individual nodes.

Macro: QSMM_PARSE_ASM_WARN_UNUSED_LABELS

[New in QSMM 1.19] Generate warnings for unused location labels.

Use the following functions to parse the text of an assembler program—convert that text to a memory representation of the assembler program.

Function: int qsmm_parse_asm_source_buf (const char *in_p, const char *cwd_p, unsigned int flags, void *rez1, void *rez2, qsmm_msglist_t msglist, qsmm_prg_t *prg_p)
Function: int qsmm_parse_asm_source_stream (FILE *filep, const char *cwd_p, unsigned int flags, void *rez1, void *rez2, qsmm_msglist_t msglist, qsmm_prg_t *prg_p)

The function qsmm_parse_asm_source_buf parses an assembler program with source text supplied in a string in_p. The function qsmm_parse_asm_source_stream parses an assembler program with source text read from a stream filep. Both functions store allocated handle of a parsed program in *prg_p if prg_p is not NULL.

If msglist is not NULL, the functions add to a message list msglist error, warning, and note messages generated while parsing the source text. The arguments rez1 and rez2 are for future use and must be equal to 0.

The argument flags specifies parsing modes as a bitmask defined as a subset of QSMM_PARSE_ASM_* macros merged by bitwise “or.” If flags has a bit specified by the mask QSMM_PARSE_ASM_PREPROCESS set, the preprocessor uses cwd_p as the name of a current working directory when resolving ‘include’ directives. If cwd_p is NULL, the preprocessor uses an actual current working directory when resolving ‘include’ directives.

The functions return a non-negative value on success or a negative error code on failure. Even on successful completion of qsmm_parse_asm_source_stream, you should check the result of ferror(filep) to detect a possible stream read error. Currently, the functions can return the following error codes.

QSMM_ERR_PRG

The source program text has at least one error. If msglist is not NULL, a message list msglist contains at least one error message.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale, including inability to convert the source program text to a wide string.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_parse_asm_source_file (const char *fln, unsigned int flags, void *rez1, void *rez2, qsmm_msglist_t msglist, qsmm_prg_t *prg_p)

This function parses an assembler program with source text supplied in a file fln. The function stores allocated handle of a parsed program in *prg_p if prg_p is not NULL. If msglist is not NULL, the function adds to a message list msglist error, warning, and note messages generated while parsing the source text. The argument flags specifies parsing modes as a bitmask defined as a subset of QSMM_PARSE_ASM_* macros merged by bitwise “or.” The arguments rez1 and rez2 are for future use and must be equal to 0.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_LIBC

The operating system reported a file access error. The variable errno holds the error code.

QSMM_ERR_PRG

The source program text has at least one error. If msglist is not NULL, a message list msglist contains at least one error message.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale, including inability to convert the source program text to a wide string.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

See Creating a Message List, for the description of a function for creating an empty message list for passing it to the functions parsing an assembler program and the description of a function for destroying the message list afterwards. See Printing Messages, for the description of a function for dumping to a stream a message list possibly filled with error, warning, and note messages generated while parsing an assembler program.


5.7 Assembling a Node

An assembler program specifies a probability profile loadable into the nodes of a multinode model. Assembling a node is loading into it a probability profile specified by a memory representation of a plain assembler program. The function qsmm_node_asm implements a node assembler performing this operation.

The node assembler can generate error and warning messages possibly with details in accompanying note messages. They can indicate the location of the beginning of a state containing a problematic instruction and explain why the state begins at that location.

State names specified by arguments of stt instructions are convertible to state indices. State names are accessible by state indices.


5.7.1 Loading a Parsed Program into a Node

To load a memory representation of a plain assembler program into a node, its instruction class set must contain instruction classes for all user and mixed-type instructions used in the assembler program, and the multinode model must have the look-ahead signal segment with zero length.

Warning: if the environment state identification engine is a small actor (the field engine_desc[QSMM_ENGINE_ENV].large_desc_p of qsmm_desc_s structure passed to the function qsmm_create is NULL), and it uses a built-in function for computing the relative probability of an output signal, adaptive behavior of assembler programs specifying nondeterministic state transitions is generally ill-defined. Similarly, if the instruction emitting engine is a small actor (the field engine_desc[QSMM_ENGINE_IEE].large_desc_p of qsmm_desc_s is NULL), and it uses a built-in function for computing the relative probability of an output signal, adaptive behavior of assembler programs specifying nondeterministic instruction emissions is also generally ill-defined. It is so, because profile probabilities act as output signal weights, and the explanation in Number of Output Signals applies. Therefore, tend to using large actors for the environment state identification engine and instruction emitting engine in the general case.

The functions qsmm_node_asm and qsmm_get_prg_nstate_v2 described further on in this section take the argument flags specifying the modes of processing a memory representation of an assembler program. That argument is a bitmask defined as a subset of macros described below merged by bitwise “or.”

Macro: QSMM_ASM_DETERM_GOTO

Impose the following restriction on a probability profile for the state transition matrix: for every triple consisting of a source node state, an individual user or mixed-type instruction or a sequence of individual or mixed-type instructions emitted in the source node state, and an instruction outcome, the probability profile must specify a single target state, that is, the selection of a target node state must be deterministic.

Setting to a non-zero value the field engine_desc[QSMM_ENGINE_ENV].is_determ of qsmm_desc_s structure passed to the function qsmm_create turns on this mode for all nodes in a multinode model. See Creating a Handle, for the description of is_determ field of qsmm_engine_desc_s structure for more information.

Macro: QSMM_ASM_DETERM_ACTION

Impose the following restriction on a probability profile for the action emission matrix: for every node state, the probability profile must specify a single user or mixed-type instruction or a single sequence of user or mixed-type instructions emitted in the node state, that is, the selection of an individual instruction or instruction sequence must be deterministic.

Setting to a non-zero value the field engine_desc[QSMM_ENGINE_IEE].is_determ of qsmm_desc_s structure passed to the function qsmm_create turns on this mode for all nodes in a multinode model. See Creating a Handle, for the description of is_determ field of qsmm_engine_desc_s structure for more information.

Macro: QSMM_ASM_TEMPLATE

Store the memory representation of an assembler program in the node as a template. The function qsmm_node_disasm automatically uses the template when disassembling the node: a disassembled program is a template program with profile probabilities in jprob and case instructions replaced with probabilities of a type specified by the field prob_type of qsmm_disasm_desc_s structure passed to qsmm_node_disasm or the type QSMM_PROB_AGGR when using default disassembling parameters. The function qsmm_node_disasm removes prob instructions from the disassembled program.

The field prob_goto_min of qsmm_disasm_desc_s structure specifies a minimum probability in jprob and case instructions for the state transition matrix. The field prob_action_min of qsmm_disasm_desc_s structure specifies a minimum probability in jprob and case instructions for the action emission matrix. The disassembler removes jprob and case instructions containing lesser probabilities from a disassembled program, although the template program contained the instructions. The disassembler can calculate additional probabilities with types specified by the field do_calc_prob of qsmm_disasm_desc_s structure for subsequent adding to comments for jprob and case instructions.

Macro: QSMM_ASM_VAR_OUT

Collect information on output probability variables in an assembler program. You use them to fetch the probabilities of jprob and individual case instructions learned while executing or training the node. See Output Variables, for more information.

Macro: QSMM_ASM_ARRAY_OUT

Collect information on output probabilities arrays in an assembler program. You use them to fetch probabilities for choice instruction blocks learned while executing or training the node. See Output Arrays, for more information.

Macro: QSMM_ASM_VAR_AUX

Enable the use of auxiliary probability variables in an assembler program. They act as constants and are neither controlled nor output variables. The disassembler merely replaces occurrences of auxiliary probability variables in jprob and case instructions with values of the variables. See Auxiliary Variables, for more information.

The functions qsmm_node_asm and qsmm_get_prg_nstate_v2 do not process compound assembler programs. Use the functions qsmm_get_prg_nnested, qsmm_get_prg_nested, and qsmm_get_prg_name described in Inspecting an Assembler Program to fetch procedures from a memory representation of a compound assembler program, determine their names, and pass the procedures to qsmm_node_asm or qsmm_get_prg_nstate_v2 individually.

Use qsmm_node_asm to load an assembler procedure or plain assembler program into a node.

Function: int qsmm_node_asm (qsmm_t model, qsmm_sig_t node, unsigned int flags, qsmm_prg_t prg, qsmm_msglist_t msglist)

This function assembles a node of a multinode model—loads a probability profile specified by a plain assembler program prg into the node. The argument node passes its identifier. The argument flags specifies assembling modes defined as a subset of QSMM_ASM_* macros merged by bitwise “or.”. If msglist is not NULL, the function adds to a message list msglist error, warning, and note messages generated while assembling.

If the function encounters instruction class sequences while assembling the node, and its instruction class set does not contain them, the function registers the instruction class sequences in the instruction class set.

The function clears event history statistics collected for the node. If the node already has a probability profile loaded, the function first unloads the profile. To clear the event history statistics and unload the profile, this function calls the function qsmm_node_unload.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_PRG

A program prg has an error. If msglist is not NULL, the function adds at least one error message along with possible warning and note messages to a message list msglist. If model has an error handler assigned, it receives a message list with at least one error message along with possible warning and note messages.

QSMM_ERR_UNTIMELY

One of the following conditions is true:

  • a model instance does not exist;
  • loading a probability profile into the node requires increasing its number of states, and this operation requires increasing the number of output signals of an existing environment state identification engine represented by a large actor, but it has created a default output signal choice tree;
  • registering an instruction class sequence requires increasing the number of output signals of an existing instruction emitting engine represented by a large actor, but it has created a default output signal choice tree.

See Number of Output Signals, for cases when a large actor creates a default output signal choice tree.

QSMM_ERR_PROFSRCP

The node is a probability profile source for other nodes. See Memory Efficient Cloning the Probability Profile, for more information on this mode.

QSMM_ERR_NOTSUP

A program prg is compound one, or model has positive length of look-ahead signal segment.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_UNTIMELY, QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the probability profile of the node in inconsistent state or make the instruction class set of the node contain newly registered but unused instruction class sequences. If after removing a reason of an error a repeated call to this function succeeds, the inconsistencies become fixed.

Use the function described below to count the number of states in an assembler program. The function is mainly for informational purposes, as QSMM 1.19 does not require to use that number before loading the assembler program into a node.

Function: int qsmm_get_prg_nstate_v2 (qsmm_t model, const char *instr_class_set_name, int rez1, unsigned int flags, qsmm_prg_t prg, qsmm_msglist_t msglist, qsmm_sig_t *nstate_p)

This function calculates the number of states required for the nodes of a multinode model to hold a probability profile specified by a plain assembler program prg. The argument instr_class_set_name specifies the name of instruction class set of the nodes. The argument flags specifies assembling modes defined as a subset of QSMM_ASM_* macros merged by bitwise “or.”. If msglist is not NULL, the function adds to a message list msglist error, warning, and note messages generated during the calculation. The argument rez1 is for future use and must be equal to 0.

On success, the function returns a non-negative value and sets *nstate_p to a calculated number of states if nstate_p is not NULL. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_PRG

The program prg has an error. If msglist is not NULL, the function adds at least one error message along with possible warning and note messages to a message list msglist. If model has an error handler assigned, it receives a message list with at least one error message along with possible warning and note messages.

QSMM_ERR_NOTSUP

A program prg is compound one, or model has positive length of look-ahead signal segment.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


5.7.2 Possible Error Messages

The functions qsmm_node_asm and qsmm_get_prg_nstate_v2 can generate the following error messages.

controlled var ‘name’ is for action emission matrix backed by large actor

QSMM 1.19 does not support using controlled probability variables for the action emission matrix if the instruction emission engine is a large actor. Here name is a controlled probability variable for the action emission matrix.

controlled var ‘name’ is for state transition matrix backed by large actor

QSMM 1.19 does not support using controlled probability variables for the state transition matrix if the environment state identification engine is a large actor. Here name is a controlled probability variable for the state transition matrix.

deterministic action emission matrix disallows the probabilistic jump

The action emission matrix has the restriction to define only deterministic action emissions, but a block of jprob instructions or a choice instruction block specifies profile probabilities of action emissions. The assembler considers that the block specifies profile probabilities of action emissions, because it goes after an stt instruction, or because the state transition matrix has the restriction to define only deterministic state transitions.

deterministic state transition matrix disallows the probabilistic jump

The state transition matrix has the restriction to define only deterministic state transitions, but a block of jprob instructions or a choice instruction block specifies profile probabilities of state transitions. The assembler considers that the block specifies profile probabilities of state transitions because the action emission matrix has the restriction to define only deterministic action emissions.

infinite looping

A jmp instruction or a jprob or case instruction with jump probability 1 transfers control to a chain of jmp instructions circularly transferring control to a jmp instruction in the chain or the jprob instruction.

infinite looping is possible

A joe instruction or a jprob or case instruction with a jump probability greater than 0 but less than 1 transfers control to a chain of jmp instructions circularly transferring control a jmp instruction in the chain or the joe instruction.

Alternatively, a chain of unconditional jumps executed after a joe instruction that does not transfer control to the next instruction transfers control to the joe instruction.

instruction class ‘name’ not found

An assembler program contains an assembler instruction belonging to an instruction class name, but it does not exist in the instruction class set of the node.

output probabilities array ‘name’ has ambiguous context

A probabilities array name specifies profile probabilities for both the state transition matrix and action emission matrix.

output probability variable ‘name’ is duplicate or has ambiguous context

A probability variable name is not controlled one, flags include QSMM_ASM_VAR_OUT but do not include QSMM_ASM_VAR_AUX, and at least one of the following conditions is true for the probability variable:

  • it has another occurrence;
  • it belongs to different contiguous blocks of jprob instructions;
  • it specifies a profile probability for both the state transition matrix and action emission matrix;
  • it is another output probability variable for the same cell of the state transition matrix.
recursive jump to beginning of ‘choice’ instruction block not allowed

A case instruction with a positive jump probability transfers control via an optional chain of jmp instructions to a choice instruction block containing the case instruction.

state contains another emission of “name_and_parameters” instruction here

A block of jprob instructions or a choice instruction block located at the beginning of a state already contains a jprob or case instruction transferring control to an instruction name_and_parameters.

state contains another emission of this instruction sequence

A block of jprob instructions or a choice instruction block located at the beginning of a state already contains a jprob or case instruction transferring control to the same instruction sequence.

unexpected probability variable ‘name

A probability variable name is not controlled one, and flags do not include QSMM_ASM_VAR_OUT and QSMM_ASM_VAR_AUX.

user or mixed-type instruction expected

The assembler expects a user or mixed-type instruction at this location because it is the beginning of a state or because the location is a jump target of a jprob or case instruction contained in a block of jprob instructions or a choice instruction block at the beginning of a state.


5.7.3 Possible Warning Messages

The functions qsmm_node_asm and qsmm_get_prg_nstate_v2 can generate the following warning messages.

‘stt’ instruction expected

The assembler expects the beginning of a state in the assembler program, but there is no stt instruction at that location. The assembler defines the state implicitly. The assembler does not generate this warning if the state transition matrix has the restriction to define only deterministic state transitions, or the action emission matrix has the restriction to define only deterministic action emissions. The assembler can generate note messages after this warning explaining why the state begins there.

all valid outcomes already tested

Control never reaches an instruction after a joe instruction block because the block contains tests for all possible outcomes of a user or mixed-type instruction.

ignoring the test for outcome num because such test already exists

The assembler ignores the joe instruction performing a jump on outcome num because there was an earlier joe instruction also performing a jump on outcome num.

ignoring the test for outcome num because the outcome is out of range

The assembler ignores the joe instruction performing a jump on outcome num because that joe instruction tests the outcome of a user or mixed-type instruction with the number of possible outcomes less than or equal to num.

instruction has no effect because jump probability is 0

The assembler ignores the jprob or case instruction because it specifies a jump with probability 0.

instruction has no effect because of a jump beneath the ‘choice’ block

The assembler ignores the case instruction because it specifies a jump beneath a containing choice instruction block.

instruction has no effect because of a jump to the next instruction

The assembler ignores the jprob or joe instruction because it specifies a jump to the next instruction.

instruction has no effect because of a possible jump to itself

The assembler ignores the jprob instruction because it specifies a jump to itself with probability less than 1.

instruction is replaceable with a ‘jmp’ instruction

Beneath the jprob instruction with jump probability greater than 0 there is a jmp instruction transferring control to that jprob instruction, and the jprob instruction does not specify a possible jump to the jmp instruction. You can replace the jprob instruction and the jmp instruction with a single jmp instruction transferring control to jump target of the jprob instruction.

unreachable state

Control never reaches the state. The assembler can generate note messages after this warning explaining why the state begins there.


5.7.4 Possible State Beginning Reasons

After some error and warning messages, the assembler generates one or more note messages:

  • indicating the line of the beginning of an assembler program state containing the line of the error or warning message;
  • explaining why the state begins there.

The list below contains possible reasons why an assembler program line can be the beginning of a state. If a line has multiple reasons why it is the beginning of a state, a note message contains a reason that goes first in this list.

the ‘stt’ instruction marks it

An stt instruction always marks a state beginning.

it is a program start

The assembler program begins with an initial state beginning with a user or mixed-type instruction.

Alternatively, the state transition matrix has the restriction to define only deterministic state transitions, and the assembler program begins with an initial state beginning with a block of jprob instructions or a choice instruction block.

this instruction at the program start transfers control to the state

The assembler program begins with a jmp instruction transferring control via an optional chain of unconditional jumps to an initial state beginning with a user or mixed-type instruction.

Alternatively, the state transition matrix has the restriction to define only deterministic state transitions, and the assembler program begins with a jmp instruction transferring control via an optional chain of unconditional jumps to an initial state beginning with a block of jprob instructions or a choice instruction block.

this ‘jprob’ instruction at program start transfers control to the state

The assembler program begins with a block of jprob instructions, and jump target of one of them is an initial state beginning with a user or mixed-type instruction, a block of jprob instructions, or a choice instruction block.

it follows this ‘jprob’ instruction at program start

The assembler program begins with a single jprob instruction followed by the second of two initial states. That initial state begins with a user or mixed-type instruction or a choice instruction block. The first initial state begins at jump target of the jprob instruction.

it is at the end of this block of ‘jprob’ instructions at program start

The assembler program begins with two or more consecutive jprob instructions followed by the last initial state beginning with a user or mixed-type instruction or a choice instruction block. The other initial states begin at jump targets of the jprob instructions.

it is at the end of this ‘choice’ instruction block at program start

The assembler program begins with a choice instruction block followed by the last initial state beginning with a user or mixed-type instruction, a block of jprob instructions, or a choice instruction block. The other initial states begin at jump targets of case instructions in the former choice instruction block.

this ‘case’ instruction at program start transfers control to the state

The assembler program begins with a choice instruction block containing a case instruction, and its jump target is an initial state beginning with a user or mixed-type instruction, a block of jprob instructions, or a choice instruction block.

this instruction performs a recursive jump to a user instruction

A chain of unconditional jumps at the end of a block of user or mixed-type instructions circularly transfers control to a user or mixed-type instruction in the block. The user or mixed-type instruction becomes a state beginning.

this instruction performs a recursive jump to a ‘joe’ instruction

A chain of unconditional jumps at the end of a block of joe instructions circularly transfers control to a joe instruction in the block. The joe instruction becomes a state beginning.

this instruction performs a recursive jump to a ‘jprob’ instruction

A chain of unconditional jumps at the end of a block of jprob instructions circularly transfers control to a jprob instruction in the block. The jprob instruction becomes a state beginning.

this ‘joe’ instruction transfers control to it

Jump target of the joe instruction is a user or mixed-type instruction at a state beginning.

Alternatively, the state transition matrix has the restriction to define only deterministic state transitions, and jump target of the joe instruction is a block of jprob instructions or a choice instruction block at a state beginning.

it follows this ‘joe’ instruction

A single joe instruction precedes a state beginning with a user or mixed-type instruction.

Alternatively, the state transition matrix has the restriction to define only deterministic state transitions, and a single joe instruction precedes a state beginning with a block of jprob instructions or a choice instruction block.

it is at the end of this block of ‘joe’ instructions

A block of two or more consecutive joe instructions precedes a state beginning with a user or mixed-type instruction.

Alternatively, the state transition matrix has the restriction to define only deterministic state transitions, and a block of two or more consecutive joe instructions precedes a state beginning with a block of jprob instructions or a choice instruction block.

this ‘jprob’ instruction is for selecting a user instruction

The state transition matrix has the restriction to define only deterministic state transitions, so the first jprob instruction in a block of jprob instructions is a state beginning.

this ‘jprob’ instruction transfers control to it

The assembler considers the jprob instruction as specifying a profile probability for the state transition matrix, so jump target of this instruction is a state beginning.

it follows this ‘jprob’ instruction

The assembler considers a single jprob instruction as specifying a profile probability for the state transition matrix, so a user or mixed-type instruction following the jprob instruction is a state beginning.

it is at the end of this block of ‘jprob’ instructions

The assembler considers a block of two or more jprob instructions as specifying profile probabilities for the state transition matrix, so a user or mixed-type instruction following the block is a state beginning.

this ‘choice’ instruction block is for selecting a user instruction

The state transition matrix has the restriction to define only deterministic state transitions, so the choice instruction block is a state beginning.

it is at the end of this ‘choice’ instruction block

The assembler considers the choice instruction block as specifying profile probabilities for the state transition matrix, so a user or mixed-type instruction following the block is a state beginning.

this ‘case’ instruction transfers control to it

The assembler considers the case instruction as specifying a profile probability for the state transition matrix, so jump target of this instruction is a state beginning.

it is an unreferenced user or mixed-type instruction

After processing all control transfer paths from all initial states and, probably, some unreferenced states in an assembler program, there remained a block of user or mixed-type instructions that did not receive control. The first instruction of the block becomes the beginning of an unreferenced state.

it is an unreferenced ‘joe’ instruction

After processing all control transfer paths from all initial states and, probably, some unreferenced states in an assembler program, there remained a block of joe instructions that did not receive control. The first instruction of the block becomes the beginning of an unreferenced state.

it is an unreferenced ‘jprob’ instruction

After processing all control transfer paths from all initial states and, probably, some unreferenced states in an assembler program, there remained a block of jprob instructions that did not receive control. The first instruction of the block becomes the beginning of an unreferenced state.

it is an unreferenced ‘choice’ instruction block

After processing all control transfer paths from all initial states and, probably, some unreferenced states in an assembler program, there remained the choice instruction block that did not receive control. The block becomes the beginning of an unreferenced state.


5.7.5 State Names in stt Instructions

An assembler program can have names assigned to its states by arguments of stt instructions. Use the following function to retrieve the index of a state of a node by the name of the state after loading an assembler program into the node.

Function: int qsmm_get_node_state_by_name (qsmm_t model, const char *state_name, qsmm_sig_t node, qsmm_sig_t *state_p)

This function retrieves the index of a state of a node of a multinode model by a state_name assigned by an stt instruction marking the beginning of the state in an assembler program loaded into the node. The argument node specifies the identifier of the node.

On success, the function returns a non-negative value and sets *state_p if state_p is not NULL. If the state exists, the function sets *state_p to the index of the state. If the node does not have an assembler program loaded, or the assembler program does not define a state named state_name, the function sets *state_p to QSMM_SIG_INVALID.

If the node uses a source probability profile provided by another node, the function retrieves the index of a node state defined in an assembler program loaded into the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_ILSEQ

Unable to convert state_name to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to retrieve the name of a node state by its index.

Function: int qsmm_get_node_state_name (qsmm_t model, qsmm_sig_t node, qsmm_sig_t state, const char **state_name_pp)

This function retrieves the name of a state of a node of a multinode model by the index of the state. An stt instruction in an assembler program loaded into the node assigns that name to the state. The argument node specifies the identifier of the node. The argument state specifies the index of the state.

On success, the function returns a non-negative value and sets *state_name_pp if state_name_pp is not NULL. If the state has a name assigned by the argument of an stt instruction, the function sets *state_name_pp to the name. If the state does not have an assigned name, the function sets *state_name_pp to NULL.

If the node uses a source probability profile provided by another node, the function retrieves a state name specified in an assembler program loaded into the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument state is greater than or equal to the number of node states holding a probability profile specified by an assembler program.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_ILSEQ

Unable to convert a state name to a multibyte string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


5.8 Using Probability Variables

The prob instruction defines a probability variable with a name in the data label of that instruction. A jprob or case instruction can define a probability variable similarly to the prob instruction or use a probability variable with a name specified instead of a numeric probability value. There are three supported types of probability variables:

  • Controlled variables. They are the means of modifying a probability profile loaded into a node. A single controlled variable can occur in multiple jprob and case instructions.
  • Output variables. They are the means of fetching probabilities learned while executing a node. A single output variable occurs in a single jprob or case instruction.
  • Auxiliary variables. They act as constants. The assembler replaces every occurrence of an auxiliary variable in an argument of a jprob or case instruction with a probability value specified using a prob, jprob, or case instruction with a data label.

A controlled probability variable can simultaneously be an output probability variable.

An output probabilities array is the means of fetching probabilities learned for case instructions in a choice instruction block by indices of case instructions. A data label assigned to the choice instruction block is an array name.


5.8.1 Variables in an Assembler Program

The prob instruction declares a probability variable and sets it equal to a specific value:

var_name prob    val

A jprob or case instruction can declare a probability variable too:

var_name_1 jprob   val1, loc_label_1

           choice
           ...
var_name_2 case    val2, loc_label_2
           ...
var_name_3 case    val3, loc_label_3
           ...
           case    val4, loc_label_4
           ...
           end     choice

A declared probability variable takes a value specified by the first argument of jprob or case instruction.

The name of a declared probability variable is available for use in jprob and case instructions on subsequent lines of a plain assembler program or assembler procedure:

           jprob   var_name, loc_label_5

           choice
           ...
           case    var_name_1, loc_label_6
           ...
           case    var_name_2, loc_label_7
           ...
           case    var_name_3, loc_label_8
           ...
           case    val9, loc_label_9
           ...
           end     choice

A jprob or case instruction cannot simultaneously declare a probability variable (via a data label) and use a probability variable specified in the first instruction argument.

After parsing an assembler program, you can obtain the number of probability variables declared in it by the following function.

Function: size_t qsmm_get_prg_nvar (qsmm_prg_t prg)

This function returns the number of probability variables declared in a program prg using data labels of prob, jprob, and case instructions.

Use the following function to get the name of a probability variable by its index.

Function: const char * qsmm_get_prg_var_name (qsmm_prg_t prg, size_t var_idx)

This function returns the name of a probability variable with index var_idx in a program prg. If var_idx is greater than or equal to the number of probability variables declared in the program using data labels of prob, jprob, and case instructions, the function returns NULL.

See Output Arrays, for how to declare output probabilities arrays in an assembler program.


5.8.2 Controlled Variables

Controlled probability variables are the means of changing a probability profile loaded into a node, for example, as a result of reasoning or self-programming.

Note: in the current implementation, an assembler program can contain controlled probability variables for profile probabilities in the state transition matrix or action emission matrix only if the environment state identification engine or instruction emitting engine respectively is a small actor. As well-defined model operation generally requires using large actors for the environment state identification engine and instruction emitting engine, practical ability to use controlled probability variables will appear after an improvement of QSMM library.

You have to register controlled probability variables in the instruction class set of a node. After registering the variables and creating the node, you can load into it an assembler program referencing a subset of the variables. Later, you can change their values for the node thereby changing its probability profile (e.g. while processing instruction invocations by event handlers of instruction meta-classes). Changing the value of a controlled probability variable causes updating profile probabilities in the state transition matrix and/or action emission matrix for occurrences of jprob and case instructions containing the variable for a probability.

Use the following function to register a controlled probability variable in an instruction class set.

Function: int qsmm_reg_var_prob (qsmm_t model, const char *instr_class_set_name, const char *var_name, size_t *var_idx_p)

This function registers a controlled probability variable var_name in instruction class set instr_class_set_name of a multinode model. If var_idx_p is not NULL, the function sets *var_idx_p to the index of the variable in the instruction class set.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument var_name does not contain a valid name for a probability variable.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_EXIST

The instruction class set already has a controlled probability variable var_name registered.

QSMM_ERR_VIOLNODE

There exists a node belonging to a node class represented by the instruction class set instr_class_set_name.

QSMM_ERR_NOTSUP

The environment state identification engine and instruction emitting engine are large actors, or the multinode model has positive length of look-ahead signal segment.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Currently, there are no API functions taking as an argument the index of a controlled probability variable returned by the function qsmm_reg_var_prob. Instead, functions that query and set values of controlled probability variables take the name of a variable as an argument. To speed up querying and setting the values, future QSMM versions may include counterpart functions taking the index of a variable instead of its name.

Use the following macro to register a controlled probability variable on processing an event QSMM_EVT_ENT_INIT by the event handler of an instruction class set.

Macro: QSMM_REG_VAR_PROB (var_name)

This macro registers a controlled probability variable var_name. The macro expands to:

qsmm_reg_var_prob((qsmm), __FUNCTION__, (var_name), 0)

This macro is for expansion from the event handler of an instruction class set. The macro expects that the name of the event handler function is equal to the name of the instruction class set and the variable qsmm holding the handle of a multinode model is accessible in the event handler function. Normally, that variable is an event handler function argument.

Use the following function to get names of controlled probability variables registered in an instruction class set.

Function: int qsmm_enum_var_prob (qsmm_t model, const char *instr_class_set_name, qsmm_enum_ent_callback_func_t callback_func, void *paramp)

This function enumerates controlled probability variables registered in instruction class set instr_class_set_name of a multinode model. The process of enumeration is repeated calling a callback function callback_func receiving QSMM_LREF_PROB_VAR_CTRL as the type of a local entity reference, the name of a controlled probability variable as a local entity identifier, and a user parameter paramp. See Enumerating Entities, for the description of callback function type.

If the callback function returns a positive value, qsmm_enum_var_prob continues enumeration. If the callback function returns zero, qsmm_enum_var_prob terminates enumeration and reports success. If the callback function returns a negative value, qsmm_enum_var_prob terminates enumeration and reports failure.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

The instruction class set instr_class_set_name does not exist.

QSMM_ERR_TYPE

An entity named instr_class_set_name is not an instruction class set. The entity is an instruction meta-class.

QSMM_ERR_CALLBACK

The callback function reported an error.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following functions to query or set the value of a controlled probability variable.

Function: int qsmm_get_node_var_prob (qsmm_t model, const char *var_name, qsmm_sig_t node, double *valp)

This function retrieves the value of controlled probability variable var_name of a node in a multinode model. The argument node specifies the identifier of the node. If valp is not NULL, the function sets *valp to a retrieved value.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument var_name does not contain a valid name for a probability variable.

QSMM_ERR_NOTFOUND

A node with identifier node or a controlled probability variable named var_name does not exist.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_set_node_var_prob (qsmm_t model, const char *var_name, qsmm_sig_t node, double val)

This function sets to val the value of controlled probability variable var_name of a node in a multinode model. The argument node specifies the identifier of the node. However, corresponding profile probabilities in the state transition matrix and/or action emission matrix of the node remain unchanged until calling the function qsmm_node_var_realize (described further on in this subsection).

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument val is not finite or is negative or greater than 1, or the argument var_name does not contain a valid name for a probability variable.

QSMM_ERR_NOTFOUND

A node with identifier node or a controlled probability variable named var_name does not exist.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

After loading an assembler program into a node, its controlled probability variables take on initial values specified in the assembler program. Assignments to controlled probability variables declared in an instruction class set but not defined in the assembler program do not affect profile probabilities in the state transition matrix and action emission matrix.

After assigning values to controlled probability variables by the function qsmm_set_node_var_prob, call the following function to update profile probabilities in the state transition matrix and action emission matrix.

Function: int qsmm_node_var_realize (qsmm_t model, qsmm_sig_t node, int rez1)

This function updates profile probabilities in the state transition matrix and/or action emission matrix of a node in a multinode model according to assignments to controlled probability variables of the node previously made by calling the function qsmm_set_node_var_prob and clears the queue of pending updates. The argument node specifies the identifier of the node. The argument rez1 is for future use and must be equal to 0.

For affected action choice states, the function updates the field nsig_ctrl and, possibly, the field sig_cycle_next in the structure qsmm_state_s. For affected cycle types, the function updates the field profile in the structure qsmm_cycle_s.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_PSUMGT1

The sum of probabilities of case instructions in a choice instruction block would exceed 1.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_PROFSRCP

A node with identifier node is a probability profile source for other nodes. See Memory Efficient Cloning the Probability Profile, for more information on this mode.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_PSUMGT1, QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave a node probability profile in inconsistent state. If after removing a reason of an error a repeated call to this function succeeds, the probability profile becomes consistent.


5.8.3 Output Variables

The purpose of output probability variables is to retrieve probabilities learned while executing or training a node. You do not register variables of this kind in an instruction class set. The function qsmm_node_asm called with the QSMM_ASM_VAR_OUT flag automatically collects information on output probability variables in a memory representation of an assembler program while loading it into a node. An output probability variable can be a controlled probability variable.

Not every probability variable in an assembler program becomes an output probability variable. The first restriction is that the variable must occur in only one jprob or case instruction. The second restriction is that the variable must have unambiguous context. If a probability variable violates at least one of the two restrictions, but the function qsmm_reg_var_prob or macro QSMM_REG_VAR_PROB has registered it as a controlled probability variable, it becomes only a controlled probability variable. If qsmm_node_asm receives the QSMM_ASM_VAR_AUX flag, and a probability variable violates at least one of the two restrictions and is not a controlled probability variable, qsmm_node_asm treats the probability variable as an auxiliary variable. If qsmm_node_asm does not receive QSMM_ASM_VAR_AUX, and a probability variable violates at least one of the two restrictions and is not a controlled probability variable, qsmm_node_asm reports an error.

Every output probability variable corresponds to either the state transition matrix or action emission matrix. The enumeration described below represents a matrix type.

Enumeration: qsmm_mat_e

This enumeration specifies a matrix type. The enumeration contains the following elements.

QSMM_MAT_GOTO

The state transition matrix.

QSMM_MAT_ACTION

The action emission matrix.

QSMM_MAT_COUNT

The number of supported matrix types.

Use the function described below to get the type of a matrix corresponding to an output probability variable.

Function: int qsmm_get_node_var_prob_mat (qsmm_t model, const char *var_name, qsmm_sig_t node, enum qsmm_mat_e *mat_p)

This function retrieves the type of a matrix corresponding to output probability variable var_name of a node of a multinode model. The argument node specifies the identifier of the node. If mat_p is not NULL, the function sets *mat_p to a retrieved type.

If the node uses a source probability profile provided by another node, the function retrieves matrix type of the output probability variable of the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node or an output probability variable named var_name does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

An output probability variable can correspond to multiple cells of a state transition matrix. The following fragment of an assembler program illustrates this situation.

        stt     "s0"
        test                    ; user instruction with multiple
                                ; outcomes (e.g. 3)
        jprob   var0, L2
        stt     "s1"
        ...
L2:     stt     "s2"

The above assembler program fragment does not condition on specific outcomes of ‘test’ instruction (i.e. handles them in the same way). The state transition matrix has rows for all three outcomes of the instruction and columns for the states ‘s0’, ‘s1’, and ‘s2’. This state transition matrix fragment is in Figure 5.1. There ν  denotes state transition frequency, and pp denotes profile probability.

state transition matrix fragment with multiple cells for a jprob instruction

Figure 5.1: state transition matrix fragment with multiple cells for a jprob instruction

The function qsmm_get_node_var_prob_out described further on in this subsection supports calculating probabilities of QSMM_PROB_PROFILE and QSMM_PROB_FQ types for output probability variables corresponding to individual or multiple cells of state transition matrix and corresponding to individual cells of action emission matrix. That function supports calculating probabilities of QSMM_PROB_AGGR and QSMM_PROB_LEARNED types for output probability variables corresponding to individual cells only.

If an output probability variable corresponds to multiple cells of state transition matrix, profile probabilities in the multiple cells are equal, and qsmm_get_node_var_prob_out returns them as a QSMM_PROB_PROFILE probability. For the above example, qsmm_get_node_var_prob_out returns value var0 as probability QSMM_PROB_PROFILE of the output probability variable ‘var0’. That function does not support calculating probabilities of QSMM_PROB_AGGR and QSMM_PROB_LEARNED types for the output probability variable ‘var0’.

To calculate a QSMM_PROB_FQ probability, qsmm_get_node_var_prob_out takes sums of frequencies of transitions to target states for relative probabilities. For example, to calculate probability QSMM_PROB_FQ of the output probability variable ‘var0’, qsmm_get_node_var_prob_out calculates the sums ν0,11,12,1  and ν0,21,22,2  and takes the ratio 0,21,22,2)/(ν0,11,12,10,21,22,2)  for the probability.

As already mentioned, a probability variable used in multiple jprob and case instructions cannot be an output probability variable. The following assembler program fragment illustrates this situation.

L1:     user    0               ; user instruction
        jprob   var0, L1        ; first occurrence of `var0' variable

L2:     user    1               ; user instruction
        jprob   var0, L2        ; second occurrence of `var0'
                                ; variable; encountering this
                                ; occurrence means that `var0' cannot
                                ; be an output probability variable
        jmp     L1

A probability variable used once but in ambiguous context cannot be an output probability variable too. An output probability variable can have ambiguous context due to the following reasons:

  • it belongs to different contiguous blocks of jprob instructions;
  • it specifies a profile probability for both the state transition matrix and action emission matrix;
  • it is another output probability variable for the same cell of the state transition matrix.

A probability variable belongs to different contiguous blocks of jprob instructions if the blocks have different start addresses. The following assembler program fragment illustrates this situation.

L1:     user    0               ; user instruction
        jprob   0.5, L3         ; beginning of the first block of
                                ; `jprob' instructions

L2:     jprob   var0, L1        ; beginning of the second (singleton)
                                ; block of `jprob' instructions and
                                ; also the second `jprob' instruction
                                ; in the first block

        user    1               ; user instruction

L3:     user    2               ; user instruction
        jmp     L2              ; jump to the second (singleton) block
                                ; of `jprob' instructions

After invoking the ‘user 0’ instruction, the block consisting of ‘jprob 0.5, L3’ and ‘jprob var0, L1’ instructions selects the next instruction to execute. However, after invoking the ‘user 2’ instruction, only the last instruction of that block selects the next instruction to execute. In the first case, the block begins with the ‘jprob 0.5, L3’ instruction. In the second case, the block begins with the ‘jprob var0, L1’ instruction and contains only this instruction. That is, the blocks containing the ‘jprob var0, L1’ instruction have different start addresses, and, therefore, the variable ‘var0’ cannot be an output probability variable.

The following assembler program fragment illustrates the situation when a variable specifies a profile probability for both the state transition matrix and action emission matrix.

        stt

        ; This `choice' instruction block specifies profile
        ; probabilities for the action emission matrix because the
        ; block follows the `stt' instruction.
        ;
        ; This block also specifies profile probabilities for the
        ; state transition matrix because the block is the next
        ; instruction to execute after a user instruction.

L0:     choice
        case    var0, L1
        case    0.2, L2
        end     choice

        user    0               ; user instruction

L1:     user    1               ; user instruction

L2:     user    2               ; user instruction
        jmp     L0              ; jump to the `choice' instruction
                                ; block for selecting a
                                ; state transition

The choice instruction block specifies profile probabilities for the action emission matrix because the stt instruction precedes that block. The block also specifies profile probabilities for the state transition matrix because there is an unconditional jump to that block after the ‘user 2’ instruction. That is, the variable ‘var0’ specifies a profile probability for both matrices and, therefore, cannot be an output probability variable.

The following assembler program fragment illustrates the situation when another probability variable corresponds to the same cell of the state transition matrix.

L0:     user    0               ; user instruction

        choice
        case    var0, L1        ; variable `var0' specifies a
                                ; probability of transition to
                                ; label `L1'

        case    var1, L1        ; variable `var1' specifies another
                                ; probability of transition to
                                ; label `L1'
        end     choice

        user    2               ; user instruction

L1:     user    1               ; user instruction
        jmp     L0

The variables ‘var0’ and ‘var1’ specify profile probabilities of the transition to a state beginning at the location label ‘L1’. That is, ‘var1’ is another variable for a matrix cell holding a profile probability of that transition. Therefore, ‘var1’ cannot be an output probability variable.

Use the following function to get names of output probability variables of a node.

Function: int qsmm_enum_var_prob_out (qsmm_t model, qsmm_sig_t node, qsmm_enum_ent_callback_func_t callback_func, void *paramp)

This function enumerates output probability variables defined in an assembler program loaded into a node of a multinode model. The argument node specifies the identifier of the node.

The process of enumeration is repeated calling a callback function callback_func receiving QSMM_LREF_PROB_VAR_OUT as the type of a local entity reference, the name of an output probability variable as a local entity identifier, and a user parameter paramp. See Enumerating Entities, for the description of callback function type.

If the callback function returns a positive value, qsmm_enum_var_prob_out continues enumeration. If the callback function returns zero, qsmm_enum_var_prob_out terminates enumeration and reports success. If the callback function returns a negative value, qsmm_enum_var_prob_out terminates enumeration and reports failure.

If the node uses a source probability profile provided by another node, the function enumerates output probability variables of the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

The function qsmm_enum_var_prob_out does not enumerate output probabilities arrays of a node. See Output Arrays, for an example program that enumerates the arrays and prints their content.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_CALLBACK

The callback function reported an error.

Use the function described below to retrieve the value of an output probability variable.

Function: int qsmm_get_node_var_prob_out (qsmm_t model, const char *var_name, qsmm_sig_t node, enum qsmm_prob_e prob_type, double *valp)

This function retrieves the value of output probability variable var_name of a node in a multinode model. The argument node specifies the identifier of the node.

The argument prob_type specifies the type of a probability to retrieve. See Emitting an Output Signal, for the description of elements of qsmm_prob_e enumeration.

If the node uses a source probability profile provided by another node, the function obtains information how to calculate an output probability variable value from the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

If the function is able to retrieve the value of the output probability variable, the function sets *valp to that value (if valp is not NULL) and returns 2. If prob_type is QSMM_PROB_AGGR or QSMM_PROB_LEARNED, and the output probability variable corresponds to multiple cells of state transition matrix, the function sets *valp to −2 (if valp is not NULL) and returns 1. If var_name is a controlled or auxiliary probability variable that occurs more than once in an assembler program loaded into the node or has ambiguous context in the assembler program, the function sets *valp to −1 (if valp is not NULL) and returns 0.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument prob_type is invalid.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist, or the assembler program does not define a probability variable named var_name.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the model instance in inconsistent state if the environment state identification engine or instruction emitting engine is a large actor. If after removing a reason of an error a repeated call to this function succeeds, the model instance state becomes consistent.

You can retrieve output probabilities for jprob instructions via output probability variables declared as data labels of jprob instructions or via output probability variables specified in the first argument of jprob instructions. You can retrieve output probabilities for case instructions in choice instruction blocks via output probability variables declared as data labels of case instructions, via output probability variables specified in the first argument of case instructions, or via output probabilities arrays referred to by data labels assigned to choice instruction blocks. Use the function qsmm_get_node_array_prob_out described in Output Arrays to retrieve an output probabilities array for a choice instruction block.

Fetching the value of an output probability variable requires calculating relative probabilities of all choice alternatives that include an alternative for the output probability variable. Putting calculated probabilities of all choice alternatives in a cache speeds up fetching values of output probability variables for other choice alternatives later. Along with the cache of calculated probabilities of choice alternatives, a node keeps a cache of calculated values of output probability variables. To free memory, you can clear both caches by the function qsmm_node_var_out_forget described further on in this subsection.

QSMM supports fetching aggregate statistics on cycle types for output probability variables and elements of output probabilities arrays. The statistics are aggregate in the sense that if an output probability variable or an element of an output probabilities array corresponds to multiple cells of state transition matrix, the statistics includes statistics on cycle types in all cells. If an output probability variable or an element of an output probabilities array corresponds to the action emission matrix, aggregate statistics are simply statistics on a cycle type in an individual cell.

Use the function described below to fetch aggregate statistics on cycle types associated with an output probability variable. Use the function qsmm_get_node_array_prob_cycle described in Output Arrays to fetch aggregate statistics on cycle types associated with an element of an output probabilities array.

Function: int qsmm_get_node_var_prob_cycle (qsmm_t model, const char *var_name, qsmm_sig_t node, struct qsmm_cycle_s *cycle_p, struct qsmm_cspval_s *cspval_p)

This function retrieves aggregate statistics on cycle types for output probability variable var_name of a node of a multinode model. The argument node specifies the identifier of the node. If cycle_p is not NULL, the function sets *cycle_p to aggregate statistics on the cycle types. If cspval_p is not NULL, the function sets the elements of cspval_p array to aggregate statistics on cycle-summed value types for the cycle types. See Structures for Accessing Storage, for descriptions of qsmm_cycle_s and qsmm_cspval_s structures.

If cspval_p is not NULL, and the output probability variable corresponds to the state transition matrix, the array cspval_p must be capable of holding the number of elements equal to the sum of values returned by the functions qsmm_get_actor_nspur and qsmm_get_actor_ntime for the environment state identification engine. If cspval_p is not NULL, and the output probability variable corresponds to the action emission matrix, the array cspval_p must be capable of holding the number of elements equal to the sum of values returned by qsmm_get_actor_nspur and qsmm_get_actor_ntime for the instruction emitting engine. The function qsmm_get_node_var_prob_mat described earlier in this subsection retrieves the type of a matrix corresponding to an output probability variable.

The aggregate statistics composes from statistics on individual cycle types in the following way. The fields fq and period_sum_d of *cycle_p are equal to their sums for all cycle types associated with the output probability variable. The field cycle_p->profile is equal to that field for the last cycle type associated with the output probability variable, as all cycle types have the same value of profile field. The fields delta_sum in the elements of cspval_p array are sums of corresponding fields for all cycle types associated with the output probability variable.

If the node uses a source probability profile provided by another node, the function obtains information how to calculate aggregate statistics from the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

On success, the function returns a non-negative number of cycle types making up the aggregate statistics. If the number is greater than INT_MAX, the function returns INT_MAX. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node or an output probability variable named var_name does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The function qsmm_get_node_var_prob_out stores all values of output probability variables calculated for a node in a cache within the node. The functions qsmm_node_call_default (see Calling a Node), qsmm_node_unload (see Unloading the Probability Profile), and qsmm_engine_destroy (see Creating the Model Instance) and the function qsmm_node_disasm called to disassemble a node assembled with the QSMM_ASM_TEMPLATE flag automatically clear this cache along with the cache of calculated probabilities of choice alternatives mentioned earlier. To free memory, you can clear both caches by calling the following function.

Function: int qsmm_node_var_out_forget (qsmm_t model, qsmm_sig_t node)

This function clears a cache of calculated probabilities of output probability variables and a cache of calculated probabilities of choice alternatives both stored in a node of a multinode model. The argument node specifies the identifier of the node. The function qsmm_get_node_var_prob_out uses both caches to speed up retrieving output probability variables of the node. The function qsmm_get_node_array_prob_out uses the second cache to speed up retrieving output probabilities arrays of the node.

On success, the function returns a non-negative value. If a node with identifier node does not exist, the function returns negative error code QSMM_ERR_NOTFOUND.


5.8.4 Output Arrays

A data label assigned to a choice instruction block refers to an output probabilities array for the block. A choice instruction block might look like this:

ARR     choice
        case    0.15, L1
        case    0.05, L2
        case    0.10, L3
        case    0.20, L4
        end     choice

This example defines the output probabilities array ‘ARR’ with four elements corresponding to case instructions in the choice instruction block. An element at index 0 is for the ‘case 0.15, L1’ instruction, and an element at index 3 is for the ‘case 0.20, L4’ instruction.

An output probabilities array corresponds to either the state transition matrix or action emission matrix. Use the function described below to get a matrix type.

Function: int qsmm_get_node_array_prob_mat (qsmm_t model, const char *label, qsmm_sig_t node, enum qsmm_mat_e *mat_p)

This function retrieves the type of a matrix for an output probabilities array of a node of a multinode model. The argument node specifies the identifier of the node. A data label assigned to a choice instruction block in an assembler program loaded into the node identifies the array. If mat_p is not NULL, the function sets *mat_p to a retrieved type. See Output Variables, for the description of elements of qsmm_mat_e enumeration.

If the node uses a source probability profile provided by another node, the function retrieves matrix type of the output probabilities array of the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node or an output probabilities array label does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the function described below to get a segment of an output probabilities array.

Function: int qsmm_get_node_array_prob_out (qsmm_t model, const char *label, qsmm_sig_t node, size_t from, size_t to, enum qsmm_prob_e prob_type, double *prob_p)

This function retrieves a segment of an output probabilities array of a node in a multinode model. The argument node specifies the identifier of the node. A data label assigned to a choice instruction block in an assembler program loaded into the node identifies the array. If prob_p is not NULL, the function copies output probabilities from the array to a buffer prob_p starting at offset 0.

The argument prob_type specifies the type of probabilities to retrieve. See Emitting an Output Signal, for the description of elements of qsmm_prob_e enumeration.

The arguments from and to specify the index of the first element and the index of the last element (exclusive) for an array segment to retrieve. If to is 0, the function uses array length as the index of the last element. The number of elements copied to prob_p is equal to the index of the last element (exclusive) minus from.

A special element of an output probabilities array at index equal to array length corresponds to a choice alternative beneath the choice instruction block. The choice alternative receives control if none of case instructions in the choice instruction block transferred control elsewhere. To retrieve the special element, specify to equal to array length plus 1.

If the node uses a source probability profile provided by another node, the function obtains information how to calculate the array elements from the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

If this function is able to retrieve an array segment, the function returns 2. If prob_type is QSMM_PROB_AGGR or QSMM_PROB_LEARNED, and each array element corresponds to multiple cells of state transition matrix, the function retrieves −2 as the value of each array element and returns 1. If an output probabilities array corresponds to both the state transition matrix and action emission matrix, the function retrieves −1 as the value of each array element and returns 0.

On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument prob_type is invalid, or from is greater than or equal to the index of the last element, or to is greater than array length plus 1.

QSMM_ERR_NOTFOUND

A node with identifier node or an output probabilities array label does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_CALLBACK

A helper function for computing the relative probability of an output signal reported an error by returning NaN. The function qsmm_actor_calc_action_prob calls the helper function.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the model instance in inconsistent state if the environment state identification engine or instruction emitting engine is a large actor. If after removing a reason of an error a repeated call to this function succeeds, the model instance state becomes consistent.

When calculating a segment of an output probabilities array of a node, the function qsmm_get_node_array_prob_out stores in a cache within the node calculated probabilities of all choice alternatives for the output probabilities array. The cache speeds up retrieving the elements of the output probabilities array later. Call the function qsmm_node_var_out_forget to forcibly clear the cache. See Output Variables, for more information on the cache and functions that clear it automatically.

Use the function described below to fetch aggregate statistics on cycle types associated with an element of an output probabilities array. See Output Variables, for the description of a counterpart function fetching aggregate statistics on cycle types associated with an output probability variable and for additional information on the concept of aggregate statistics.

Function: int qsmm_get_node_array_prob_cycle (qsmm_t model, const char *label, qsmm_sig_t node, size_t offs, struct qsmm_cycle_s *cycle_p, struct qsmm_cspval_s *cspval_p)

This function retrieves aggregate statistics on cycle types for an element of an output probabilities array of a node in a multinode model. The argument node specifies the identifier of the node. A location label assigned to a choice instruction block in an assembler program loaded into the node identifies the array.

The argument offs specifies the index of the array element. A special element of an output probabilities array at index equal to array length corresponds to a choice alternative beneath the choice instruction block. The choice alternative receives control if none of case instructions in the choice instruction block transferred control elsewhere.

If cycle_p is not NULL, the function sets *cycle_p to aggregate statistics on the cycle types. If cspval_p is not NULL, the function sets the elements of *cspval_p array to aggregate statistics on cycle-summed value types for the cycle types. See Structures for Accessing Storage, for descriptions of qsmm_cycle_s and qsmm_cspval_s structures.

If cspval_p is not NULL, and the output probabilities array corresponds to the state transition matrix, the array cspval_p must be capable of holding the number of elements equal to the sum of values returned by the functions qsmm_get_actor_nspur and qsmm_get_actor_ntime for the environment state identification engine. If cspval_p is not NULL, and the output probabilities array corresponds to the action emission matrix, the array cspval_p must be capable of holding the number of elements equal to the sum of values returned by qsmm_get_actor_nspur and qsmm_get_actor_ntime for the instruction emitting engine. The function qsmm_get_node_array_prob_mat described earlier in this subsection retrieves the type of a matrix corresponding to an output probabilities array.

The aggregate statistics composes from statistics on individual cycle types in the following way. The fields fq and period_sum_d of *cycle_p are equal to their sums for all cycle types associated with the element of the output probabilities array. The field cycle_p->profile is equal to that field for the last cycle type associated with the element of the output probabilities array, as all cycle types have the same value of profile field. The fields delta_sum in the elements of cspval_p array are sums of corresponding fields for all cycle types associated with the element of the output probabilities array.

If the node uses a source probability profile provided by another node, the function obtains information how to calculate aggregate statistics from the latter node. See Memory Efficient Cloning the Probability Profile, for a detailed description of this mode.

On success, the function returns a non-negative number of cycle types making up the aggregate statistics. If the number is greater than INT_MAX, the function returns INT_MAX. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument offs is greater than the length of the output probabilities array.

QSMM_ERR_NOTFOUND

A node with identifier node or an output probabilities array label does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

A node with identifier node does not have a probability profile specified.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

To dump contents of all output probabilities arrays defined in an assembler program, consider only instructions with the type QSMM_INSTR_CHOICE. Use the function qsmm_get_instr_type to obtain the type of an assembler instruction by its handle. If an instruction with the type QSMM_INSTR_CHOICE has a data label assigned, the instruction has an associated output probabilities array. The call qsmm_get_instr_label(instr,-1), where instr is an instruction handle, returns a data label identifying the output probabilities array. If that call returns NULL, the instruction does not have a data label assigned and, therefore, does not have an associated output probabilities array. The length of an associated output probabilities array is equal to the return value of qsmm_get_instr_nnested function minus 1, as the last nested instruction is the ‘end choice’ instruction.

Below there is an example function that dumps contents of all output probabilities arrays of a node containing an assembler program prg. The function returns 0 on success or −1 on out of memory error.

#include <stdlib.h>
#include <qsmm/qsmm.h>

static int
dump_arr_prob_out(
    qsmm_t qsmm,
    qsmm_sig_t node,
    qsmm_prg_t prg,
    enum qsmm_prob_e prob_type
) {
    int result=-1;
    double *probp=0;
    size_t prob_allo=0;
    const size_t ninstr=qsmm_get_prg_ninstr(prg);
    for (size_t iinstr=0; iinstr<ninstr; iinstr++) {
        const qsmm_instr_t instr=qsmm_get_prg_instr(prg,iinstr);
        const char *const array_name_p=qsmm_get_instr_label(instr,-1);
        if (!array_name_p) continue;
        if (qsmm_get_instr_type(instr)!=QSMM_INSTR_CHOICE) continue;
        const size_t nprob=qsmm_get_instr_nnested(instr)-1;
        if (prob_allo<nprob) {
            double *const newp=realloc(probp,nprob*sizeof(*newp));
            if (!newp) goto Exit;
            prob_allo=nprob;
            probp=newp;
        }
        qsmm_get_node_array_prob_out(qsmm, array_name_p, node, 0, nprob,
                                     prob_type, probp);
        for (size_t iprob=0; iprob<nprob; iprob++)
            printf("%s[%zu]=%.15E\n",array_name_p,iprob,probp[iprob]);
    }
    result=0;

Exit:
    free(probp);
    return result;
}

5.8.5 Auxiliary Variables

Auxiliary probability variables act as constants. A controlled or output probability variable can never simultaneously be an auxiliary probability variable. The function qsmm_node_asm replaces the name of an auxiliary probability variable specified in the first argument of jprob and case instructions with probability specified in the first argument of a prob, jprob, or case instruction declaring the variable using a data label earlier in a procedure or plain assembler program. You cannot access auxiliary probability variables after loading an assembler program into a node.

You pass the QSMM_ASM_VAR_AUX flag to qsmm_node_asm to load an assembler program containing auxiliary probability variables. An occurrence of a probability variable in an assembler program is valid if the probability variable is a controlled or output probability variable, or if qsmm_node_asm received the QSMM_ASM_VAR_AUX flag. Note that you first register controlled probability variables in an instruction class set, and you pass the QSMM_ASM_VAR_OUT flag to qsmm_node_asm to collect information on output probability variables.


5.9 Cloning the Probability Profile

To load the same probability profile into multiple nodes of a multinode model, you can load an assembler program into one node and copy its probability profile to other nodes—clone a probability profile. Cloning a probability profile from a node to other nodes is faster than loading the same assembler program into them.

Use the function described below to clone a probability profile.

Function: int qsmm_node_profile_clone (qsmm_t model, qsmm_sig_t node_from, qsmm_sig_t node_to, unsigned int flags)

This function copies a probability profile from a node of a multinode model to another node of the model. The argument node_from specifies the identifier of a source node. The argument node_to specifies the identifier of a destination node.

The function clears event history statistics collected for the destination node. If it already has a probability profile loaded, the function first unloads the profile from the node along with additional information the function can copy (see the description of flags argument below). To clear event history statistics and unload the profile, this function calls the function qsmm_node_unload described in Unloading the Probability Profile.

The function qsmm_node_profile_clone cannot copy probability profiles manually written to storage without prior calling the function qsmm_node_asm.

The argument flags is a bitmask specifying the types of information to copy from the source node to the destination node along with the probability profile. The following macros specify the bits of the bitmask taken into account.

Macro: QSMM_NODE_CLONE_VARS

Copy definitions of controlled and output probability variables and arrays. This copying makes it possible to modify controlled probability variables of the destination node and to retrieve its output probability variables and arrays, as you can modify and retrieve them for the source node. Before copying definitions of controlled probability variables, this function calls the function qsmm_node_var_realize for the source node if it has uncommitted assignments to controlled probability variables.

Macro: QSMM_NODE_CLONE_STATE_NAMES

Copy names assigned to node states by arguments of stt instructions. The functions qsmm_get_node_state_name and qsmm_get_node_state_by_name can retrieve this information from the destination node. The function qsmm_node_disasm can use this information when disassembling the destination node. The function qsmm_mat_goto_dump_v2 uses this information when dumping the state transition matrix of that node. The function qsmm_mat_action_dump_v2 uses this information when dumping the action emission matrix of that node.

Macro: QSMM_NODE_CLONE_TEMPLATE

If the source node has an associated assembler program template, copy the template. The function qsmm_node_disasm uses the template when disassembling the destination node.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument node_from is equal to the argument node_to.

QSMM_ERR_NOTFOUND

The source or destination node does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

The source node does not have a probability profile specified.

QSMM_ERR_PROFSRCU

The source node is a user of a source probability profile provided by another node.

QSMM_ERR_PROFSRCP

One of the following conditions is true:

  • destination node is a probability profile source for other nodes;
  • on passing QSMM_NODE_CLONE_VARS, the source node had uncommitted assignments to controlled probability variables, so qsmm_node_profile_clone called the function qsmm_node_var_realize to commit them, and the latter function has failed because that node is a probability profile source for other nodes.

This error can leave the probability profile of the destination node in inconsistent state. If after removing a reason of the error a repeated call to this function succeeds, the probability profile becomes consistent.

QSMM_ERR_NOEQCLAS

The instruction class set of the source node and the instruction class set of the destination node are different.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_PSUMGT1

On passing QSMM_NODE_CLONE_VARS, the source node had uncommitted assignments to controlled probability variables, so qsmm_node_profile_clone called the function qsmm_node_var_realize to commit them, and the latter function has failed because the sum of probabilities of case instructions in a choice instruction block would exceed 1.

This error can leave the probability profile of the source node in inconsistent state. If after removing a reason of the error a repeated call to qsmm_node_profile_clone succeeds, the probability profile becomes consistent.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the probability profile of the source or destination node in inconsistent state. If after removing a reason of an error a repeated call to this function succeeds, the probability profile becomes consistent.


5.10 Memory Efficient Cloning the Probability Profile

QSMM supports deferred copying a probability profile from a source node to a destination node, where a copying operation itself only sets a correspondence between the two nodes: the source node becomes a probability profile source, and the destination node becomes a probability profile user. A node can be a probability profile source for multiple other nodes. Storage redirection functions described in Specifying Redirection Functions provide read-only access for the destination node to a probability profile held in the source node.

The deferred copying operation provides copy-on-write behavior for instances of qsmm_state_s and qsmm_cycle_s structures described in Structures for Accessing Storage. The instances hold a probability profile along with statistics on the event history. The first operation of writing statistics to such an instance for the destination node causes allocating the instance and copying there a piece of information on the probability profile from the source node.

You can change values of controlled probability variables for the destination node in the normal way. An assembler program loaded into the source node provides information on how to update the state transition matrix and action emission matrix of the destination node when changing its values of controlled probability variables. Updating the state transition matrix and action emission matrix causes allocating instances of qsmm_state_s and qsmm_cycle_s structures for the destination node if they do not yet exist.

The following information held in a source node becomes automatically available for a destination node:

  • Information on output probability variables and arrays collected when loading an assembler program into the source node. The functions qsmm_get_node_var_prob_out, qsmm_get_node_array_prob_out, qsmm_get_node_var_prob_cycle, qsmm_get_node_array_prob_cycle, qsmm_get_node_var_prob_mat, qsmm_get_node_array_prob_mat, and qsmm_enum_var_prob_out called for the destination node use this information.
  • Names assigned to the states of an assembler program loaded into the source node. The functions qsmm_get_node_state_name and qsmm_get_node_state_by_name called for the destination node retrieve this information. The function qsmm_node_disasm called for the destination node can use this information. The functions qsmm_mat_goto_dump_v2 and qsmm_mat_action_dump_v2 called for the destination node use this information.
  • An assembler program template associated with the source node. The function qsmm_node_disasm called to disassemble the destination node automatically applies the template.

You cannot perform the following operations on a node acting as a probability profile source for other nodes:

  • loading an assembler program into the node by the function qsmm_node_asm;
  • copying a probability profile to the node by the function qsmm_node_profile_clone;
  • setting the node as a user of a probability profile provided by another node using the function qsmm_set_node_profile_source;
  • unloading a probability profile from the node by the function qsmm_node_unload;
  • destroying the node by the function qsmm_node_destroy;
  • committing assignments to probability variables of the node by the function qsmm_node_var_realize.

You cannot perform the following operations on a node acting as a user of a probability profile provided by another node:

  • setting the node as a probability profile source for other nodes;
  • cloning a probability profile from the node to another node by the function qsmm_node_profile_clone.

When disassembling a node acting as a probability profile user or dumping its state transition matrix or action emission matrix, keep in mind that a set of probabilities of QSMM_PROB_PROFILE type can be incomplete for the node, as some instances of qsmm_state_s structure from a source node might not yet be available for the destination node. Therefore, avoid calculating probabilities of QSMM_PROB_PROFILE type for a node acting as a probability profile user.

Using the deferred copying mechanism for some or all nodes of a multinode model slows down all access operations to storage used by the multinode model approximately twice (even for other nodes).

Use the following function to set a correspondence between two nodes of a multinode model where one node becomes a probability profile source and the other node becomes a probability profile user.

Function: int qsmm_set_node_profile_source (qsmm_t model, qsmm_sig_t node_from, qsmm_sig_t node_to, int rez1)

This function sets a node of a multinode model as the source of a probability profile and sets another node as a user of the probability profile. The argument node_from specifies the identifier of the source (former) node, and the argument node_to specifies the identifier of the destination (latter) node. The argument rez1 is for future use and must be equal to 0.

The function clears event history statistics collected for the destination node. If it has a probability profile loaded, the function unloads the profile along with dependent information. To clear event history statistics and unload the profile, this function calls the function qsmm_node_unload described in Unloading the Probability Profile.

If the source node has uncommitted assignments to controlled probability variables, qsmm_set_node_profile_source calls the function qsmm_node_var_realize to commit them.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument node_from is equal to the argument node_to.

QSMM_ERR_NOTFOUND

The source or destination node does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_NOPROF

The source node does not have a probability profile specified.

QSMM_ERR_PROFSRCU

The source node is a user of a source probability profile provided by another node.

QSMM_ERR_PROFSRCP

One of the following conditions is true:

  • destination node is a probability profile source for other nodes;
  • source node had uncommitted assignments to controlled probability variables, so qsmm_set_node_profile_source called qsmm_node_var_realize to commit them, and the latter function has failed because the node is a probability profile source for other nodes.

This error can leave the probability profile of the destination node in inconsistent state. If after removing a reason of the error a repeated call to this function succeeds, the probability profile becomes consistent.

QSMM_ERR_NOEQCLAS

The instruction class set of the source node and the instruction class set of the destination node are different.

QSMM_ERR_NOTSUP

The multinode model has positive length of look-ahead signal segment.

QSMM_ERR_PSUMGT1

The source node had uncommitted assignments to controlled probability variables, so qsmm_set_node_profile_source called qsmm_node_var_realize to commit them, and the latter function has failed because the sum of probabilities of case instructions in a choice instruction block would exceed 1.

This error can leave the probability profile of the source node in inconsistent state. If after removing a reason of the error a repeated call to qsmm_set_node_profile_source succeeds, the probability profile becomes consistent.

QSMM_ERR_STORAGE

A Storage API function reported storage failure.

QSMM_ERR_STATS

Inconsistent statistics on an action choice state or cycle type detected.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Errors QSMM_ERR_STORAGE, QSMM_ERR_STATS, QSMM_ERR_ILSEQ, and QSMM_ERR_NOMEM can leave the probability profile of the source or destination node in inconsistent state. If after removing a reason of an error a repeated call to this function succeeds, the probability profile becomes consistent.

The function qsmm_node_unload described in the next section can break off a correspondence between a node acting as a probability profile source and a node acting as a probability profile user.


5.11 Unloading the Probability Profile

Use the function described below to unload statistics and a probability profile from a node.

Function: int qsmm_node_unload (qsmm_t model, qsmm_sig_t node)

This function performs the following operations on a node of a multinode model:

  • if the node is a probability profile user, break off its correspondence with a node acting as a probability profile source;
  • unload statistics collected on the event history for the node;
  • unload the probability profile of the node;
  • if the node has an assembler program loaded, unload information on controlled and output probability variables defined in the assembler program;
  • if the node has an assembler program loaded, unload information about names assigned to the states of the assembler program;
  • unload an assembler program template used for disassembling;
  • destroy the cache of calculated probabilities of output probability variables and the cache of calculated probabilities of choice alternatives.

The argument node specifies the identifier of the node.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOTFOUND

A node with identifier node does not exist.

QSMM_ERR_UNTIMELY

A model instance does not exist.

QSMM_ERR_PROFSRCP

The node is a probability profile source for other nodes. See Memory Efficient Cloning the Probability Profile, for more information on this mode.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Error QSMM_ERR_NOMEM can leave the probability profile of the node or its statistics in inconsistent state. If after removing a reason of the error a repeated call to this function succeeds, the probability profile and statistics become unloaded.


5.12 Using the Assembler Preprocessor

In QSMM, the assembler preprocessor provides the means of encapsulating similar blocks of source code in macros reusable in an assembler program. Macros can define nested control transfer structures and produce unique location labels when expanded. The preprocessor also provides the means of including other files in an assembler source file.

The preprocessor returns a single output buffer with a preprocessed text for an assembler program and all source files it includes. Preprocessed output can contain ‘line’ directives describing locations of preprocessed text fragments in source files. The assembler includes this information in error, warning, and note messages. The preprocessor also merges (quoted) string literals separated by zero or more whitespace characters into a single string literal.

The preprocessor provides only basic features necessary to work with symbols and macros. If you need more sophisticated features to generate the source text of an assembler program, either produce input to the preprocessor using an auxiliary function, program, or script or generate an assembler program that does not require preprocessing by a function, program, or script directly.


5.12.1 Changing Line Number and File Name

Use the ‘line’ directive of the assembler preprocessor to change current line number and, possibly, the logical name of a preprocessed source file tracked by the preprocessor with emitting a corresponding ‘line’ directive to preprocessed output for subsequent interpreting by the assembler. Additionally, the preprocessor uses information changed by the ‘line’ directive when generating error and note messages.

The directive must be on a line of its own (after at least one whitespace character at a line beginning) and must have one of the following formats:

        line    line_number
        line    line_number, file_name

In the first case, the directive changes the logical number of the next line in a current source file to line_number. In the second case, the directive changes the logical number of the next line to line_number and the logical name of a current source file to file_name. The parameter file_name must be a (quoted) string literal.


5.12.2 Including Other Source Files

To include another source file in an assembler source file, use the ‘include’ directive:

        include file_name

The argument file_name specifies a (quoted) absolute or relative path to an included file. The base directory for the relative path is:

  • a directory containing a file with the ‘include’ directive;
  • a base directory specified as a preprocessing parameter if the name of a file with the ‘include’ directive is unknown;
  • a current working directory if there is no base directory specification using a preprocessing parameter.

The directive must be on a line of its own after at least one whitespace character at a line beginning. The directive must not occur within a macro definition. The maximum nesting level of ‘include’ directives is 100.


5.12.3 Defining Symbols

You can use the ‘def’ directive to define or redefine a symbol:

name    def     value

This statement defines or redefines a symbol name to a value. A symbol name must start at the beginning of a line. A symbol value must not contain commas outside of string literals.

There are two possible scopes of a symbol: global and local. Defining a symbol outside of macros makes the symbol global. If a symbol is global one, a ‘def’ directive used for the symbol inside a macro redefines the global symbol to a new value.

Defining a symbol inside a macro makes the symbol local. Macro arguments are also local symbols. Local symbols are not visible outside of macros containing their definitions. If a symbol is local one, a ‘def’ directive used for the symbol inside a macro (containing the symbol definition) redefines the local symbol to a new value.

QSMM 1.19 introduces the ‘ldef’ directive for using inside a macro:

name    ldef    value

This statement defines or redefines a local symbol name to a value even if there exists a global symbol name.

Use the ‘def’ directive for defining or redefining global symbols and use the ‘ldef’ directive for defining or redefining local symbols.

The assembler preprocessor replaces with a symbol value every occurrence of a symbol name as a token in a symbol scope. To concatenate a symbol value with adjacent tokens, prepend and/or append the characters ‘##’ to a symbol name token.

For example, the source text

st      def     01

        choice
        case    a##st##_00, l##st##_00
        case    a##st##_01, l##st##_01
        end     choice

        jmp     l##st##_02

preprocesses to the text

        choice
        case    a01_00, l01_00
        case    a01_01, l01_01
        end     choice

        jmp     l01_02

If a symbol value is not a (quoted) string literal, prepend the character ‘#’ to the symbol name token to convert the symbol value to a string literal. For example, the source text

id       def     5

s##id:   stt     #id

preprocesses to the text

s5:   stt     "5"

The right-hand side of a symbol definition or redefinition can contain symbol names. After expanding the symbol names, the value of the symbol must reduce to either a string literal or other text without string literals, spaces, and commas.

The assembler preprocessor supports the predefined symbol ‘__UNIQUE__’ expanded to the next number from the sequence of natural numbers. You can use that symbol to generate unique location labels in macros.


5.12.4 Defining Macros

A macro definition looks like this:

name    macro   arg1, arg2, ...
        text
        end     macro

or

name    macro   arg1, arg2, ...
        text
name    end     macro

The above code blocks define a macro name with arguments arg1, arg2, ... A macro may have no arguments at all. Names of macro arguments work as the names of local symbols usable within the macro.

If a macro has a long list of arguments, you can split the list into multiple lines. To indicate that a line of a list of arguments continues on the next line, terminate a continued line with a comma after the name of an argument. The following example demonstrates this:

mac1    macro   arg1, arg2, arg3,
                arg4, arg5, arg6,
                arg7, arg8
        ...
mac1    end     macro

You may not define nested macros. However, a macro can expand another macro expanding another macro and so on. The maximum supported nesting level of macro expansions is 65535.

To expand a macro name defined earlier in a source text and use arg1, arg2, … for values of macro arguments, write a line like this:

        name    arg1, arg2, ...

The name of an expanded macro must be on a line of its own. The line must begin with either at least one whitespace character followed by a macro name or a location label definition followed by at least one whitespace character and a macro name.

The assembler preprocessor does not perform substitutions of symbol names with symbol values in names of expanded macros. However, the preprocessor performs such substitutions in values of macro arguments. After substituting, the value of every macro argument must reduce to either a string literal or other text without string literals, spaces, and commas.

If you are expanding a macro using a long list of arguments, you can split the list into multiple lines. To indicate that a line of a list of arguments continues on the next line, terminate a continued line with a comma after the value of an argument. The following example demonstrates this:

        mac1    "alpha", 0.1,
                "beta",  0.2,
                "gamma", 0.3,
                "delta", 0.4

5.12.5 Generating Unique Location Labels

Macros can contain definitions of location labels that must not duplicate when expanding a macro multiple times. To define a number of location labels in local scope of a macro, you can define local symbols for them using the lines of code like these:

lu0     ldef    u##__UNIQUE__
lu1     ldef    u##__UNIQUE__
lu2     ldef    u##__UNIQUE__

The above directives define the symbols lu0, lu1, and lu2 with values that have the form ui, where i is an increasing integer number. When expanding the macro the first time, the symbols lu0, lu1, and lu2 take the values u1, u2, u3 (if there are no definitions of other symbols using the predefined symbol ‘__UNIQUE__’). When expanding the macro the second time, the symbols lu0, lu1, and lu2 take the values u4, u5, u6, and so on. Thus, values of the symbols lu0, lu1, and lu2 are always unique, and you can use them for location labels within macros expanded multiple times. The following example of a macro illustrates this:

emit_ch macro

lu0     ldef    u##__UNIQUE__
lu1     ldef    u##__UNIQUE__
lu2     ldef    u##__UNIQUE__

        choice
        case    0.33, lu0
        case    0.33, lu1
        end     choice

        emit    "A"
        jmp     lu2

lu0:    emit    "B"
        jmp     lu2

lu1:    emit    "C"

lu2:

emit_ch end     macro

This macro emits the character ‘A’, ‘B’, or ‘C’ by the corresponding user instruction emit. You can safely expand the macro an arbitrary number of times—location labels are unique in every expansion. For example, to emit a sequence of two characters, expand the macro twice:

        ...
        emit_ch
        emit_ch
        ...

This sequence of two calls to the macro emit_ch expands to the following source text (for clarity, the text does not contain ‘line’ directives):

        choice
        case    0.33, u1
        case    0.33, u2
        end     choice

        emit    "A"
        jmp     u3

u1:    emit    "B"
        jmp     u3

u2:    emit    "C"

u3:

        choice
        case    0.33, u4
        case    0.33, u5
        end     choice

        emit    "A"
        jmp     u6

u4:    emit    "B"
        jmp     u6

u5:    emit    "C"

u6:

5.12.6 Getting Preprocessed Output

The functions qsmm_parse_asm_source_buf, qsmm_parse_asm_source_stream, and qsmm_parse_asm_source_file described in Parsing an Assembler Program can automatically call the assembler preprocessor to preprocess a source program text if they receive the QSMM_PARSE_ASM_PREPROCESS flag. However, sometimes it might be necessary to obtain a preprocessed source text directly. Use the following functions to accomplish this task.

Function: int qsmm_preprocess_asm_source_buf (const char *in_p, const char *cwd_p, int rez1, void *rez2, void *rez3, qsmm_msglist_t msglist, char **out_pp)
Function: int qsmm_preprocess_asm_source_stream (FILE *filep, const char *cwd_p, int rez1, void *rez2, void *rez3, qsmm_msglist_t msglist, char **out_pp)

The function qsmm_preprocess_asm_source_buf preprocesses a source program text provided via the argument in_p as a string. The function qsmm_preprocess_asm_source_stream preprocesses a source program text read from a stream filep.

If out_pp is not NULL, both functions set *out_pp to an allocated string containing preprocessed output; free by the function free a memory block addressed by *out_pp after use. If the preprocessor produces zero-length output, both functions set *out_pp to NULL.

If msglist is not NULL, both functions add to a message list msglist error and note messages generated while preprocessing the source program text. If cwd_p is not NULL, both functions use a string cwd_p as the name of a current working directory when resolving ‘include’ directives. If cwd_p is NULL, both functions use an actual current working directory when resolving ‘include’ directives. The arguments rez1, rez2, and rez3 are for future use and must be equal to 0.

On success, both functions return a non-negative number of bytes in the preprocessed output or INT_MAX if the number is greater than INT_MAX. If out_pp is not NULL, and the number is greater than 0 and less than INT_MAX, it is the length of a string *out_pp. On failure, both functions return a negative error code. Currently, the functions can return the following error codes.

QSMM_ERR_PRG

The source program text has at least one error. If msglist is not NULL, the message list msglist contains at least one error message.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale, including inability to convert the source program text to a wide string and inability to convert the preprocessed output to a multibyte string.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_preprocess_asm_source_file (const char *fln, int rez1, void *rez2, void *rez3, qsmm_msglist_t msglist, char **out_pp)

This function preprocesses a source program text read from a file fln. If out_pp is not NULL, the function sets *out_pp to an allocated string containing preprocessed output; free by the function free a memory block addressed by *out_pp after use. If the preprocessor produces zero-length output, the function sets *out_pp to NULL.

If msglist is not NULL, the function adds to a message list msglist error and note messages generated while preprocessing the source program text. The arguments rez1, rez2, and rez3 are for future use and must be equal to 0.

On success, the function returns a non-negative number of bytes in the preprocessed output or INT_MAX if the number is greater than INT_MAX. If out_pp is not NULL, and the number is greater than 0 and less than INT_MAX, it is the length of a string *out_pp. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_LIBC

The operating system reported a file access error. The variable errno holds the error code.

QSMM_ERR_PRG

The source program text has at least one error. If msglist is not NULL, the message list msglist contains at least one error message.

QSMM_ERR_ILSEQ

Unable to convert a multibyte string to a wide string or vice versa according to a current locale, including inability to convert the source program text to a wide string and inability to convert the preprocessed output to a multibyte string.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


5.13 Example of Working with an Assembler Program

In the example of working with an assembler program, an agent controlled by the sample program has to find a path to the gold in a labyrinth and then to an exit from the labyrinth. As in the sample program labyr2.c described in Example of Using the Actor API, the C source code contains the picture of a labyrinth encoded using a subset of ASCII characters resembling pseudographics. You can change that picture to test agent behavior for various labyrinth configurations.

To learn a labyrinth configuration, the agent visits the labyrinth the number of times defined by the macro NVISIT. Moving the agent to a cell designated as a labyrinth exit finishes a labyrinth visit.

The picture of a labyrinth cell is in Figure 2.8. See the description of a labyrinth cell and the macros MAX_X, MAX_Y, ENTRY_X and ENTRY_Y around that figure.

The agent does not know its precise location in the labyrinth in default mode of program operation—the agent receives a limited amount of information about a current location. This information includes an indication whether a current cell is an exit from the labyrinth and, if the current cell is not an exit from the labyrinth, the union of the following pieces of information:

  • an indication whether the last move was successful or unsuccessful because of an obstacle;
  • a bitmask of four bits indicating ability to move in the north, east, south, or west direction from a current cell; an obstacle prevents a move;
  • an indication whether the agent has taken the gold during a current labyrinth visit.

The macro NSTATE specifies the number of tracked environment states in default mode of program operation. The sample program prints that number just after its invocation. Defining that macro to a lesser value may result in infinite looping.

After every labyrinth visit, the sample program prints the following information:

  1. The ordinal number of a labyrinth visit.
  2. The number of times the agent found the gold since the beginning of program execution.
  3. The length of the last visiting path.
  4. The length of all traversed visiting paths.
  5. The average amount of gold found per one move in the labyrinth.

In default mode of program operation, the agent visits the labyrinth a number of times without taking the gold until at some point the agent usually “understands” how to take the gold and then finds the gold at almost every labyrinth visit.

At the last labyrinth visit, the sample program switches the terminal to full-screen mode and shows a labyrinth picture. After pressing SPACE, the sample program shows the movements of the agent in the labyrinth and prints current length of visiting path and an indication whether or not the agent took the gold. After the agent finds an exit from the labyrinth, pressing Q turns off full-screen terminal mode and quits the sample program.

You can specify a random seed by the first program argument. If the random seed is non-negative, the agent operates adaptively (normally). If the random seed is negative, the agent operates randomly. You can compare agent behavior and program output for the two modes of program operation.

Additional mode of program operation is the use of a profile assembler program helping the agent to do its job more efficiently. The second program argument turns on the additional mode by passing the name of a file with the profile assembler program.

The file samples/maze.asm in the package distribution installed to $prefix/share/qsmm/samples/maze.asm contains the source text of a profile assembler program for use with labyrinths that have up to 10 cells in width and height. The assembler program actually provides tracking a precise location of the agent in the labyrinth—the agent finds the gold at almost all labyrinth visits. The final visiting path shown in full-screen terminal mode does not have vacillations taking place in default mode of program operation.

The content of that file is below.

        ; RELOCate.
        ;
        ; Analyze the outcome of an `mv' instruction for performing the
        ; next move.
        ;
        ; l_repeat - jump label for repeating an attempt to perform the
        ;            move if the `mv' instruction moved the
        ;            agent to an obstacle.
        ;
        ; new_row  - new row index for the agent if the movement
        ;            was successful.

        ; new_col  - new column index for the agent if the movement
        ;            was successful.

reloc   macro   l_repeat, new_row, new_col

l_g0    def     g0_r##new_row##_c##new_col
l_g1    def     g1_r##new_row##_c##new_col

        joe     0, l_g0
        joe     1, l_g0
        joe     2, l_g0
        joe     3, l_g0
        joe     4, l_g0
        joe     5, l_g0
        joe     6, l_g0
        joe     7, l_g0
        joe     8, l_g0
        joe     9, l_g0
        joe     10, l_g0
        joe     11, l_g0
        joe     12, l_g0
        joe     13, l_g0
        joe     14, l_g0
        joe     15, l_g0
        joe     32, l_g1
        joe     33, l_g1
        joe     34, l_g1
        joe     35, l_g1
        joe     36, l_g1
        joe     37, l_g1
        joe     38, l_g1
        joe     39, l_g1
        joe     40, l_g1
        joe     41, l_g1
        joe     42, l_g1
        joe     43, l_g1
        joe     44, l_g1
        joe     45, l_g1
        joe     46, l_g1
        joe     47, l_g1
        jmp     l_repeat

        end     macro


        ; Select a movement direction and analyze a movement outcome.
        ;
        ; is_gf     - indication whether the agent has found gold:
        ;             1 = has found;
        ;             0 = not yet found.
        ;
        ; row       - current row index for the agent.
        ; col       - current column index for the agent.
        ;
        ; row_north - new row index for the agent if it moves one step in
        ;             the north direction.
        ;
        ; row_south - new row index for the agent if it moves one step in
        ;             the south direction.
        ;
        ; col_west  - new column index for the agent if it moves one step
        ;             in the west direction.
        ;
        ; col_east  - new column index for the agent if it moves one step
        ;             in the east direction.

state   macro   is_gf, row, col,
                row_north, row_south, col_west, col_east

repeat  def     u##__UNIQUE__
m_north def     u##__UNIQUE__
m_east  def     u##__UNIQUE__
m_south def     u##__UNIQUE__

g##is_gf##_r##row##_c##col:
repeat: stt

        choice
        case    0.25, m_north
        case    0.25, m_east
        case    0.25, m_south
        end     choice

        mv      west
        reloc   repeat, row, col_west

m_south:
        mv      south
        reloc   repeat, row_south, col

m_east: mv      east
        reloc   repeat, row, col_east

m_north:
        mv      north
        reloc   repeat, row_north, col

        end     macro


        ; STates for a ROW.
        ;
        ; Movement selection states for a specific agent location row.
        ;
        ; is_gf     - indication whether the agent has found gold:
        ;             1 = has found;
        ;             0 = not yet found.
        ;
        ; row       - current row index for the agent.
        ;
        ; row_north - new row index for the agent if it moves one step in
        ;             the north direction.
        ;
        ; row_south - new row index for the agent if it moves one step in
        ;             the south direction.


strow   macro   is_gf, row, row_north, row_south

        state   is_gf, row, 0, row_north, row_south, 9, 1
        state   is_gf, row, 1, row_north, row_south, 0, 2
        state   is_gf, row, 2, row_north, row_south, 1, 3
        state   is_gf, row, 3, row_north, row_south, 2, 4
        state   is_gf, row, 4, row_north, row_south, 3, 5
        state   is_gf, row, 5, row_north, row_south, 4, 6
        state   is_gf, row, 6, row_north, row_south, 5, 7
        state   is_gf, row, 7, row_north, row_south, 6, 8
        state   is_gf, row, 8, row_north, row_south, 7, 9
        state   is_gf, row, 9, row_north, row_south, 8, 0

        end     macro


        ; STates for all ROWS.
        ;
        ; Movement selection states for all agent location rows.
        ;
        ; is_gf - indication whether the agent has found gold:
        ;         1 = has found;
        ;         0 = not yet found.

strows  macro   is_gf

        strow   is_gf, 0, 9, 1
        strow   is_gf, 1, 0, 2
        strow   is_gf, 2, 1, 3
        strow   is_gf, 3, 2, 4
        strow   is_gf, 4, 3, 5
        strow   is_gf, 5, 4, 6
        strow   is_gf, 6, 5, 7
        strow   is_gf, 7, 6, 8
        strow   is_gf, 8, 7, 9
        strow   is_gf, 9, 8, 0

        end     macro


        ; Generate movement selection states for the case when the agent
        ; has not yet found gold and the case when the agent has
        ; found the gold.

        strows  0
        strows  1

The file samples/maze_asm.c in the package distribution installed to $prefix/share/qsmm/samples/maze_asm.c contains the source code of the sample program. A copy of that source code is below. The command make builds the sample program if the configure script has configured QSMM to use the ncurses library. The command make install installs the binary of the sample program and names the installed binary as ‘qsmm-example-maze-asm’ if the configure script has configured QSMM to install example programs. See the file INSTALL in the root of the package distribution for information on the configure script.

#include <config.h>

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#if defined(HAVE_CURSES_H)
#   include <curses.h>
#elif defined(HAVE_NCURSES_CURSES_H)
#   include <ncurses/curses.h>
#endif

#include <qsmm/qsmm.h>

#define NVISIT  200
#define NSTATE  512
#define MAX_X   8
#define MAX_Y   8
#define ENTRY_X 1
#define ENTRY_Y 8


#define CHK_FAIL(func, ...)                                               \
    do {                                                                  \
        const int rc=func(__VA_ARGS__);                                   \
        if (rc<0) ERREXIT( #func ": %s", qsmm_err_str(rc));               \
    }                                                                     \
    while (0)


#define ERREXIT(fmt, ...)                                                 \
    do {                                                                  \
        fprintf(stderr,fmt "\n", ## __VA_ARGS__);                         \
        goto Exit;                                                        \
    }                                                                     \
    while (0)


enum direct_e {
    DIRECT_NORTH=0,  // move one step up
    DIRECT_EAST =1,  // move one step right
    DIRECT_SOUTH=2,  // move one step down
    DIRECT_WEST =3,  // move one step left
    DIRECT_COUNT     // number of movement directions
};


static char is_gold_found;
static int path_len_pass, n_gold_found=0, path_len_total=0;
static qsmm_prg_t prg_asm=0;
static qsmm_msglist_t msglist=0;


// Get the bitmask of allowed movement directions.

static unsigned char
get_percept(
    const char **picture_pp,
    int xx,
    int yy
) {
    unsigned char result=0;
    const int col=xx*3+1, row=yy*2+1;
    assert(picture_pp[row][col]==' ' && picture_pp[row][col+1]==' ');
    assert((picture_pp[row-1][col]==' ' &&
            picture_pp[row-1][col+1]==' ') ||
           (picture_pp[row-1][col]!=' ' &&
            picture_pp[row-1][col+1]!=' '));
    assert((picture_pp[row+1][col]==' ' &&
            picture_pp[row+1][col+1]==' ') ||
           (picture_pp[row+1][col]!=' ' &&
            picture_pp[row+1][col+1]!=' '));
    if (picture_pp[row-1][col]==' ' && picture_pp[row-1][col+1]==' ')
        result|=1 << DIRECT_NORTH;
    if (picture_pp[row][col+2]==' ') result|=1 << DIRECT_EAST;
    if (picture_pp[row+1][col]==' ' && picture_pp[row+1][col+1]==' ')
        result|=1 << DIRECT_SOUTH;
    if (picture_pp[row][col-1]==' ') result|=1 << DIRECT_WEST;
    return result;
}


// Make a movement in the labyrinth in a specified direction possibly
// showing the movement on the screen.
// Returns: 3 = movement resulted in exiting the labyrinth;
//          2 = movement resulted in taking the gold;
//          1 = movement made successfully;
//          0 = cannot make the movement because a new location cell of the
//              agent is not empty.

static int
opaque_maze(
    enum direct_e direct,
    unsigned char *percept_p
) {
    static const char *picture[]={
        // 0  1  2  3  4  5  6  7  8
        "+-----+--+--#..#--+--------+",
        "|     |  |        |        |",  // 0
        "+--+  |  |  #--#  |  +  +  |",
        "|     |  |     |  |  |  |  |",  // 1
        "|  +--+  |  +--+  +--+  *  *",
        "|        |     |  |     |  |",  // 2
        "+--+  +--+-----+  +--+  *--*",
        "|     |  |        |        |",  // 3
        "|  +--+  +  +  +  |  +--+  |",
        "|           |  |  |     |  |",  // 4
        "|  +--+  +--+  |  |  +--+  |",
        "|  |     |     |  |     |  |",  // 5
        "+--+  +--+--+  +--+-----+  |",
        "|     |  |        |        |",  // 6
        "+--+  |  |  +--+  +--+  +--+",
        "|     |  |     |           |",  // 7
        "|  +--+  |  +--+  +--+  +--+",
        "|        |     |  |        |",  // 8
        "+--+..+--+-----+--+--------+"
    };
    static char is_gf=0;
    static int path_len, visit=0, xx=-1, yy=-1;
    char ss[128];
    int col, row, result=1;
    if (xx<0 || yy<0) {
        if (visit==NVISIT-1) {
            if (!initscr()) exit(2);
            noecho();
            for (row=0; row<=(MAX_Y+1)*2+1; row++)
                mvaddstr(row,0,picture[row]);
            row=(MAX_Y+1)*2+3;
            mvaddstr(row,0,"Press [Space] to start moving");
            while (getch()!=' ') ;
            sprintf(ss,"%64s","");
            mvaddstr(row,0,ss);
        }
        xx=ENTRY_X;
        yy=ENTRY_Y;
        path_len=0;
    }
    assert(xx>=0 && xx<=MAX_X);
    assert(yy>=0 && yy<=MAX_Y);
    unsigned char percept;
    if (get_percept(picture,xx,yy) & (1 << direct)) {
        col=xx*3+1;
        row=yy*2+1;
        switch (direct) {
            case DIRECT_NORTH: yy--; break;
            case DIRECT_EAST:  xx++; break;
            case DIRECT_SOUTH: yy++; break;
            case DIRECT_WEST:  xx--; break;
            case DIRECT_COUNT:       assert(0);
        }
        percept=get_percept(picture,xx,yy);
        path_len++;
        if (visit==NVISIT-1) mvaddstr(row,col,"  ");
        col=xx*3+1;
        row=yy*2+1;
        if (visit==NVISIT-1) {
            const int picture_w=strlen(picture[0]);
            mvaddstr(row,col,"[]");
            sprintf(ss," Gold found: %d",is_gf);
            mvaddstr(1,picture_w+2,ss);
            sprintf(ss,"Path length: %d",path_len);
            mvaddstr(3,picture_w+2,ss);
            move((MAX_Y+1)*2+3,0);
            refresh();
            usleep(125000);
        }
        if (picture[row-1][col-1]=='*' && picture[row-1][col+2]=='*' &&
            picture[row+1][col-1]=='*' && picture[row+1][col+2]=='*') {
            if (!is_gf) {
                is_gf=1;
                result=2;
            }
        }
        else if (picture[row-1][col-1]=='#' && picture[row-1][col+2]=='#' &&
                 picture[row+1][col-1]=='#' && picture[row+1][col+2]=='#') {
            is_gf=0;
            result=3;
            xx=-1;
            yy=-1;
            if (visit==NVISIT-1) {
                row=(MAX_Y+1)*2+3;
                mvaddstr(row,0,"Press [Q] to exit");
                while (1) {
                    int key=getch();
                    if (key=='q' || key=='Q') break;
                }
                endwin();
            }
            else visit++;
        }
    }
    else {
        percept=get_percept(picture,xx,yy)+16;
        result=0;
    }
    if (is_gf) percept+=32;
    if (percept_p) *percept_p=percept;
    return result;
}


static QSMM_INSTR_META_CLASS(mv) {
    int result=-1;
    enum direct_e direct=0;
    if (QSMM_HAS_INSTR_CLASS(mehcall->evt))
        qsmm_get_mehcall_instr_param_bin(mehcall,sizeof(direct),0,&direct);
    switch (mehcall->evt) {
        case QSMM_EVT_INSTR_CLASS_INIT: {
            const char *ccp=0;
            switch (direct) {
                case DIRECT_NORTH: ccp="north"; break;
                case DIRECT_EAST:  ccp="east";  break;
                case DIRECT_SOUTH: ccp="south"; break;
                case DIRECT_WEST:  ccp="west";  break;
                case DIRECT_COUNT: assert(0);
            }
            assert(ccp);
            qsmm_set_mehcall_instr_param_f(mehcall,"%s",ccp);
            qsmm_set_mehcall_noutcome(mehcall,64);
            break;
        }
        case QSMM_EVT_ACTIVATE: {
            unsigned char percept=0;
            const int rc=opaque_maze(direct,&percept);
            const qsmm_actpair_t actpair=qsmm_get_actpair(qsmm);
            const qsmm_actor_t actor_env=
                qsmm_get_actpair_actor(actpair,QSMM_ENGINE_ENV),
                actor_iee=qsmm_get_actpair_actor(actpair,QSMM_ENGINE_IEE);
            CHK_FAIL(qsmm_actor_time_delta_v2,actor_env,0,0,1);
            CHK_FAIL(qsmm_actor_time_delta_v2,actor_iee,0,0,1);
            switch (rc) {
                case 0:
                case 1:
                    break;
                case 2:
                    is_gold_found=1;
                    n_gold_found++;
                    break;
                case 3:
                    if (is_gold_found) {
                        CHK_FAIL(qsmm_actor_spur_delta,actor_env,1,1);
                        CHK_FAIL(qsmm_actor_spur_delta,actor_iee,0,1);
                    }
                    qsmm_set_mehcall_return(mehcall,1);
                    break;
                default:
                    assert(0);
            }
            if (rc!=3) {
                if (rc) {
                    path_len_pass++;
                    path_len_total++;
                }
                qsmm_set_mehcall_outcome(mehcall,percept);
            }
            break;
        }
    }
    result=0;

Exit:
    return result;
}


// Find a path to gold in the labyrinth and then to its exit possibly
// using a node probability profile specified by an assembler program.

int
main(
    int argc,
    char **argv
) {
    int seed=0, exit_code=1;
    qsmm_t qsmm=0;
    qsmm_msglist_t msglist_dump=0;
    if (argc>2) {
        CHK_FAIL(qsmm_msglist_create,&msglist);
        CHK_FAIL(qsmm_parse_asm_source_file, argv[2],
                 QSMM_PARSE_ASM_PREPROCESS, 0, 0, msglist, &prg_asm);
    }
    struct qsmm_desc_s desc;
    memset(&desc,0,sizeof(desc));
    desc.dont_use_instr_class_weights=1;
    desc.stack_sz_max=1;
    desc.compat=3;
    desc.nnode_max=1;
    struct qsmm_engine_desc_s *const engine_desc_p=desc.engine_desc;
    engine_desc_p[QSMM_ENGINE_ENV].nspur=2;
    engine_desc_p[QSMM_ENGINE_ENV].ntime=1;
    engine_desc_p[QSMM_ENGINE_IEE].nspur=1;
    engine_desc_p[QSMM_ENGINE_IEE].ntime=1;
    struct qsmm_actor_large_desc_s large_desc;
    memset(&large_desc,0,sizeof(large_desc));
    large_desc.tree_arity=2;
    engine_desc_p[QSMM_ENGINE_ENV].large_desc_p=&large_desc;
    engine_desc_p[QSMM_ENGINE_IEE].large_desc_p=&large_desc;
    CHK_FAIL(qsmm_create,&desc,&qsmm);
    QSMM_REG_INSTR_META_CLASS_PARAM(qsmm,mv,0);
    qsmm_reg_instr_class_set(qsmm,"walker",0,0);
    for (enum direct_e direct=0; direct<DIRECT_COUNT; direct++)
        qsmm_reg_instr_class_v2(qsmm, "mv", "walker", 0,
                                sizeof(direct), &direct, 0);
    if (!prg_asm) {
        printf("nstate %d\n",NSTATE);
        qsmm_set_nstate_max(qsmm,"walker",NSTATE);
    }
    qsmm_sig_t node=0;
    qsmm_node_create_v2(qsmm,"walker",0,&node);
    qsmm_engine_create(qsmm);
    if (prg_asm) qsmm_node_asm(qsmm,node,QSMM_EXCEPT_ALL,prg_asm,msglist);
    const qsmm_actor_t actor_env=
        qsmm_get_actpair_actor(qsmm_get_actpair(qsmm),QSMM_ENGINE_ENV);
    CHK_FAIL(qsmm_set_actor_auto_spur_type,actor_env,0);
    CHK_FAIL(qsmm_set_actor_spur_weight,actor_env,0,1);
    CHK_FAIL(qsmm_set_actor_spur_weight,actor_env,1,1);
    if (argc>1 && (seed=atoi(argv[1]))<0) {
        qsmm_set_random(qsmm,1);
        seed=-seed;
    }
    qsmm_rng_seed(qsmm_get_rng(qsmm),seed);
    for (int visit=0; visit<NVISIT; visit++) {
        unsigned char percept=0;
        is_gold_found=0;
        path_len_pass=0;
        opaque_maze(DIRECT_NORTH,&percept);
        qsmm_node_call_default(qsmm,node,0);
        printf(
    "visit %d: ngf %d, path_pass %d, path_total %d, ngf/path_total %.8f\n",
               visit+1, n_gold_found, path_len_pass, path_len_total,
               (double) n_gold_found/path_len_total);
    }
    exit_code=0;

Exit:
    qsmm_prg_destroy(prg_asm);
    qsmm_destroy(qsmm);
    if (msglist) {
        msglist_dump=msglist;
        msglist=0;
        CHK_FAIL(qsmm_msglist_dump,msglist_dump,0,"BUFFER",0,stderr);
    }
    qsmm_msglist_destroy(msglist_dump);
    return exit_code;
}

Sample program output is below.

$ qsmm-example-maze-asm -1
nstate 512
visit 1: ngf 0, path_pass 94, path_total 94, ngf/path_total 0.00000000
visit 2: ngf 0, path_pass 706, path_total 800, ngf/path_total 0.00000000
...
visit 101: ngf 19, path_pass 640, path_total 87374, ngf/path_total 0.00021746
visit 102: ngf 19, path_pass 962, path_total 88336, ngf/path_total 0.00021509
...
visit 199: ngf 37, path_pass 90, path_total 178714, ngf/path_total 0.00020703
visit 200: ngf 37, path_pass 726, path_total 179440, ngf/path_total 0.00020620
$ qsmm-example-maze-asm 1
nstate 512
visit 1: ngf 0, path_pass 632, path_total 632, ngf/path_total 0.00000000
visit 2: ngf 1, path_pass 2252, path_total 2884, ngf/path_total 0.00034674
...
visit 101: ngf 88, path_pass 266, path_total 51398, ngf/path_total 0.00171213
visit 102: ngf 89, path_pass 266, path_total 51664, ngf/path_total 0.00172267
...
visit 199: ngf 186, path_pass 468, path_total 82666, ngf/path_total 0.00225002
visit 200: ngf 187, path_pass 338, path_total 83004, ngf/path_total 0.00225290

The above pieces of output show that the average amount of gold found per one move in the labyrinth in adaptive mode of program operation with random seed 1 without using the profile assembler program is about 11 times greater than in random mode of program operation.

$ qsmm-example-maze-asm -1 "$prefix/share/qsmm/samples/maze.asm"
visit 1: ngf 1, path_pass 3086, path_total 3086, ngf/path_total 0.00032404
visit 2: ngf 1, path_pass 274, path_total 3360, ngf/path_total 0.00029762
...
visit 101: ngf 17, path_pass 768, path_total 92636, ngf/path_total 0.00018351
visit 102: ngf 17, path_pass 898, path_total 93534, ngf/path_total 0.00018175
...
visit 199: ngf 43, path_pass 132, path_total 192766, ngf/path_total 0.00022307
visit 200: ngf 43, path_pass 118, path_total 192884, ngf/path_total 0.00022293
$ qsmm-example-maze-asm 1 "$prefix/share/qsmm/samples/maze.asm"
visit 1: ngf 1, path_pass 3086, path_total 3086, ngf/path_total 0.00032404
visit 2: ngf 2, path_pass 52, path_total 3138, ngf/path_total 0.00063735
...
visit 101: ngf 101, path_pass 52, path_total 8286, ngf/path_total 0.01218923
visit 102: ngf 102, path_pass 52, path_total 8338, ngf/path_total 0.01223315
...
visit 199: ngf 199, path_pass 52, path_total 13382, ngf/path_total 0.01487072
visit 200: ngf 200, path_pass 52, path_total 13434, ngf/path_total 0.01488760

The above pieces of output show that the average amount of gold found per one move in the labyrinth in adaptive mode of program operation with random seed 1 and the use of the profile assembler program is about 67 times greater than in random mode of program operation.


6 Miscellaneous Topics

This chapter covers secondary topics not covered in the other chapters of this manual.


6.1 Random Number Generators

An actor uses a random number generator as a source of randomness to stochastically emit output signals according to their probabilities.

A standard random number generator used in QSMM is actually a pseudo-random number generator. By default, the GNU Scientific Library provides the pseudo-random number generator. A developer can provide a custom random number generator for using by QSMM. The custom random number generator may actually be a pseudo-random number generator or may provide real random numbers obtained using some physical process.

Whereas using a random (not pseudo-random) number generator adds a sense of “free will” to a system, improper application of a random number generator in the system might be comparable with a brain injury. The selection of a method of interfacing a physical process with a system via a random number generator might affect whether the system behaves as an integral or separate part of the environment. Currently, QSMM might not support developing a system behaving as an integral part of the environment.


6.1.1 Creating a Random Number Generator

A random number generator handle refers to a random number generator.

Data type: qsmm_rng_t

This is a type for the handle of a random number generator. The handle is a pointer, so variables of this type can be NULL. The functions qsmm_rng_create and qsmm_rng_create_custom allocate a new handle. The function qsmm_rng_destroy frees an existing handle.

You can pass an allocated handle to API functions taking an argument of qsmm_rng_t type until freeing the handle. You can also set an allocated handle as the rng field of qsmm_actor_desc_s or qsmm_desc_s structure specifying the parameters of creating an actor or multinode model respectively. The lifetime of the allocated handle should be longer than the lifetime of the actor or multinode model.

The function qsmm_get_actor_rng returns the handle of a random number generator specified in the rng field of qsmm_actor_desc_s structure when creating an actor by the function qsmm_actor_create or returns the handle of an instance of default random number generator allocated automatically if that field was NULL. The function qsmm_get_rng returns the handle of a random number generator specified in the rng field of qsmm_desc_s structure when creating a multinode model by the function qsmm_create or returns the handle of an instance of default random number generator allocated automatically if that field was NULL.

Use the following function to create a random number generator as an instance of default random number generator.

Function: int qsmm_rng_create (qsmm_rng_t *rng_p)

This function creates a random number generator and stores its newly allocated handle in *rng_p. The function creates either a random number generator with a type defined by a user-supplied function qsmm_proxy_func_t and its parameter set by a call to the function qsmm_set_rng_default (see Custom Random Number Generators) or a random number generator with a standard type defined when configuring the package if the user-supplied function not set.

The function returns a non-negative value on success or a negative error code on failure in creating a random number generator. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument rng_p is NULL.

QSMM_ERR_NOMEM

There was not enough memory to create a random number generator.

In default and recommended mode, the configure script configures the package to use a pseudo-random number generator provided by the GNU Scientific Library as a standard random number generator. In the other mode, the configure script configures the package to use a pseudo-random number generator implemented by the function rand from the standard C library. The latter mode does not require dependency on the external library. See the file INSTALL in the root of the package distribution for how to specify the latter mode for the configure script.

One of disadvantages of using a pseudo-random number generator implemented by rand is that only one instance of the pseudo-random number generator exists, and different handles actually refer to this single instance causing problems when seeding pseudo-random number generators represented by different handles.

Use the function described below to create a random number generator based on a user-supplied function.

Function: int qsmm_rng_create_custom (qsmm_proxy_func_t rng_func, void *paramp, qsmm_rng_t *rng_p)

This function creates a random number generator based on a function rng_func and its parameter paramp and stores a newly allocated handle of the random number generator in *rng_p. The function rng_func must implement a random number generator interface described in Custom Random Number Generators.

The function returns a non-negative value on success or a negative error code on failure in creating a random number generator. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument rng_p is NULL.

QSMM_ERR_NOMEM

There was not enough memory to create a random number generator.

Use the following function to destroy a random number generator.

Function: void qsmm_rng_destroy (qsmm_rng_t rng)

This function destroys a random number generator specified by a handle rng. You must not use the handle after destroying the random number generator. If rng is NULL, the function has no effect.

An application program may only destroy random number generators it created explicitly by the function qsmm_rng_create or qsmm_rng_create_custom. If an application program destroys a random number generator implicitly allocated for an actor or multinode model on its creation and returned by the function qsmm_get_actor_rng or qsmm_get_rng respectively, a memory error occurs later.


6.1.2 Generating Random Numbers

Use the following functions to generate uniformly distributed random numbers.

Function: int qsmm_rng_uniform_int (qsmm_rng_t rng, int nn)

This function returns a new integer random number uniformly distributed in the range 0 (inclusive) to nn (exclusive) produced using a random number generator rng. If nn is less than 1, the function returns negative error code QSMM_ERR_INVAL.

Function: double qsmm_rng_uniform (qsmm_rng_t rng)

This function returns a new random number uniformly distributed in the range 0 (inclusive) to 1 (exclusive) produced using a random number generator rng.

Function: double qsmm_rng_uniform_pos (qsmm_rng_t rng)

This function returns a new positive random number uniformly distributed in the range 0 to 1 (exclusive) produced using a random number generator rng.

Use the following function to seed a pseudo-random number generator.

Function: void qsmm_rng_seed (qsmm_rng_t rng, int seed)

This function seeds a pseudo-random number generator rng using seed. A seed specifies a stream of pseudo-random numbers produced by the generator. A random number generator created on the basis of a user-supplied function might not support seeding.


6.1.3 Custom Random Number Generators

A user-supplied function qsmm_proxy_func_t and its parameter define a custom type of random number generator. The function qsmm_rng_create_custom creates an instance of a custom random number generator. You can set a custom type of random number generator as the default type of random number generator. The function qsmm_rng_create creates an instance of a default random number generator. The functions qsmm_actor_create and qsmm_create call qsmm_rng_create if the rng field of qsmm_actor_desc_s or qsmm_desc_s structure is NULL.

Use the following functions to retrieve or set a user-supplied function qsmm_proxy_func_t and its parameter defining the default type of random number generator.

Function: void qsmm_get_rng_default (qsmm_proxy_func_t *rng_func_p, void **param_pp)

This function retrieves the default type of random number generator defined by a user-supplied function qsmm_proxy_func_t and its parameter. If rng_func_p is not NULL, the function sets *rng_func_p to a pointer to the user-supplied function. If the default random number generator is a standard random number generator (with a type defined when configuring the package), the function sets *rng_func_p to NULL. If param_pp is not NULL, the function sets *param_pp to a user parameter of qsmm_proxy_func_t function.

Function: void qsmm_set_rng_default (qsmm_proxy_func_t rng_func, void *paramp)

This function sets the default type of random number generator. A function rng_func and its parameter paramp define that type. If rng_func is NULL, the function qsmm_set_rng_default sets a standard random number generator (with a type defined when configuring the package) as the default random number generator.

A function that along with its user parameter defines the type of a random number generator has a prototype of an abstract proxy function. Future QSMM versions may use this abstract proxy function to perform operations on other objects.

Data type: qsmm_proxy_func_t

This is a type for the pointer to an abstract proxy function. The following declaration corresponds to the type:

typedef int
(*qsmm_proxy_func_t)(
    int cmd,
    int in_sz,
    int out_sz,
    const void *in_p,
    void *out_p,
    void *paramp
);

The argument cmd specifies the identifier of a command—an operation the proxy function shall perform. A buffer in_p with length in_sz bytes specifies input parameters of the command. The proxy function shall store or update in a buffer out_p with length out_sz bytes the results of command invocation. The argument paramp is a user parameter specified when setting the proxy function.

On successful completion, the proxy function shall return a non-negative value. On error, the proxy function shall return a negative value. Specific interpretation of a returned value depends on an object the function represents and an operation performed by the function.

Below there is a description of a random number generator interface for implementing by a proxy function—possible cmd values, input command parameters, and the results of command invocation.

Macro: QSMM_RNG_CMD_CREATE

Create a random number generator. The proxy function shall store in a buffer out_p the pointer to an object representing the random number generator. The argument out_sz is always equal to sizeof(void *). For example, to return the pointer rng_state_p addressing an allocated instance of a structure holding the state of a created random number generator, write a line of code like this:

*((void **) out_p)=rng_state_p;

The proxy function can return negative error code QSMM_ERR_NOMEM indicating that there was not enough memory to allocate an object representing the random number generator. In this case, the function qsmm_rng_create or qsmm_rng_create_custom called to create the random number generator returns this error code.

Macro: QSMM_RNG_CMD_DESTROY

Destroy a random number generator. A buffer in_p holds the pointer to an object representing the random number generator. The argument in_sz is always equal to sizeof(void *). For example, to obtain the pointer rng_state_p addressing an allocated instance of a structure holding the state of a random number generator for subsequent destruction of the instance, write the following line of code:

rng_state_p=*((void **) in_p);

The proxy function shall return a non-negative value.

Macro: QSMM_RNG_CMD_GENERATE

Generate a random number. A buffer in_p holds the pointer to an object representing the random number generator. The argument in_sz is always equal to sizeof(void *). The proxy function shall store in a buffer out_p a generated random number uniformly distributed in the range 0 (inclusive) to 1 (exclusive). The argument out_sz is always equal to sizeof(double). For example, to return generated random number rnd, write a line of code like this:

*((double **) out_p)=rnd;

The proxy function shall return a non-negative value.

Macro: QSMM_RNG_CMD_SEED

Seed a pseudo-random number generator. A buffer in_p holds an instance of qsmm_rng_cmd_seed_in_s structure (see below) containing a random seed and the pointer to an object representing the pseudo-random number generator. The function qsmm_rng_seed receives the random seed as the second argument. The argument in_sz is always equal to sizeof(struct qsmm_rng_cmd_seed_in_s). To obtain seeding parameters, use the lines of code like these:

const struct qsmm_rng_cmd_seed_in_s *const cmd_in_p=in_p;
rng_state_p=cmd_in_p->rng_object_p;

If the pseudo-random number generator does not support the seeding operation, the proxy function can return negative error code QSMM_ERR_NOTSUP. However, the function qsmm_rng_seed currently returns void and ignores this error code.

The following structure conveys the parameters of a seeding operation.

Structure: qsmm_rng_cmd_seed_in_s

This structure passes input parameters of an operation of seeding a pseudo-random number generator. The structure contains the following fields.

Field: int seed

A seed value.

Field: void * rng_object_p

The pointer to an object representing the pseudo-random number generator.

An example proxy function implementing the random number generator interface is below.

#include <stdint.h>
#include <stdlib.h>

#include <qsmm/qsmm.h>

static int
rng_proxy(
    int cmd,
    int in_sz,
    int out_sz,
    const void *in_p,
    void *out_p,
    void *paramp
) {
    uint32_t *seed_p;
    switch (cmd) {
        case QSMM_RNG_CMD_CREATE:
            if (!(seed_p=malloc(sizeof(*seed_p)))) return QSMM_ERR_NOMEM;
            *seed_p=1;
            *((void **) out_p)=seed_p;
            break;
        case QSMM_RNG_CMD_DESTROY:
            free(*((void **) in_p));
            break;
        case QSMM_RNG_CMD_GENERATE:
            seed_p=*((void **) in_p);
            *seed_p=*seed_p*1103515245+12345;
            *((double *) out_p)=(*seed_p/65536)%32768/32768.0;
            break;
        case QSMM_RNG_CMD_SEED: {
            const struct qsmm_rng_cmd_seed_in_s *const cmd_in_p=in_p;
            seed_p=cmd_in_p->rng_object_p;
            *seed_p=cmd_in_p->seed;
            break;
        }
    }
    return 0;
}

To set this proxy function as the default type of random number generator, write the line of code

qsmm_set_rng_default(&rng_proxy,0);

6.2 Ordinary and Sparse Vectors

A vector handle refers to an ordinary or sparse vector.

Data type: qsmm_vec_t

This is a type for a vector handle. It is a pointer, so variables of this type can be NULL. The function qsmm_get_actor_choice_sig_prob_vec returns the handle of a vector holding the probabilities of emitting output signals by an actor. The function qsmm_vec_clone returns the handle of a newly allocated copy of a vector. After using the copy, free its handle by the function qsmm_vec_destroy.

Use the following function to get the number of accessible vector elements.

Function: size_t qsmm_get_vec_npos (qsmm_vec_t vec)

This function returns the number of accessible elements in a vector vec. For an ordinary vector, that number might be equal to the length of a vector segment containing elements with set values. For a sparse vector, that number is equal to the number of elements with set values. Normally, it is the number of non-zero elements in the sparse vector.

Use the following function to get the value of an element of a vector.

Function: int qsmm_get_vec_elm_by_pos_d (qsmm_vec_t vec, size_t pos, size_t *idx_p, double *val_p)

This function retrieves the index and value of an element of a vector vec by access position of the element. The argument pos specifies the access position. It must be less than the number of accessible elements in the vector. If idx_p is not NULL, the function sets *idx_p to the index of the element. If val_p is not NULL, the function sets *val_p to the value of the element.

On success, the function returns a non-negative value. If the access position is greater than or equal to a value returned by the function qsmm_get_vec_npos, qsmm_get_vec_elm_by_pos_d returns negative error code QSMM_ERR_INVAL.

Use the following function to get access position of an element of a vector by the index of the element.

Function: int qsmm_get_vec_pos_by_idx_v2 (qsmm_vec_t vec, int rez1, size_t idx, size_t *pos_p)

This function retrieves access position of an element of a vector vec by the index of the element. The argument idx specifies that index. If pos_p is not NULL, the function sets *pos_p to the access position. It is less than the number of accessible vector elements returned by the function qsmm_get_vec_npos. The argument rez1 is for future use and must be equal to 0.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument idx is greater than or equal to the number of vector dimensions.

QSMM_ERR_NOTFOUND

No such access position for a valid idx—the element at index idx is zero.

For example, to get the value of an element of a vector vec at index idx, you can use a block of code like this:

int rc;
double val=0;  // element value
size_t pos=0;  // element access position
if ((rc=qsmm_get_vec_pos_by_idx_v2(vec,0,idx,&pos))>=0) {
    rc=qsmm_get_vec_elm_by_pos_d(vec,pos,0,&val);
    assert(rc>=0);
}
else assert(rc==QSMM_ERR_NOTFOUND);

Use the following function to create a copy of a vector.

Function: int qsmm_vec_clone (qsmm_vec_t vec_src, qsmm_vec_t *vec_dst_p)

This function creates a copy of a vector vec_src and stores the handle of the copy in *vec_dst_p. The copy might occupy less memory compared to the original vector because the function might only copy a segment of an ordinary vector containing elements with set values.

The function returns a non-negative value on success or a negative error code on failure in creating a copy of a vector. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument vec_dst_p is NULL.

QSMM_ERR_NOMEM

There was not enough memory to create a copy of vec_src.

Use the following function to destroy a copy of a vector created by qsmm_vec_clone.

Function: void qsmm_vec_destroy (qsmm_vec_t vec)

This function destroys a vector specified by a handle vec. You must not use the handle after destroying the vector. If vec is NULL, the function has no effect.

An application program may only destroy vectors it created by the function qsmm_vec_clone. If an application program destroys a vector with a handle returned by the function qsmm_get_actor_choice_sig_prob_vec, a memory error occurs later.


6.3 Messages and Message Lists

QSMM uses message lists to return error, warning, and note messages as part of a result of the following operations:

  • loading a memory representation of an assembler program into a node;
  • parsing the source text of an assembler program;
  • preprocessing the source text of an assembler program;
  • access to statistics storage.

Besides that, you can use the Message List API to return lists of messages from functions you develop.

A handle of qsmm_msglist_t type refers to a message list. A handle of qsmm_msg_t type refers to an individual message. The function qsmm_msglist_create creates an empty message list. You pass an empty message list to an API function that can fill it with messages. The function qsmm_msglist_dump dumps all messages in a message list to a stream. After using a message list, you destroy it by the function qsmm_msglist_destroy.


6.3.1 Creating Messages

A message list contains message objects. A message handle refers to an individual message object.

Data type: qsmm_msg_t

This is a type for a message handle. It is a pointer, so variables of this type can be NULL. The functions qsmm_msg_create_f and qsmm_msg_create_fv allocate a new message handle. The function qsmm_msg_destroy frees the handle of a message not added to a message list. If a message is in a message list, clearing or destroying the message list frees the handle of the message. You can pass an allocated message handle to API functions taking an argument of qsmm_msg_t type until freeing the handle.

When creating a message object, you specify its message category using the following enumeration.

Enumeration: qsmm_msg_e

This enumeration specifies the category of a message. That category affects labeling the message in its text representation. The function qsmm_get_msglist_sz_type retrieves the number of messages belonging to a specific category in a message list. The enumeration consists of the following elements.

QSMM_MSG_GENERAL

An uncategorized message. No category label precedes a message text.

QSMM_MSG_NOTE

A note message. The label ‘note: ’ precedes a message text.

QSMM_MSG_WARNING

A warning message. The label ‘warning: ’ precedes a message text.

QSMM_MSG_ERROR

An error message. The label ‘error: ’ precedes a message text.

QSMM_MSG_COUNT

The last enumeration element equal to the number of supported message categories.

Use the following functions to create a message object with a specified message text.

Function: int qsmm_msg_create_f (qsmm_msg_t *msg_p, enum qsmm_msg_e msg_type, const char *fmt_p, ...)
Function: int qsmm_msg_create_fv (qsmm_msg_t *msg_p, enum qsmm_msg_e msg_type, const char *fmt_p, va_list ap)

The functions create a message belonging to a category msg_type and store a newly allocated message handle in *msg_p if msg_p is not NULL. If msg_p is NULL, the functions destroy a just created message and report success.

The function qsmm_msg_create_f formats a message text according to the argument fmt_p and subsequent arguments interpreted as in the function printf. The function qsmm_msg_create_fv formats a message text according to the arguments fmt_p and ap interpreted as in the function vprintf. If fmt_p is NULL, the functions create an empty message. In this case, qsmm_msg_create_fv ignores the argument ap.

The functions return a non-negative value on success or a negative error code on failure in creating a message. Currently, the functions can return the following error codes.

QSMM_ERR_INVAL

The argument msg_type is negative or greater than or equal to QSMM_MSG_COUNT.

QSMM_ERR_ILSEQ

Unable to convert the message text to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to create the message.

Use the following functions to append text to an already existing message.

Function: int qsmm_msg_append_f (qsmm_msg_t msg, int rez1, const char *fmt, ...)
Function: int qsmm_msg_append_fv (qsmm_msg_t msg, int rez1, const char *fmt, va_list ap)

The functions append a formatted text to a message msg. The argument rez1 is for future use and must be equal to 0.

The function qsmm_msg_append_f formats appended message text according to the argument fmt and subsequent arguments interpreted as in the function printf. The function qsmm_msg_append_fv formats appended message text according to the arguments fmt and ap interpreted as in the function vprintf.

The functions return a non-negative value on success or a negative error code on failure. Currently, the functions can return the following error codes.

QSMM_ERR_ILSEQ

Unable to convert the formatted text to a wide string according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to create a copy of a message object.

Function: int qsmm_msg_clone (qsmm_msg_t src, qsmm_msg_t *dst_p)

This function creates a copy of a message src and stores the handle of the copy in *dst_p if dst_p is not NULL. If dst_p is NULL, the function destroys a just created copy and reports success.

The function returns a non-negative value on success or negative error code QSMM_ERR_NOMEM if there was not enough memory to create a message copy.

Use the following function to destroy a message object.

Function: void qsmm_msg_destroy (qsmm_msg_t msg)

This function destroys a message specified by a handle msg. You must not use the handle after destroying the message. If msg is NULL, the function has no effect.

You must not use this function to destroy messages added to a message list. The function qsmm_msglist_clear or qsmm_msglist_destroy destroys the messages when clearing or destroying the message list.

Use the following function to get the category of a message.

Function: enum qsmm_msg_e qsmm_get_msg_type (qsmm_msg_t msg)

This function returns the category of a message msg. The function qsmm_msg_create_f or qsmm_msg_create_fv sets that category when creating the message.

A message can have a line number assigned. If the line number is positive, and the function qsmm_msg_str or qsmm_msglist_dump (see Printing Messages) knows a file name associated with the message, the function prepends the file name and line number to a message text. By default, a created message does not have a line number assigned.

Function: int qsmm_set_msg_lineno (qsmm_msg_t msg, long lineno)

This function assigns line number lineno to a message msg.

If the function qsmm_msg_str or qsmm_msglist_dump knows a file name associated with the message, and lineno is positive, the file name and line number lineno go before a message text. If qsmm_msg_str or qsmm_msglist_dump knows a file name associated with the message, and lineno is 0, the file name but not the line number goes before a message text. Thus, special line number 0 may indicate that the message pertains to the entire file. If lineno is −1, qsmm_msg_str and qsmm_msglist_dump do not prepend a file name and line number to a message text.

The function qsmm_set_msg_lineno returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument lineno is less than −1.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.


6.3.2 Creating a Message List

A message list handle refers to a message list.

Data type: qsmm_msglist_t

This is a type for a message list handle. It is a pointer, so variables of this type can be NULL. The function qsmm_msglist_create allocates a new message list handle. The function qsmm_msglist_destroy frees an existing message list handle. You can pass an allocated message list handle to API functions taking an argument of qsmm_msglist_t type until freeing the handle.

Use the following function to create an empty message list for passing it to a function that can fill it with messages.

Function: int qsmm_msglist_create (qsmm_msglist_t *msglist_p)

This function creates an empty message list and stores its newly allocated handle in *msglist_p if msglist_p is not NULL. If msglist_p is NULL, the function destroys a just created message list and reports success.

The function returns a non-negative value on success or negative error code QSMM_ERR_NOMEM if there was not enough memory to create a message list.

Use the following function to destroy a message list and all the messages it contains.

Function: void qsmm_msglist_destroy (qsmm_msglist_t msglist)

This function destroys a message list specified by a handle msglist. You must not use the handle after destroying the message list. If msglist is NULL, the function has no effect.


6.3.3 Adding Messages to a Message List

Use the following function to add a message to a message list.

Function: int qsmm_msglist_add_msg (qsmm_msglist_t msglist, qsmm_msg_t msg)

This function adds a message msg to a message list msglist. The message list becomes the owner of the message. You must not add a message to multiple message lists.

After adding a message to a message list, you must not explicitly destroy the message by the function qsmm_msg_destroy. The function qsmm_msglist_clear or qsmm_msglist_destroy destroys the message automatically when clearing or destroying the message list.

The function qsmm_msglist_add_msg returns a non-negative value on success or negative error code QSMM_ERR_NOMEM if there was not enough memory to perform the operation.

Use the following function to append to a message list copies of all messages contained in another message list.

Function: int qsmm_msglist_extend (qsmm_msglist_t dst, qsmm_msglist_t src)

This function appends to the end of a message list dst copies of all messages contained in a message list src, in the same order.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument src or dst is NULL, or src is equal to dst.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Use the following function to clear a message list.

Function: void qsmm_msglist_clear (qsmm_msglist_t msglist)

This function removes all messages from a message list msglist and destroys them.

Use the following function to get the total number of messages contained in a message list.

Function: size_t qsmm_get_msglist_sz (qsmm_msglist_t msglist)

This function returns the total number of messages contained in a message list msglist.

Use the following function to get the number of messages belonging to a specific category contained in a message list.

Function: int qsmm_get_msglist_sz_type (qsmm_msglist_t msglist, enum qsmm_msg_e msg_type, size_t *sz_p)

This function retrieves the number of messages belonging to a category msg_type contained in a message list msglist. If sz_p is not NULL, the function sets *sz_p to that number of messages.

If the message list contains at least one message belonging to the category, the function returns a positive value. If the message list does not contain messages belonging to the category, the function returns 0. If msg_type is negative or greater than or equal to QSMM_MSG_COUNT, the function returns negative error code QSMM_ERR_INVAL .

Use the following function to get a message contained in a message list.

Function: qsmm_msg_t qsmm_get_msglist_msg (qsmm_msglist_t msglist, size_t idx)

This function returns the handle of a message contained in a message list msglist at index idx. If idx is greater than or equal to the total number of messages held in the message list, the function returns NULL.


6.3.4 Printing Messages

Use the following function to get a text representation of a message object.

Function: int qsmm_msg_str (char *bufp, size_t bufsz, qsmm_msg_t msg, struct qsmm_dump_msg_desc_s *desc_p)

This function stores in a buffer bufp with size bufsz bytes a text representation of a message msg. If desc_p is not NULL, the function generates the text representation according to parameters in *desc_p. If desc_p is NULL, the function generates the text representation according to default parameters.

If desc_p is not NULL, the function sets desc_p->out_sz to the number of bytes required to store the text representation not counting finalizing byte 0. That number does not depend on bufsz. To determine the length of a text representation in this way, the function supports passing 0 for both bufp and bufsz.

If bufsz is positive, the function always finalizes a string written to bufp with byte 0. If the string and its finalizing byte 0 occupy more than bufsz bytes, the function truncates the string. In this case, desc_p->out_sz is greater than or equal to bufsz (if desc_p is not NULL).

If the buffer is large enough to hold the text representation including its finalizing byte 0, the function returns a positive value. If the buffer is smaller than needed, the function returns 0. On failure, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

The argument bufsz is positive, but bufp is NULL.

QSMM_ERR_ILSEQ

Unable to convert the message object to its text representation according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

The description of a structure for specifying the parameters of converting a message object to its text representation is below. The structure has a field for storing the length of the representation by the function qsmm_msg_str.

Structure: qsmm_dump_msg_desc_s

This structure specifies input and output parameters of converting a message object to its text representation. The structure contains the following fields.

Field: char is_compile

If this field is not 0, the function qsmm_msg_str considers an application program that has generated the message as a compiler (or assembler), or a process the application program is carrying out as compiling (or assembling). In this case, if the message object contains source location information specifying the name of a source file and a line number in it, qsmm_msg_str does not prepend the text representation with an application program name passed in the field prg_name_p of this structure.

If this field is 0, qsmm_msg_str always prepends an application program name to the text representation provided that prg_name_p is not NULL.

By default, qsmm_msg_str considers the application program as a compiler, or a process the application program is carrying out as compiling.

Field: char do_print_type

If not 0, prepend to the text representation a message category defined by the macro QSMM_MSG_NOTE, QSMM_MSG_WARNING, or QSMM_MSG_ERROR.

The function qsmm_msg_create_f or qsmm_msg_create_fv sets the category of a message using the enumeration qsmm_msg_e when creating the message. The function qsmm_get_msg_type returns the category of a message. See Creating Messages, for more information about message categories.

By default, prepend a message category to the text representation.

Field: const char * prg_name_p

The name of an application program that has generated the message. The field is_compile of this structure and source location information in the message object determine whether or not that name precedes the text representation. If the field prg_name_p is NULL, the function qsmm_msg_str does not prepend an application program name to the text representation.

The default value is NULL.

Field: const char * fln_p

An associated file name if the message object does not have this file name in source location information. If the message object has a line number, including special line number 0, in the source location information (assigned by the function qsmm_set_msg_lineno), the function qsmm_msg_str prepends an associated file name to the text representation.

This field can contain the name of a top-level source file for use with message objects created while preprocessing the source text of an assembler program, parsing the source text of an assembler program, or loading a memory representation of an assembler program into a node. If such a message object has source location information specifying the name of a source file and a line number in it, the source location information references the source file directly or indirectly included in the top-level source file by the ‘include’ preprocessor directive. If the source location information specifies a line number but not a source file name, the line number pertains to the top-level source file. In the latter case, if this field is not NULL, qsmm_msg_str uses it for the name of the top-level source file and prepends that name to the text representation.

The default value of this field is NULL.

Field: size_t out_sz

Output parameter. The number of bytes occupied by the text representation not counting finalizing byte 0. That number does not depend on buffer size passed to qsmm_msg_str.

Zero by the function memset an instance of qsmm_dump_msg_desc_s structure before setting its fields.

The function qsmm_msg_str converts user-created message objects to their text representations in formats listed below. A label corresponding to the category of a message specified when creating the message object can precede a message text; see the description of do_print_type field of qsmm_dump_msg_desc_s structure for more information.

message text
program name: message text
input file name: message text
input file name:line number: message text
program name: input file name: message text
program name:input file name:line number: message text

Text representations of message objects created when preprocessing the source text of an assembler program, parsing the source text of an assembler program, or loading a memory representation of an assembler program into a node may have other formats. For example, the function qsmm_msg_str might prepend a stack of locations in assembler source files to an error message generated while parsing the source text of an assembler program. The stack might indicate locations of ‘include’ preprocessor directives included the content of an assembler source file with an error.

Use the following function to dump a message list to a stream.

Function: int qsmm_msglist_dump (qsmm_msglist_t msglist, const char *prg_name_p, const char *fln_p, unsigned int flags, FILE *filep)

This function dumps to a stream filep all messages contained in a message list msglist. The argument prg_name_p specifies the name of an application program that has generated the messages. The argument fln_p specifies the name of a top-level file (usually input one) associated with the messages. The argument flags can contain a bitmask defined by the macro QSMM_MSG_DUMP_PRG_NAME_ALL.

If prg_name_p is not NULL, and flags do not contain the bitmask QSMM_MSG_DUMP_PRG_NAME_ALL, the function prepends the application program name prg_name_p to messages without associated line numbers (but does not prepend the application program name to messages with associated non-negative line numbers). If prg_name_p is not NULL, and flags contain the bitmask QSMM_MSG_DUMP_PRG_NAME_ALL, the function prepends the application program name to all messages.

If fln_p is not NULL, the function prepends the top-level file name fln_p to all messages with associated line numbers, including line number 0, but without associated file names.

To obtain text representations of message objects contained in the message list, this function calls the function qsmm_msg_str. If after writing the text representation of a message object to the stream the function ferror reports a stream error, qsmm_msglist_dump aborts dumping the messages and reports success. A calling function can use ferror to test for this stream error condition.

On success or stream error, qsmm_msglist_dump returns a non-negative value. On other errors, the function returns a negative error code. Currently, the function can return the following error codes.

QSMM_ERR_ILSEQ

Unable to convert a message object contained in the message list to a text representation according to a current locale.

QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

On the above errors, the function aborts dumping remaining messages in the message list.


6.4 Exchanging Data Packets in a Multithreaded Program [Experimental]

QSMM provides a simple mechanism for exchanging data packets in multithreaded programs. The mechanism can be helpful in organizing the interaction of a system you develop with an environment you model, each executing in a separate thread. Another possible use of the mechanism is aggregating the results of parallel invocation of adaptive probabilistic mappings to get more optimal and precise system behavior.

Part of QSMM API called Side API represents the mechanism—multiple sides can take part in the interaction. The header file qsmm/side.h contains declarations and definitions for the Side API.

The Side API is available if the configure script has configured the package to use the POSIX threads API. See the file INSTALL in the root of the package distribution for information about the configure script.


6.4.1 Registering Interaction Sides

Before exchanging data packets, an application program registers sides taking part in the interaction. A side handle refers to a registered interaction side.

Data type: qsmm_side_t

This is a type for a side handle. It is a pointer, so variables of this type can be NULL. The function qsmm_side_create allocates a new side handle. The function qsmm_side_destroy frees an existing side handle. You can pass an allocated side handle to API functions taking an argument of qsmm_side_t type until freeing the handle.

Use the following functions to register and unregister an interaction side.

Function: int qsmm_side_create (const char *name_p, qsmm_side_t *side_p)

This function registers an interaction side named name_p and stores a newly allocated side handle in *side_p if side_p is not NULL. If side_p is NULL, the function has no effect. A name name_p identifies the interaction side in trace log of data packet exchange between sides. If name_p is not NULL, the function creates a copy of name_p and stores the copy in an internal structure.

The function returns a non-negative value on success or a negative error code on failure in registering a side. Currently, the function can return the following error codes.

QSMM_ERR_PTHREAD

A POSIX threads API error.

QSMM_ERR_NOMEM

There was not enough memory to register a side.

Function: void qsmm_side_destroy (qsmm_side_t side)

This function unregisters an interaction side specified by a handle side. You must not use the handle after unregistering the side. If side is NULL, the function has no effect.

Use the following function to get the name of an interaction side specified by its handle.

Function: const char * qsmm_get_side_name (qsmm_side_t side)

This function returns the name of an interaction side specified when creating it. If the interaction side does not have a name specified, the function returns NULL.


6.4.2 Exchanging Data Packets Between Sides

The following function sends a data packet from a side to another side.

Function: int qsmm_side_send (qsmm_side_t side_from, qsmm_side_t side_to, size_t sz, const void *msgp)

This function sends a data packet occupying sz bytes and addressed by msgp from a side side_from to a side side_to. The function appends the data packet to the end of a queue of received data packets for side_to. If another thread called the function qsmm_side_recv for side_to and is waiting for a data packet to receive, the thread resumes execution, and that function returns a data packet just received.

On success, the function returns a non-negative value. If there was not enough memory to perform the operation, the function returns negative error code QSMM_ERR_NOMEM.

The following function receives a data packet.

Function: int qsmm_side_recv (qsmm_side_t side, size_t sz, void *msgp)

This function retrieves a data packet from the queue of received data packets of side and stores the data packet in a buffer msgp with size sz bytes. If sz is greater than the size of the data packet, the function leaves the remaining content of msgp unchanged. If there is no data packet to retrieve, the function blocks until another thread sends a data packet to side.

On success, the function returns a non-negative number of bytes occupied by a retrieved data packet or INT_MAX if the number is greater than INT_MAX. If sz is less than the size of a data packet in the queue, or if sz is positive, and msgp is NULL, the function returns negative error code QSMM_ERR_INVAL.

Use the following macro to send a data packet from a side to another side.

Macro: QSMM_SIDE_SEND (from, to, msg)

This macro sends a data packet stored in a variable msg from a side from to a side to. The macro expands to:

qsmm_side_send((from), (to), sizeof(msg), &(msg))

The macro argument msg must be a variable and not a constant, as the macro takes the address of that argument using ‘&’. For example, to send signal 1 from a side side_from to a side side_to, use the lines of code like these:

const qsmm_sig_t sig_out=1;
QSMM_SIDE_SEND(side_from,side_to,sig_out);

Use the following macro to receive a data packet.

Macro: QSMM_SIDE_RECV (side, msgp)

This macro retrieves a data packet from the queue of received data packets of side and stores the data packet in a variable *msgp. The macro expands to:

qsmm_side_recv((side), sizeof(*(msgp)), (msgp))

For example, to receive a signal sent to a side, use the lines of code like these:

qsmm_sig_t sig_in=QSMM_SIG_INVALID;
QSMM_SIDE_RECV(side,&sig_in);

6.4.3 Tracing the Exchange of Data Packets

QSMM provides facilities for tracing events related to interaction sides. You can specify types of events dumped to a trace log using a bitmask defined as a subset of the following macros merged by bitwise “or.”

Macro: QSMM_SIDE_TRACE_API

Side API calls entry and exit. API functions with a side handle argument dump a function name, names and values of function arguments, and a returned value.

Macro: QSMM_SIDE_TRACE_MSG

The content of data packets sent from an interaction side to other interaction sides dumped as byte arrays in hexadecimal notation.

Use the following functions to query or set a bitmask of types of events dumped to a trace log.

Function: unsigned int qsmm_get_side_trace_flags (qsmm_side_t side)

This function returns the bitmask of types of events dumped to trace log of an interaction side. The interaction side is the originator of the events. This function returns a bitmask set by the function qsmm_set_side_trace_flags or a default bitmask (see a remark below) if the latter function not yet called.

Function: void qsmm_set_side_trace_flags (qsmm_side_t side, unsigned int flags)

This function sets to flags the bitmask of types of events dumped to trace log of an interaction side. The interaction side is the originator of the events. The function does not check whether the bitmask is correct.

The function qsmm_side_create initializes the bitmask of types of events dumped to a trace log to QSMM_SIDE_TRACE_MSG.

An interaction side does not dump events to a trace log unless the side has an assigned stream for the trace log. Use the following functions to get or set the stream.

Function: FILE * qsmm_get_side_trace_stream (qsmm_side_t side)

This function returns a stream for trace log of an interaction side. If the side does not have the stream assigned, the function returns NULL.

Function: void qsmm_set_side_trace_stream (qsmm_side_t side, FILE *filep)

This function sets to filep the stream for trace log of an interaction side. The NULL stream disables dumping log messages.

Use the following functions to dump to a trace log a custom formatted message, for example, containing additional information about a data packet sent or received.

Function: void qsmm_side_trace_f (qsmm_side_t side, const char *fmt, ...)
Function: void qsmm_side_trace_fv (qsmm_side_t side, const char *fmt, va_list ap)

The functions write a formatted message to trace log of an interaction side. They append the character ‘\n’ to the message and flush the stream buffer. If side does not have a log stream set, the functions have no effect. The meaning of fmt argument and subsequent arguments of qsmm_side_trace_f is the same as in the function printf. The meaning of fmt and ap arguments of qsmm_side_trace_fv is the same as in the function vprintf.


6.4.4 Error Handling

An interaction side can have an error handler assigned to it. The error handler is a function called in the case of a failure in any Side API function that takes an argument of qsmm_side_t type and can return an error code of int type. The default error handler of an interaction side prints information on an occurred error to stderr and calls exit(2). If an interaction side does not have an error handler assigned (including the default error handler), or an error handler assigned to the interaction side does not terminate program execution and returns, a failed Side API function returns a corresponding error code.

Use the following functions to query or set an error handler for an interaction side.

Function: void qsmm_get_side_err_handler (qsmm_side_t side, qsmm_err_handler_func_t *func_p, void **param_pp)

This function retrieves information on an error handler assigned to an interaction side. If func_p is not NULL, the function sets *func_p to the pointer to the error handler function or to NULL if the interaction side does not have an error handler function assigned. If param_pp is not NULL, the function sets *param_pp to the user parameter of the error handler function.

Function: void qsmm_set_side_err_handler (qsmm_side_t side, qsmm_err_handler_func_t func, void *paramp)

This function assigns an error handler to an interaction side. The argument func specifies an error handler function. The argument paramp specifies the user parameter of the error handler function. If func is NULL, the interaction side does not use an error handler.

See Error Handling for a Multinode Model, for the description of qsmm_err_handler_func_t type for an error handler function.


6.5 The Implementation of Functionality of STL map Template

QSMM contains the implementation of functionality of C++ STL map and multimap templates. You can use the implementation in your C programs to create mapping objects without the need to rewrite the programs in C++ and potentially increase their complexity.

The header file qsmm/map.h contains declarations of datatypes and functions of the implementation.


6.5.1 Creating Maps and Iterators

A map handle refers to a mapping object.

Data type: qsmm_map_t

This is a type for a map handle referring to a mapping object supporting the functionality of C++ STL map or multimap template. A map handle is a pointer, so variables of this type can be NULL. The functions qsmm_map_create, qsmm_map_create_sz, qsmm_map_multi_create, and qsmm_map_multi_create_sz allocate a new map handle. The function qsmm_map_destroy frees an existing map handle. You can pass an allocated map handle to API functions taking an argument of qsmm_map_t type until freeing the handle.

There are two ways of dealing with keys and values in key-value pairs of a mapping object:

  1. Keys and/or values stored in key-value pair objects are untyped pointers—you should allocate and deallocate memory blocks addressed by the untyped pointers. When the keys and/or values are integer numbers, you can convert them to the standard intptr_t type and store them as pointers without the need to perform memory allocation and deallocation.
  2. Memory blocks of key-value pair objects include the content of keys and/or values thereby removing overhead caused by allocating and deallocating memory blocks for keys and/or values. You have to specify the size of each key and/or value when creating the mapping object.

Use the following functions to create a mapping object.

Function: qsmm_map_t qsmm_map_create (qsmm_compar_func_t key_compar_func, void *paramp)
Function: qsmm_map_t qsmm_map_create_sz (size_t key_sz, size_t val_sz, qsmm_compar_func_t key_compar_func, void *paramp)
Function: qsmm_map_t qsmm_map_multi_create (qsmm_compar_func_t key_compar_func, void *paramp)
Function: qsmm_map_t qsmm_map_multi_create_sz (size_t key_sz, size_t val_sz, qsmm_compar_func_t key_compar_func, void *paramp)

These functions create a mapping object. The functions qsmm_map_create and qsmm_map_create_sz create a mapping object supporting the functionality of C++ STL map template, that is, a mapping object that cannot contain duplicate keys in key-value pairs. The functions qsmm_map_multi_create and qsmm_map_multi_create_sz create a mapping object supporting the functionality of C++ STL multimap template, that is, a mapping object that can contain duplicate keys in key-value pairs.

The argument key_compar_func specifies a comparison function for the keys of the mapping object. The argument paramp specifies user parameter of the comparison function.

The functions qsmm_map_create and qsmm_map_multi_create create a mapping object with untyped pointers for its keys and values. The functions qsmm_map_create_sz and qsmm_map_multi_create_sz create a mapping object containing keys with size key_sz not equal to 0 and values with size val_sz. If key_sz is (size_t) -1, the keys are untyped pointers; otherwise, a positive key_sz specifies the size of each key in bytes. If val_sz is (size_t) -1, the values are untyped pointers; otherwise, val_sz specifies the size of each value in bytes. If val_sz is 0, the mapping object cannot store values corresponding to keys, that is, the mapping object is actually a set object, and set elements are the keys of the mapping object.

The call qsmm_map_create(&compar,paramp) is equivalent to the call qsmm_map_create_sz(-1,-1,&compar,paramp). The call qsmm_map_multi_create(&compar,paramp) is equivalent to the call qsmm_map_multi_create_sz(-1,-1,&compar,paramp).

On success, the functions return a non-NULL map handle. If there was not enough memory to create a mapping object, the functions return NULL.

Use the following function to destroy a mapping object.

Function: void qsmm_map_destroy (qsmm_map_t mm)

This function destroys a mapping object specified by a handle mm. You must not use the handle after destroying the mapping object. If mm is NULL, the function has no effect. If keys and/or values in key-value pairs of a mapping object contain untyped pointers to allocated objects, you must free them before destroying the mapping object. If memory blocks of key-value pairs of a mapping object contain memory blocks of keys and/or values that require special uninitialization, you must uninitialize them before destroying the mapping object.

When creating a mapping object, you supply a function for comparing the keys of the mapping object and supply a user parameter for the function. The mapping object contains key-value pairs sorted in ascending order of keys. A description of a type for a pointer to the comparison function is below.

Data type: qsmm_compar_func_t

This is a type for the pointer to a key comparison function. The following declaration corresponds to this type:

typedef int
(*qsmm_compar_func_t)(
    const void *o1p,
    const void *o2p,
    void *paramp
);

The key comparison function shall compare two keys addressed by the arguments o1p and o2p and return a positive value if the first key is greater than the second key, a negative value if the first key is less than the second key, or 0 if the keys are equal. The argument paramp is a user parameter specified when creating a mapping object with the key comparison function.

Use the following functions to obtain the pointer to a key comparison function and obtain its user parameter both specified when creating a mapping object.

Function: qsmm_compar_func_t qsmm_map_key_compar_func (qsmm_map_t mm)

This function returns the pointer to a key comparison function specified when creating a mapping object mm.

Function: void * qsmm_map_key_compar_param (qsmm_map_t mm)

This function returns user parameter of a key comparison function specified when creating a mapping object mm.

Use the following functions to obtain the size of each key and value specified when creating a mapping object.

Function: size_t qsmm_get_map_key_sz (qsmm_map_t mm)

This function returns the size of a key in each key-value pair of a mapping object mm. If a returned value is (size_t) -1, the keys are untyped pointers. Otherwise, a positive returned value is the number of bytes occupied by every key in the memory block of a key-value pair object. The function does not return 0.

Function: size_t qsmm_get_map_val_sz (qsmm_map_t mm)

This function returns the size of a value in each key-value pair of a mapping object mm. If a returned value is (size_t) -1, the values are untyped pointers. Otherwise, a returned value is the number of bytes occupied by every value in the memory block of a key-value pair object. If a returned value is 0, the mapping object cannot store values corresponding to keys, that is, the mapping object is actually a set object, and set elements are the keys of the mapping object.

Map iterators provide access to key-value pairs of mapping objects. An iterator handle refers to a map iterator.

Data type: qsmm_iter_t

This is a type for an iterator handle. It is a pointer, so variables of this type can be NULL.

The functions qsmm_map_iter_create and qsmm_map_multi_iter_create allocate a new iterator handle. An iterator handle allocated by qsmm_map_iter_create is for using with mapping objects created by the functions qsmm_map_create and qsmm_map_create_sz. An iterator handle allocated by qsmm_map_multi_iter_create is for using with mapping objects created by the functions qsmm_map_multi_create and qsmm_map_multi_create_sz.

The function qsmm_iter_destroy frees an existing iterator handle. You can pass an allocated iterator handle to API functions taking an argument of qsmm_iter_t type until freeing the handle.

Use the following functions to create and destroy a map iterator.

Function: qsmm_iter_t qsmm_map_iter_create ()

This function creates an iterator for using with mapping objects supporting the functionality of C++ STL map template. On success, the function returns a non-NULL iterator handle. If there was not enough memory to create an iterator, the function returns NULL.

Function: qsmm_iter_t qsmm_map_multi_iter_create ()

This function creates an iterator for using with mapping objects supporting the functionality of C++ STL multimap template. On success, the function returns a non-NULL iterator handle. If there was not enough memory to create an iterator, the function returns NULL.

Function: void qsmm_iter_destroy (qsmm_iter_t iter)

This function destroys a map iterator specified by a handle iter. You must not use the handle after destroying the iterator. If iter is NULL, the function has no effect.


6.5.2 Operations on Maps

Basic operations on mapping objects correspond to methods of C++ STL map and multimap templates.

Function: size_t qsmm_map_size (qsmm_map_t mm)

This function returns the number of key-value pairs contained in a mapping object mm. The function corresponds to the method size of STL map and multimap templates.

Function: int qsmm_is_map_empty (qsmm_map_t mm)

This function returns a positive value if a mapping object mm does not contain key-value pairs, or zero if it does. The function never returns negative values. It corresponds to the method empty of STL map and multimap templates.

Function: int qsmm_map_assign (qsmm_map_t dst, qsmm_map_t src)

This function copies all key-value pairs of a mapping object src to a mapping object dst. The function discards all key-value pairs contained in the mapping object dst before the copying. Either the functions qsmm_map_create and qsmm_map_create_sz or the functions qsmm_map_multi_create and qsmm_map_multi_create_sz must have created the mapping objects src and dst. Both mapping objects must have the same key size, the same value size, and the same pointer to the key comparison function and its user parameter.

If keys and/or values stored in key-value pair objects are untyped pointers, the function copies or discards the pointers rather than memory blocks addressed by them. If memory blocks of key-value pair objects contain memory blocks of keys and/or values, the function copies or discards them.

The function qsmm_map_assign corresponds to operator= of STL map and multimap templates. The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_INVAL

One of the following conditions is true:

  • qsmm_map_create or qsmm_map_create_sz created the mapping object src, whereas qsmm_map_multi_create or qsmm_map_multi_create_sz created the mapping object dst;
  • qsmm_map_multi_create or qsmm_map_multi_create_sz created the mapping object src, whereas qsmm_map_create or qsmm_map_create_sz created the mapping object dst;
  • mapping objects src and dst have different key size or value size;
  • mapping objects src and dst have different pointers to the key comparison function or its user parameter.
QSMM_ERR_NOMEM

There was not enough memory to perform the operation.

Function: int qsmm_map_insert (qsmm_map_t mm, void *keyp, void *valp, qsmm_iter_t result_loc)

This function inserts a key-value pair in a mapping object mm. The argument keyp specifies the key of the pair. The argument valp specifies the value of the pair.

If keys and/or values in key-value pair objects are untyped pointers, the function inserts a key-value pair object with an untyped pointer keyp and/or valp. If memory blocks of key-value pair objects contain memory blocks of keys and/or values, the function copies a memory block addressed by keyp and/or valp to an inserted key-value pair object. If memory blocks of key-value pair objects contain memory blocks of values, and valp is NULL, the function initializes memory block of a value in the key-value pair object with zero bytes.

If the function qsmm_map_create or qsmm_map_create_sz created the mapping object, it cannot contain duplicate keys. A key comparison function specified when creating the mapping object determines the uniqueness of keys. When inserting a new key-value pair with a key already contained in the mapping object, the new key-value pair replaces an old key-value pair. Replacing the old pair may cause a memory leak if the pair contains pointers to allocated memory blocks.

If the function qsmm_map_multi_create or qsmm_map_multi_create_sz created the mapping object, it can contain multiple key-value pairs with the same key. If the mapping object already has a key specified by keyp, an inserted key-value pair goes after all key-value pairs with this key.

After successful function completion, an iterator result_loc addresses a key-value pair just inserted in the mapping object if result_loc was not NULL. The type of the iterator must agree with the type of the mapping object. Calling the function with a non-NULL result_loc is useful when memory blocks of key-value pair objects contain memory blocks of values, and valp is NULL. In this case, the call qsmm_get_iter_val(result_loc) returns a pointer to the memory block of a value preinitialized with zero bytes for setting the value.

The function qsmm_map_insert corresponds to the method insert of STL map and multimap templates.

If qsmm_map_multi_create or qsmm_map_multi_create_sz created the mapping object, or it did not have a key specified by keyp, qsmm_map_insert returns a positive value. If qsmm_map_create or qsmm_map_create_sz created the mapping object, it already contained a key-value pair with a key specified by keyp, and qsmm_map_insert overwrote the key-value pair with a key and value specified by keyp and valp respectively, this function returns 0. On out of memory error, the function returns negative error code QSMM_ERR_NOMEM.

Function: void qsmm_map_clear (qsmm_map_t mm)

This function removes all key-value pairs from a mapping object mm. The function does not deallocate memory blocks addressed by pointers in keys and/or values of key-value pairs. The function corresponds to the method clear of STL map and multimap templates.

Function: void qsmm_map_find (qsmm_map_t mm, const void *keyp, qsmm_iter_t result)

This function finds in a mapping object mm a key-value pair that has a key equal to keyp. If the function qsmm_map_multi_create or qsmm_map_multi_create_sz created the mapping object, qsmm_map_find finds the first key-value pair that has a key equal to keyp. A key comparison function specified when creating the mapping object tests the equality of keys.

The function qsmm_map_find corresponds to the method find of STL map and multimap templates.

After function completion, an iterator result addresses a key-value pair found. If the key-value pair not found, the iterator addresses a location just after the last key-value pair in the mapping object. The type of the iterator must agree with the type of the mapping object.

Function: void qsmm_map_lower_bound (qsmm_map_t mm, const void *keyp, qsmm_iter_t result)

This function finds in a mapping object mm the first key-value pair that has a key greater than or equal to keyp. The function corresponds to the method lower_bound of STL map and multimap templates.

After function completion, an iterator result addresses a key-value pair found. If the key-value pair not found, the iterator addresses a location just after the last key-value pair in the mapping object. The type of the iterator must agree with the type of the mapping object.

Function: void qsmm_map_upper_bound (qsmm_map_t mm, const void *keyp, qsmm_iter_t result)

This function finds in a mapping object mm the first key-value pair that has a key greater than keyp. The function corresponds to the method upper_bound of STL map and multimap templates.

After function completion, an iterator result addresses a key-value pair found. If the key-value pair not found, the iterator addresses a location just after the last key-value pair in the mapping object. The type of the iterator must agree with the type of the mapping object.

Function: void qsmm_map_iter_begin (qsmm_map_t mm, qsmm_iter_t result)

This function retrieves the location of the first key-value pair in a mapping object mm. After function completion, an iterator result addresses that key-value pair. If the mapping object does not contain key-value pairs, the iterator addresses a location commonly designated as a location just after the last key-value pair in the mapping object. The type of the iterator must agree with the type of the mapping object. The function corresponds to the method begin of STL map and multimap templates.

Function: void qsmm_map_iter_end (qsmm_map_t mm, qsmm_iter_t result)

This function makes an iterator result address a location just after the last key-value pair in a mapping object mm. The type of the iterator must agree with the type of the mapping object. The function corresponds to the method end of STL map and multimap templates.

Function: void qsmm_map_iter_rbegin (qsmm_map_t mm, qsmm_iter_t result)

This function sets an iterator result to be a reverse iterator addressing the last key-value pair (in ascending order of keys) in a mapping object mm. If the mapping object does not contain key-value pairs, the iterator addresses a location commonly designated as a location just before the first key-value pair in the mapping object. The type of the iterator must agree with the type of the mapping object. The function corresponds to the method rbegin of STL map and multimap templates.

Function: void qsmm_map_iter_rend (qsmm_map_t mm, qsmm_iter_t result)

This function sets an iterator result to be a reverse iterator addressing a location just before the first key-value pair in a mapping object mm. The type of the iterator must agree with the type of the mapping object. The function corresponds to the method rend of STL map and multimap templates.

Function: void qsmm_map_erase (qsmm_map_t mm, qsmm_iter_t where)

This function removes from a mapping object mm a key-value pair addressed by an iterator where. The function does not deallocate memory blocks addressed by pointers in the key and/or value of the key-value pair. The function corresponds to the method erase of STL map and multimap templates.


6.5.3 Operations on Iterators

Map iterators support the following operations.

Function: int qsmm_is_iter_at_end (qsmm_iter_t iter)

This function returns a positive value if an iterator iter is a forward (normal) iterator addressing a location just after the last key-value pair in a mapping object, or if the iterator is a reverse iterator addressing a location just before the first key-value pair in a mapping object, or returns 0 otherwise. The function never returns negative values.

Function: int qsmm_iter_test_eq (qsmm_iter_t iter1, qsmm_iter_t iter2)

This function returns a positive value if iterators iter1 and iter2 address the same location in a mapping object, or returns 0 otherwise. The function never returns negative values.

Function: void qsmm_iter_next (qsmm_iter_t iter)

This function makes an iterator iter address the next key-value pair in a mapping object. If the iterator is a forward (normal) iterator, it addresses the next key-value pair in ascending order of keys. If the iterator is a reverse iterator, it addresses the next key-value pair in descending order of keys (i.e. the previous key-value pair in ascending order of keys).

Function: void qsmm_iter_prev (qsmm_iter_t iter)

This function makes an iterator iter address the previous key-value pair in a mapping object. If the iterator is a forward (normal) iterator, it addresses the previous key-value pair in ascending order of keys (i.e. the next key-value pair in descending order of keys). If the iterator is a reverse iterator, it addresses the previous key-value pair in descending order of keys (i.e. the next key-value pair in ascending order of keys).

Function: void qsmm_iter_assign (qsmm_iter_t dst, qsmm_iter_t src)

This function makes an iterator dst address the same location as an iterator src. The function also copies from src to dst the indicator whether an iterator is forward (normal) or reverse one. Either the function qsmm_map_iter_create or the function qsmm_map_multi_iter_create must have created both iterators.

Function: void qsmm_set_iter_val (qsmm_iter_t iter, void *valp)

This function sets to valp the value of a key-value pair addressed by an iterator iter and discards an old value. If values stored in key-value pair objects are untyped pointers, the function sets the untyped pointer equal to valp. If memory blocks of key-value pair objects contain memory blocks of values, and valp is not NULL, the function copies a memory block addressed by valp to the memory block of a value in the key-value pair object. If memory blocks of key-value pair objects contain memory blocks of values, and valp is NULL, the function zeroes the memory block of a value in the key-value pair object.

Function: void * qsmm_get_iter_key (qsmm_iter_t iter)

This function returns the key of a key-value pair addressed by an iterator iter. If keys stored in key-value pair objects are untyped pointers, the function returns such untyped pointer. If memory blocks of key-value pair objects contain memory blocks of keys, the function returns a pointer to the memory block of a key.

Function: void * qsmm_get_iter_val (qsmm_iter_t iter)

This function returns the value of a key-value pair addressed by an iterator iter. If values stored in key-value pair objects are untyped pointers, the function returns such untyped pointer. If memory blocks of key-value pair objects contain memory blocks of values, the function returns a pointer to the memory block of a value.


7 Tools

QSMM includes the adaptive top-down parser atd-parser and the adaptive bottom-up parser abu-parser. They learn a deterministic regular expression grammar based on a nondeterministic template grammar with the goal to parse training terminal symbol sequences with a maximum probability.

The adaptive top-down parser and adaptive bottom-up parser use a top-down template grammar—a template regular expression grammar intended for parsing a terminal symbol sequence in the top-down direction. The adaptive bottom-up parser requires obtaining a top-down template grammar from a bottom-up template grammar—a template regular expression grammar intended for parsing a terminal symbol sequence in the bottom-up direction. To convert a bottom-up template grammar to a top-down template grammar, you use the rege-markup-cfg tool for marking up source PCFG productions in the bottom-up template grammar and the rege-bottom-up tool for converting the bottom-up template grammar containing a markup of source PCFG productions to the top-down template grammar.

Designing a bottom-up template grammar for parsing entire parse units might be a non-trivial task, as parsing a root nonterminal symbol might terminate before the end of a parse unit. The rege-vit tool helps cope with this problem by creating a factored PCFG for parsing terminal symbol sequences up to specified length as full parse units. To obtain a factored top-down template grammar, take a bottom-up template grammar with a markup of source PCFG productions generated by rege-markup-cfg, process the grammar by rege-vit, and pass the output to rege-bottom-up.

The pcfg-generate-seq tool generates a pseudo-random terminal symbol sequence according to a specified PCFG. The pcfg-predict-eval tool might help evaluate the quality of prediction of symbols in a terminal symbol sequence generated according to a specified PCFG.


7.1 Top-Down Template Grammar

A top-down template grammar can consist of the following elements:

  • productions;
  • nonterminal symbol copying assignments;
  • terminal symbol class assignments.

Every production defines a nonterminal symbol located at its left-hand side. A nonterminal symbol at the left-hand side of the first production in the grammar is a start nonterminal symbol. The grammar must contain at least one production.

On passing the option --viterbi to the adaptive bottom-up parser abu-parser, it expects for the name of a start nonterminal symbol to contain a stem name and parse unit length counted in terminal symbols (see Nonterminal Symbols, for more information on this parse unit length specification). In this case, start nonterminal symbols are all nonterminal symbols with this stem name. The bottom-up parser selects a particular start nonterminal symbol based on the length of a particular parse unit.

Nonterminal symbols defined by productions and copying assignments are visible in right-hand sides of all productions. Nonterminal symbols in right-hand sides of copying assignments require prior definition by productions or copying assignments. Named terminal symbol classes in right-hand sides of productions and right-hand sides of terminal symbol class assignments require definition by preceding terminal symbol class assignments.

The grammar can contain end-of-line comments starting with ‘//’ and comments enclosed in ‘/*’ and ‘*/’.


7.1.1 Terminal Symbols

Terminal symbols are string literals enclosed in double quotes, for example: "a", "Beta", "foo bar", "2+x". The character ‘\’ escapes the characters ‘\’ and ‘"’ in string literals.

Terminal symbols fall into three following categories.

  1. Input terminal symbols. A top-down template grammar consumes them from a parse unit or training terminal symbol sequence.
  2. Put-back terminal symbols. A top-down template grammar analyzes them without consumption from a parse unit or training terminal symbol sequence.
  3. Output terminal symbols. A parser prepends them to unprocessed part of a parse unit or training terminal symbol sequence for subsequent consumption or analysis by input or put-back terminal symbols.

The adaptive top-down parser atd-parser on passing the option --eos-marker and the adaptive bottom-up parser abu-parser support the special terminal symbol

$$

for the end-of-stream marker. It can be an input or, preferably, a put-back terminal symbol. For abu-parser, or on passing the option --input-parse-units to atd-parser, a top-down template grammar consumes terminal symbols $$ after consuming all terminal symbols from a parse unit. Without passing --input-parse-units to atd-parser, a top-down template grammar consumes terminal symbols $$ after consuming all terminal symbols from a training terminal symbol sequence.

A top-down template grammar is template one in the sense that it makes it possible to specify terminal symbol placeholders and classes matching multiple terminal symbols for consumption or analysis as one input or put-back terminal symbol.

The terminal symbol placeholder

.

matches any terminal symbol. A terminal symbol class specified inside ‘[’ and ‘]’ matches a terminal symbol belonging to the class.

A parser treats a sequence of input or put-back terminal symbols, terminal symbol placeholders, and terminal symbol classes as a single unit. For example, the sequence

"at" . . . .

is the template for a sequence consisting of five terminal symbols and beginning with the terminal symbol "at".

Use ‘(’ and ‘)’ to split a template sequence into smaller units. For example

( "at" . ) ( . . . )

denotes two units, where the first unit is a sequence consisting of two terminal symbols and beginning with the terminal symbol "at", and the second unit is a sequence consisting of three terminal symbols.

Note: it is generally preferable to use longer sequences of terminal symbols, terminal symbol placeholders, and terminal symbol classes, as longer sequences capture more relations between terminal symbols.

To give a name to a sequence of input or put-back terminal symbols, terminal symbol placeholders, and terminal symbol classes, prepend the name followed by ‘:’ to the sequence. The sequence becomes a named terminal symbol segment. Multiple terminal symbol segments located in various productions of a grammar can have the same name on condition that the terminal symbol segments have the same length counted in terminal symbols. See Named Segments, for more information.

Not all terminal symbols and terminal symbol classes specified in production right-hand sides restrict terminal symbols to consume or analyze. If a terminal symbol or terminal symbol class does not take part in selecting the next production subexpression to execute, a parser interprets the terminal symbol or terminal symbol class as the terminal symbol placeholder ‘.’.

For example, the sequence

"at" . "in" . .

might or might not restrict the first terminal symbol to be "at", but it never restricts the third terminal symbol to be "in". A parser interprets "in" as ‘.’ there, and "in" suggests a terminal symbol at that position for a grammar developer.


7.1.1.1 Input

A sequence of input terminal symbols, terminal symbol placeholders, and terminal symbol classes is such a sequence not put inside ‘[’ … ‘]’ and ‘<’ … ‘>’ and not followed by ‘~’. While processing the sequence, a parser consumes corresponding terminal symbols from a parse unit or training terminal symbol sequence.

Example

(before reading the sequence)

The sequence of input terminal symbols and terminal symbol placeholders in a grammar:

"a" . . . .

The remaining part of training terminal symbol sequence:

a b c d e f g h

(after reading the sequence)

The read instance of the sequence:

"a" "b" "c" "d" "e"

The remaining part of training terminal symbol sequence:

f g h

The adaptive top-down parser atd-parser on passing the option --eos-marker and the adaptive bottom-up parser abu-parser supply the end-of-stream marker $$ as a terminal symbol consumed after the end of a parse unit or training terminal symbol sequence.

Example

(before reading the sequence)

The sequence of input terminal symbols and terminal symbol placeholders in a grammar:

"a" . . . .

The remaining part of parse unit:

a aa aaa

(after reading the sequence)

The read instance of the sequence:

"a" "aa" "aaa" $$ $$

The remaining part of parse unit is empty.


7.1.1.2 Put-Back

A sequence of put-back terminal symbols, terminal symbol placeholders, and terminal symbol classes is such a sequence followed by ‘~’. While processing the sequence, a parser does not consume corresponding terminal symbols from a parse unit or training terminal symbol sequence.

Example

(before reading the sequence)

The sequence of put-back terminal symbols and terminal symbol placeholders in a grammar:

"a" . . . .~

The remaining part of training terminal symbol sequence:

a b c d e f g h

(after reading the sequence)

The read instance of the sequence:

"a" "b" "c" "d" "e"~

The remaining part of training terminal symbol sequence:

a b c d e f g h

Note: in a bottom-up template grammar, the notation ‘"a" . . . .~’ means that the terminal symbol sequence ‘"a" . . .’ is the input one, and only the last terminal symbol placeholder .~ is the put-back one.


7.1.1.3 Output

An output terminal symbol is a terminal symbol enclosed in ‘<’ and ‘>’. A parser prepends an output terminal symbol to remaining part of a parse unit or training terminal symbol sequence. On processing a sequence of output terminal symbols, a parser prepends them to remaining part of a parse unit or training terminal symbol sequence in reverse order. The end-of-stream marker $$ cannot be an output terminal symbol.

Example

The sequence of output terminal symbols in a grammar:

<"abc"> <"def"> <"ghi">

The remaining part of training terminal symbol sequence before processing the sequence of output terminal symbols:

a b c d e f g h

The remaining part of training terminal symbol sequence after processing the sequence of output terminal symbols:

ghi def abc a b c d e f g h

7.1.1.4 Classes

A terminal symbol class is a specification of a set of terminal symbols enclosed in ‘[’ and ‘]’.

An empty terminal symbol class

[ ]

specifies an empty set of terminal symbols.

Note: an empty terminal symbol class [ ] put at the beginning of a branch prevents transferring control to it.

An inclusive terminal symbol class specifies a set of allowed terminal symbols inside ‘[’ and ‘]’. Example: [ "one" "two" "three" ].

The adaptive top-down parser atd-parser on passing the option --eos-marker and the adaptive bottom-up parser abu-parser support specifying the end-of-stream marker $$ as an allowed terminal symbol. Example: [ $$ "one" "two" "three" ].

An inclusive terminal symbol class can encompass a set of named terminal symbol classes previously defined using terminal symbol class expressions (see Symbol Class Expressions). To specify that an inclusive terminal symbol class additionally includes all terminal symbols from a named terminal symbol class TCLAS, put :TCLAS: inside ‘[’ and ‘]’. Example: [ :letters: "one" "two" "three" :arrows: ].

An exclusive terminal symbol class specifies a set of disallowed terminal symbols inside ‘[^’ and ‘]’.

Example

[^ "one" "two" "three" ]

If the set of terminal symbols in the grammar and training terminal symbol sequence is

one two three four five six seven eight nine

the above terminal symbol class contains the terminal symbols

four five six seven eight nine

The adaptive top-down parser atd-parser on passing the option --eos-marker and the adaptive bottom-up parser abu-parser implicitly add the end-of-stream marker $$ to a set of terminal symbols contained in the grammar and training terminal symbol sequences.

In this case, the above terminal symbol class [^ "one" "two" "three" ] will contain the terminal symbols

$$ four five six seven eight nine

To prevent adding the end-of-stream marker to a set of terminal symbols defined by an exclusive terminal symbol class, add $$ to a set of terminal symbols inside ‘[^’ and ‘]’. Example: [^ $$ "one" "two" "three" ].

An exclusive terminal symbol class can exclude terminal symbols contained in named terminal symbol classes previously defined using terminal symbol class expressions (see Symbol Class Expressions). To specify that an exclusive terminal symbol class additionally excludes all terminal symbols contained in a named terminal symbol class TCLAS, put :TCLAS: inside ‘[^’ and ‘]’. Example: [^ $$ :nonterminals: :errors: ].


7.1.1.5 Named Segments

A named terminal symbol segment is a name followed by ‘:’ followed by a sequence of terminal symbols, terminal symbol placeholders, and terminal symbol classes. The name can contain digits, English letters, and ‘_’ and must begin with an English letter or ‘_’.

Example:

response_a: . . . .

The name can serve for descriptive purposes or for the identification of a sequence of terminal symbols, terminal symbol placeholders, and terminal symbol classes in a grammar.

Alternatively, the name can serve as the left-hand side of PCFG productions for read instances of named terminal symbol segments. Using the name as the left-hand side makes sense when multiple named terminal symbol segments have the same name. Multiple named terminal symbol segments can have the same name if they have the same length counted in terminal symbols.

Example

A grammar contains the named terminal symbol segment

position: "above" . .

in one production and the named terminal symbol segment

position: "below" . .

in another production.

Suppose that while parsing a training terminal symbol sequence, the first named terminal symbol segment consumed the two terminal symbol sequences

above the line
above the circle

and the second named terminal symbol segment consumed the two terminal symbol sequences

below the plane
below the sphere

A PCFG generated for the parsed terminal symbol sequence would contain the following definition of the nonterminal symbol:

position: "above" "the" "line"
        | "above" "the" "circle"
        | "below" "the" "plane"
        | "below" "the" "sphere"
;

Note: a bottom-up template grammar uses named terminal symbol segments to associate nonterminal symbols of a source PCFG with sequences of terminal symbols, terminal symbol placeholders, and terminal symbol classes. The productions of a source PCFG with the nonterminal symbols at the left-hand side have terminal symbol sequences at the right-hand side.


7.1.2 Nonterminal Symbols

Nonterminal symbols are names of grammar productions. If a nonterminal symbol is at the left-hand side of a production, the nonterminal symbol does name the production. If a nonterminal symbol is in the right-hand side of a production, the nonterminal symbol means expanding a nested production named by the nonterminal symbol.

Simple nonterminal symbols are unquoted strings that can consist of digits, English letters, and ‘_’ and must begin with an English letter or ‘_’. Examples: START, C25, Function_A. Simple nonterminal symbols that begin with ‘_’ are for internal use by QSMM tools.

On passing the option --viterbi to the adaptive bottom-up parser abu-parser, it supports simple and compound nonterminal symbols. A compound nonterminal symbol consists of a simple nonterminal symbol and length concatenated by ‘/’:

NAME/LENGTH

Here LENGTH is the expected number of terminal symbols in a terminal symbol subsequence parsed by the compound nonterminal symbol. Examples: START/2, START/10.

Note: bottom-up template grammar supports extended syntax for compound nonterminal symbols, where they can include a context name; see Compound Nonterminal Symbols, for more information.

A start nonterminal symbol is a nonterminal symbol at the left-hand side of a top-level production for consuming the entire parse unit or segment of a training terminal symbol sequence. If the first production in a grammar has a simple nonterminal symbol at the left-hand side, the simple nonterminal symbol is a single start nonterminal symbol in the grammar.

On passing the option --viterbi to abu-parser, the first production in a grammar must have a compound nonterminal symbol StartName/… at the left-hand side, and all compound nonterminal symbols StartName/… are start nonterminal symbols. If ParseUnitLength is the number of terminal symbols in a training parse unit, the parser selects a compound nonterminal symbol StartName/ParseUnitLength as a start nonterminal symbol.


7.1.3 Productions

A grammar production has the form

LHS: RHS ;

where the left-hand side LHS contains a nonterminal symbol, and the right-hand side RHS is an expression for the nonterminal symbol similar to a regular expression.

Every production in a grammar must contain a unique nonterminal symbol at the left-hand side.

A nonterminal symbol defined at the left-hand side of a production in a grammar is available for referencing in right-hand sides of all productions in the grammar.

The right-hand side of a production can contain:

  • Sequences of terminal symbols, terminal symbol placeholders, terminal symbol classes, nonterminal symbols, specifiers beginning with ‘#’ (see Specifiers), and expressions grouped by ‘(’ … ‘)
  • Alternatives separated by ‘|
  • Loops defined using the quantifier ‘*
  • Reverse order sequences for analyzing a look-ahead terminal symbol by the last sequence element rather than the first sequence element

The adaptive bottom-up parser abu-parser without passing the option --viterbi and the adaptive top-down parser atd-parser use a simple nonterminal symbol at the left-hand side of the first production in a grammar as its start nonterminal symbol.

Example

In the grammar

S: . . A B A B ;
A: . ;
B: . . ;

the nonterminal symbol S is the start one.

On passing the option --viterbi to abu-parser, it uses a simple nonterminal symbol contained in a compound nonterminal symbol located at the left-hand side of the first production to determine a set of start nonterminal symbols. The parser selects a particular start nonterminal symbol based on the length of a training parse unit counted in terminal symbols.

Example

In the grammar

S/6: . . A A ;
  A: . . ;
S/3: . . . ;
S/4: A A ;

the start nonterminal symbols are S/3, S/4, and S/6. For processing the parse unit

a b c d

the parser selects the start nonterminal symbol S/4.


7.1.3.1 Left-Hand Side

The left-hand side of a production contains a nonterminal symbol and, for the adaptive top-down parser atd-parser, optionally, a spur update mode specifier #su… (see Switching Spur Update Mode). The nonterminal symbol does name the production and must not occur at left-hand sides of copying assignments and other productions.

Note: bottom-up template grammars support including in production left-hand sides a marker #l-… indicating a nonterminal symbol at the left-hand side of a production of a source PCFG; see Marking a Left-Hand Side, for more information about this marker.

On calling the adaptive bottom-up parser abu-parser without passing the option --viterbi or on calling the adaptive top-down parser atd-parser, a nonterminal symbol at a production left-hand side must be a simple nonterminal symbol.

Example

AB: ... ;

On calling abu-parser with passing the option --viterbi, if a nonterminal symbol at a production left-hand side is a start nonterminal symbol, it must be compound one, otherwise it can be simple or compound one.

Example

START/1: ... ;

A spur update mode specifier #su… at the left-hand side of a production sets its initial spur update mode to “enabled” or “disabled”. As default initial spur update mode is “enabled”, it only makes sense to set initial spur update mode to “disabled” by the spur update mode specifier #su0, if necessary.

Example

AB #su0: ... ;

7.1.3.2 Sequences and Groupings

A sequence consists of elements usually separated by space or newline characters. A sequence element can be:

  • An input sequence where each element can be a terminal symbol, terminal symbol placeholder, or terminal symbol class. See Input. The input sequence can be a named terminal symbol segment.
  • A put-back sequence where each element can be a terminal symbol, terminal symbol placeholder, or terminal symbol class. See Put-Back. The put-back sequence can be a named terminal symbol segment.
  • An output terminal symbol. See Output.
  • A nonterminal symbol defined anywhere in the grammar by a production or copying assignment. See Nonterminal Symbols.
  • A specifier. See Specifiers.
  • An expression grouped by ‘(’ … ‘)’.

Use ‘(’ … ‘)’ to group elements into a single unit. You can use ‘(’ … ‘)’ to group:

  • sequence elements;
  • sets of alternatives separated by ‘|’;
  • loop bodies quantified by ‘*’;
  • optional expression bodies quantified by ‘?’.

A grouped expression provides context for the specifiers #su… and #d. They do not affect expressions outside of a group ( … ) containing the specifiers. See Switching Spur Update Mode and Deferring a Terminal Symbol, for more information on the specifiers.


7.1.3.3 Alternatives

Use ‘|’ to separate alternative expressions. On transferring control to a set of alternative expressions, a parser filters alternative expressions with FIRST sets containing a look-ahead terminal symbol and selects one of filtered expressions.

Example

S: [ "a" "b" ] .    // 1st
 | [ "b" "c" ] . .  // 2nd
 | "c" . . .        // 3rd
;

On the look-ahead terminal symbol "a", a parser selects the first expression. On the look-ahead terminal symbol "b", a parser selects the first or second expression. On the look-ahead terminal symbol "c", a parser selects the second or third expression. Processing every expression begins with consuming a just analyzed look-ahead terminal symbol.

In the above example, the selection of an alternative on the look-ahead terminal symbol "a" is deterministic, and the selection of an alternative on the look-ahead terminal symbol "b" or "c" is nondeterministic.

Note: in a bottom-up template grammar, the parser may select an alternative based on subsequent terminal symbols in a parse unit or training terminal symbol sequence rather than analyze the first look-ahead terminal symbol only.

As a result of iterative determinization, a parser removes terminal symbols from overlapping terminal symbol classes defining FIRST sets of the alternatives but preserves a set of terminal symbols in the union of the FIRST sets.

A parser can determinize the production from the above example in the following ways:

S: "a" .
 | "b" . .
 | "c" . . .
;

or

S: [ "a" "b" ] .
 | "c" . . .
;

or

S: "a" .
 | [ "b" "c" ] . .
;

On nondeterministic choice, a parser selects each applicable alternative with equal profile probability. Use a notation

[RelativeProbability]

at the beginning of an alternative to specify its custom relative profile probability. Examples: [2], [1.5], [0.25].

Note: in the general case, using precise default or custom profile probabilities requires calling a parser with the option --profile-tol=FLOAT where FLOAT is small enough.

If at least one alternative begins with a relative profile probability specification, all other alternatives must begin with relative profile probability specifications too.

Example

S: [0.50] [ "a" "b" ] .
 | [0.25] [ "b" "c" ] . .
 | [0.25] "c" . . .
;

An expression quantified by ‘?

( EXPRESSION )?

is equivalent to

( | EXPRESSION )

If an expression is not inside ‘(’ … ‘)’, the quantifier ‘?’ after the expression relates to its last element. For example, in the expression ‘. . A B?’ the quantifier ‘?’ relates only to ‘B’.

Note: if the quantifier ‘?’ follows a sequence of input terminal symbols, terminal symbol placeholders, and terminal symbol classes, a quantified expression is the entire sequence rather than its last element. For example, the notation ‘. . [ "a" "Beta" ]?’ means that the quantified expression is ‘. . [ "a" "Beta" ]’. To relate ‘?’ only to [ "a" "Beta" ], use the notation ‘. . ([ "a" "Beta" ]?)’ or ‘. . ([ "a" "Beta" ])?’.

If the FIRST set of an EXPRESSION and the FIRST set of a location just after a construct ‘( EXPRESSION )?’ or ‘( | EXPRESSION )’ overlap, avoid using the construct to prevent unstable determinization. Instead, use the construct

( #su0 .~ | EXPRESSION )

See Switching Spur Update Mode, for the description of #su0 specifier.

Note: this construct (without #su0) has a different meaning in a bottom-up template grammar.


7.1.3.4 Loops

To repeatedly execute an expression, quantify it by ‘*’.

Example

( [ "a" "b" ] . A )* [ "b" "c" ] . .

A parser repeats the execution of ‘[ "a" "b" ] . A’ expression while a look-ahead terminal symbol is "a" and stops repeating the execution if a look-ahead terminal symbol is "c". If a look-ahead terminal symbol is "b", the parser either repeats the execution of that expression or stops repeating the execution.

In the above example, a choice whether to continue or stop repeating expression execution is deterministic on the look-ahead terminal symbol "a" or "c" and nondeterministic on the look-ahead terminal symbol "b".

Note: in a bottom-up template grammar, the parser may choose whether or not to repeat an expression quantified by ‘*’ based on subsequent terminal symbols consumable by the expression or an expression following the quantifier ‘*’.

If an expression is not inside ‘(’ … ‘)’, the quantifier ‘*’ after the expression relates to its last element. For example, in the expression ‘. . A B*’ the quantifier ‘*’ relates only to ‘B’.

Note: if the quantifier ‘*’ follows a sequence of input terminal symbols, terminal symbol placeholders, and terminal symbol classes, a quantified expression is the entire sequence rather than its last element. For example, the notation ‘. . [ "a" "Beta" ]*’ means that the quantified expression is ‘. . [ "a" "Beta" ]’. To relate ‘*’ only to [ "a" "Beta" ], use the notation ‘. . ([ "a" "Beta" ]*)’ or ‘. . ([ "a" "Beta" ])*’.

As a result of iterative determinization, a parser removes terminal symbols from overlapping terminal symbol classes defining the FIRST set of an expression quantified by ‘*’ and the FIRST set of an expression after the quantifier ‘*’ but preserves a set of terminal symbols in the union of the two FIRST sets.

A parser can determinize the expression from the above example in the following ways:

( [ "a" "b" ] . A )* "c" . .

or

( "a" . A )* [ "b" "c" ] . .

On nondeterministic choice between repeating the execution of an expression and stopping the execution, a parser selects one of the two alternatives with profile probability 0.5. Use a notation

[Probability]

at the beginning of an expression quantified by ‘*’ to specify a custom profile probability of repeating the execution. The probability of stopping the execution is equal to 1-Probability.

Example

( [0.25] [ "a" "b" ] . A )* [ "b" "c" ] . .

On the look-ahead terminal symbol "b", a parser executes the expression ‘[ "a" "b" ] . A’ with profile probability 0.25 or executes the expression ‘[ "b" "c" ] . .’ with profile probability 0.75.

Note: using a custom profile probability of repeating the execution of an expression quantified by ‘*’ requires calling a parser with the option --profile-tol=FLOAT where FLOAT is small enough; otherwise, specifying the custom profile probability will not have any effect.


7.1.3.5 Reverse Order Sequences

A reverse order sequence is a sequence with a FIRST set determined by the last element of the sequence. In the notation of a reverse order sequence, its last element goes first:

ElementN <- ... <- Element2 <- Element1

The operator ‘<-’ has greater precedence compared to the operator ‘|’.

A reverse order sequence is a means of parsing a nonterminal symbol sequence defined by a bottom-up template grammar. This parsing involves the use of #d specifier described in Deferring a Terminal Symbol.

In a top-down template grammar, to the nonterminal symbol sequence there corresponds a terminal symbol sequence consisting of virtual nonterminal symbols—terminal symbols with names consisting of ‘_’ followed by a nonterminal symbol name. A set of alternatives represented by reverse order sequences for parsing a set of alternatives represented by nonterminal symbol sequences defined by a bottom-up template grammar has the form:

  C ( VN1,1 VN1,2 ... VN1,m1 <- #d C1,2 #d ... Cm1 #d
    | VN2,1 VN2,2 ... VN2,m2 <- #d C2,2 #d ... Cm2 #d
    | ...
    | VNn,1 VNn,2 ... VNn,mn <- #d Cn,2 #d ... Cmn #d
    )

Here a nonterminal symbol C outputs a virtual nonterminal symbol belonging to a virtual nonterminal symbol class VN1,1, VN2,1, …, or VNn,1. A parser selects an alternative i matching the virtual nonterminal symbol and executes an expression #d Ci,2 #d … Cmi #d at the right-hand side of ‘<-’. The specifier #d at the beginning of that right-hand side defers the virtual nonterminal symbol until finishing processing the right-hand side. A nonterminal symbol Ci,2 outputs the second virtual nonterminal symbol deferred by the second #d. The parser repeats calling nonterminal symbols and deferring output virtual nonterminal symbols until finishing processing a nonterminal symbol Cmi and #d at the end of the right-hand side. After that, the parser converts a sequence of deferred virtual nonterminal symbols to a sequence of input virtual nonterminal symbols consumed by an expression VNi,1 VNi,2VNi,mi at the left-hand side of ‘<-’.

Example

To the bottom-up template grammar

S: A A
 | B B C
 | C B B
;

A: "a" . ;
B: "b" . ;
C: "c" . ;

there corresponds the top-down template grammar

S: C1 ( "_A" "_A" <- #d C2 #d
      | "_B" "_B" "_C" <- #d C3 #d C4 #d
      | "_C" "_B" "_B" <- #d C3 #d C3 #d
      )
;

C1: "%a" . < "_A" >
  | "%b" . < "_B" >
  | "%c" . < "_C" >
;

C2: "%a" . < "_A" > ;
C3: "%b" . < "_B" > ;
C4: "%c" . < "_C" > ;

The terminal symbols "%a", "%b", and "%c" are virtual terminal symbols for the terminal symbols "a", "b", and "c" in the bottom-up template grammar. The terminal symbols "_A", "_B", and "_C" are virtual nonterminal symbols for the nonterminal symbols A, B, and C in the bottom-up template grammar.


7.1.3.6 Inserting Assembler Code [Experimental]

A template grammar can contain assembler code insertions enclosed in ‘{’ and ‘}’, for example:

A: . { push_random
       set_random  true } ( { pop_random } .
                          | { pop_random } . .
                          | { pop_random } . . .
                          )
;

Note: processing a template grammar with assembler code insertions usually requires changing parser source code to define corresponding instruction meta-classes and register corresponding instruction classes in the instruction class set (for push_random, set_random, and pop_random in the above example).


7.1.4 Specifiers

Specifiers are strings beginning with the character ‘#’. They perform additional operations in grammar productions or supply extra meaning to them.

Top-down template grammars support the following specifiers.

#su…

A spur update mode switch. Only the adaptive top-down parser atd-parser supports this specifier.

#d

An operator for deferring an input terminal symbol.

#pt-…

A marker for the end of a PCFG production with terminal symbols at the right-hand side. Only the adaptive bottom-up parser abu-parser supports this specifier.

#pn-…

A marker for the end of a PCFG production with nonterminal symbols at the right-hand side. Only the adaptive bottom-up parser abu-parser supports this specifier.

The rege-markup-cfg tool marks up PCFG productions in a bottom-up template grammar for subsequent conversion to a top-down template grammar by the rege-bottom-up tool.

The specifiers #su… and #d use the context of a sequence or grouping.


7.1.4.1 Switching Spur Update Mode

Only the adaptive top-down parser atd-parser supports specifiers for spur update mode switching. The following spur update modes are available:

Enabled

The parser updates spur when leading out PCFG productions with terminal symbols or nonterminal symbols at the right-hand side. The specifier

#su

(without the following ‘0’) sets this mode. This is default spur update mode.

Disabled

The parser does not update spur when leading out PCFG productions with terminal symbols at the right-hand side. The parser still updates spur when leading out PCFG productions with nonterminal symbols at the right-hand side. The specifier

#su0

sets this mode.

The specifiers #su and #su0 have the scope of a grouping: they do not affect spur update mode outside of an expression ‘(’ … ‘)’ containing the specifiers.

The specifier #su or #su0 in a production right-hand side changes current spur update mode, that is, spur update mode for subsequent elements in a sequence or grouping until the next specifier #su or #su0 in the sequence or grouping. If a sequence element is a grouping, current spur update mode propagates to the grouping, that is, it becomes initial spur update mode for the grouping.

Example

To disable updating spur on processing a put-back sequence, put #su0 before the put-back sequence and optionally put #su after it:

#su0 .~ | . . .

The specifier #su or #su0 can follow a nonterminal symbol at a production left-hand side for setting initial spur update mode for the right-hand side. As default spur update mode is “enabled”, it only makes sense to put the specifier #su0 in the left-hand side for switching initial spur update mode to “disabled”.


7.1.4.2 Deferring a Terminal Symbol

The specifier #d is an operator that consumes a terminal symbol and prepends it to remaining part of a parse unit or training terminal symbol sequence at the end of processing a sequence or grouping containing the operator. If a sequence or grouping contains multiple #d operators, terminal symbols prepended to remaining part of a parse unit or training terminal symbol sequence are in the order of consuming the terminal symbols by the #d operators.

Example

(before processing the expression)

The expression in a grammar:

( #d . . . . #d . . )

The remaining part of training terminal symbol sequence:

a b c d e f g h i j

(after processing the expression)

The read instance of the expression:

( #d "b" "c" "d" "e" #d "g" "h" )

The remaining part of training terminal symbol sequence:

a f i j

The #d operator is normally required at the beginning of an expression at the right-hand side of ‘<-’ operator to defer a look-ahead terminal symbol for subsequent consuming by the left-hand side of ‘<-’. See Reverse Order Sequences, for more information and an example.


7.1.4.3 Ending a Terminal Production

Only the adaptive bottom-up parser abu-parser supports a specifier for marking the end of a production with terminal symbols at its right-hand side. The specifier has the format

#pt-NonterminalSymbol

where NonterminalSymbol is a nonterminal symbol at the left-hand side of a production from a source PCFG. NonterminalSymbol is a string that can consist of digits, English letters, and ‘_’.

At the beginning of processing a regular expression of a nonterminal symbol in a top-down template grammar, the parser clears a list of terminal symbols at the right-hand side of a production from a source PCFG. While processing the regular expression, the parser appends consumed source terminal symbols to the list. On encountering a #pt-NonterminalSymbol specifier, the parser registers a production from a source PCFG and clears the list. The left-hand side of the production is a NonterminalSymbol, and the right-hand side of the production is source terminal symbols from the list.

Source terminal symbols are virtual terminal symbols with a stripped prefix STR specified by the option --term-prefix=STR. The prefix distinguishes virtual terminal symbols from virtual nonterminal symbols. The default prefix is ‘%’.

Example

A grammar contains the production:

C0: "%a" "%b" ( #pt-t1a "%c" "%d" #pt-t1b ...
              | #pt-t2a "%e" "%f" #pt-t2b ...
              )
;

After processing the sequence of virtual terminal symbols ‘%a %b %c %d’, the parser registers the source productions:

t1a: "a" "b" ;
t1b: "c" "d" ;

After processing the sequence of virtual terminal symbols ‘%a %b %e %f’, the parser registers the source productions:

t2a: "a" "b" ;
t2b: "e" "f" ;

7.1.4.4 Ending a Nonterminal Production

Only the adaptive bottom-up parser abu-parser supports a specifier for marking the end of a production with nonterminal symbols at its right-hand side. The specifier has the format

#pn-NonterminalSymbol-RightHandSide

where NonterminalSymbol is a nonterminal symbol at the left-hand side of a production from a source PCFG, and RightHandSide is a non-negative index that identifies a right-hand side defined in a source PCFG for the nonterminal symbol. NonterminalSymbol is a string that can consist of digits, English letters, and ‘_’.

On encountering a #pn-… specifier, the parser registers an occurrence of a corresponding production from a source PCFG.

Example

Suppose a source PCFG contains this definition of the nonterminal symbol S:

S: B B
 | A B C
 | C B A
;

The right-hand side ‘B B’ has index 0, the right-hand side ‘A B C’ has index 1, and the right-hand side ‘C B A’ has index 2.

A definition of a nonterminal symbol in a top-down template grammar for parsing the source nonterminal symbol S may look like this:

C0: C1 ( ("_A" "_B" "_C" <- #d C2 #d C3 #d) #pn-S-1 < "_S" >
       | ("_B" "_B" <- #d C2 #d) #pn-S-0 < "_S" >
       | ("_C" "_B" "_A" <- #d C2 #d C4 #d) #pn-S-2 < "_S" >
       )
;

The specifiers #pn-S-0, #pn-S-1, and #pn-S-2 let the parser know about the completion of parsing the corresponding productions from the source PCFG.


7.1.5 Symbol Class Expressions

Top-down template grammars and bottom-up template grammars can contain symbol class expressions. A symbol class expression defines a named terminal symbol class or named nonterminal symbol class. See Classes, for how to specify named terminal symbol classes as part of inclusive terminal symbol classes or exclusive terminal symbol classes.

Note: only bottom-up template grammars support nonterminal symbol classes. See Nonterminal Symbol Classes, for more information.

A symbol class expression has the format

:NAME: = EXPRESSION ;

where NAME is the name of a symbol class to define, and EXPRESSION specifies the content of the symbol class. NAME is a sequence of English letters, digits, and the characters ‘_’ starting with an English letter or ‘_’.

For terminal symbol classes, EXPRESSION can be:

  • The terminal symbol placeholder:
    :all: = . ;
    
  • An inclusive terminal symbol class:
      :single: = [ "zero" ] ;
    :multiple: = [ "one" "two" "three" $$ ] ;
       :vnont: = [ :c0: :c1: :c2: "_ER" ] ;
    
  • An exclusive terminal symbol class:
    :vterm: = [^ :vnont: ] ;
    
  • Another named terminal symbol class:
    :any: = :all: ;
    

For nonterminal symbol classes, EXPRESSION can be:

  • An (inclusive) nonterminal symbol class:
    :Level1: = [ L1_0 L1_1 L1_2 L1_3 :W: ] ;
    
  • A named nonterminal symbol class:
    :LevelLast: = :Level3: ;
    

EXPRESSION can be a set theory operation on symbol classes, where ‘(’ … ‘)’ enclose subexpressions:

  • The operator ‘&’ delimits symbol classes in an intersection.

    Example 1

    :selected_a: = [ "aa" "bb" "cc" "dd" ] ;
    :selected_b: = [ "ff" "ee" "dd" "cc" ] ;
    :selected_c: = [ "cc" "ee" "dd" ] ;
        :common: = :selected_a: & :selected_b: & :selected_c: ;
    

    The terminal symbol class :common: is [ "cc" "dd" ].

    Example 2

    AA: ... ;
    BB: ... ;
    CC: ... ;
    DD: ... ;
    EE: ... ;
    FF: ... ;
    
    :SelectedA: = [ AA BB CC DD ] ;
    :SelectedB: = [ FF EE DD CC ] ;
    :SelectedC: = [ CC EE DD ] ;
       :Common: = :SelectedA: & :SelectedB: & :SelectedC: ;
    

    The nonterminal symbol class :Common: is [ CC DD ].

  • The operator ‘|’ delimits symbol classes in a union:
    :expected: = ( :selected_a: | :selected_b: ) & :allowed: ;
    

    This notation is equivalent to:

    :expected: = [ :selected_a: :selected_b: ] & :allowed: ;
    
  • The operator ‘-’ delimits symbol classes in a difference:

    Example

    :all_vterm: = [ $$ "aa" "bb" "cc" ] ;
       :no_eos: = :all_vterm: - [ $$ ] ;
    

    The terminal symbol class :no_eos: is [ "aa" "bb" "cc" ].

  • The operator ‘^’ delimits symbol classes in a symmetric difference:

    Example

      :left: = [ "aa" "bb" "cc" ] ;
     :right: = [ "ab" "cc" "aa" "dd" ] ;
    :unique: = :left: ^ :right: ;
    

    The terminal symbol class :unique: is [ "ab" "bb" "dd" ].

For terminal symbol classes, EXPRESSION can contain the operator ‘~’ denoting a complement:

:other: = ~( :selected_a: | :selected_b: ) ;

This notation is equivalent to:

:other: = [^ :selected_a: :selected_b: ] ;

If EXPRESSION references named symbol classes, a grammar must contain their definitions earlier in its text. If EXPRESSION references nonterminal symbols (in nonterminal symbol classes), a grammar can contain their definitions anywhere in its text.

To define a named nonterminal symbol class as a deep copy of a nonterminal symbol class expression, use the operator ‘=*=’ instead of ‘=’:

:NonterminalSymbolClassName: =*= NonterminalSymbolClassExpression ;

The operator ‘=*=’ creates a deep copy of each nonterminal symbol of a nonterminal symbol class specified by NonterminalSymbolClassExpression. See Cloning Nonterminal Symbols, for details on the deep copying process. New nonterminal symbols have unique names to distinguish them from source nonterminal symbols. A named nonterminal symbol class NonterminalSymbolClassName consists of the new nonterminal symbols.


7.1.6 Cloning Nonterminal Symbols

A nonterminal symbol assignment using ‘=’ creates a shallow copy of a nonterminal symbol:

NewNonterminalSymbol = ExistingNonterminalSymbol ;

This assignment is equivalent to defining a nonterminal symbol NewNonterminalSymbol with the right-hand side of a nonterminal symbol ExistingNonterminalSymbol. The grammar must contain the definition of ExistingNonterminalSymbol earlier in its text.

Example

The grammar fragment

A: "c" B
 | C C
;

E = A ;

is equivalent to the fragment

A: "c" B
 | C C
;

E: "c" B
 | C C
;

A nonterminal symbol assignment using ‘=*=’ creates a deep copy of a nonterminal symbol:

NewNonterminalSymbol =*= ExistingNonterminalSymbol ;

The grammar must contain the definition of ExistingNonterminalSymbol earlier in its text.

The deep copy operation first collects a set of nonterminal symbols in a right-hand side defined for ExistingNonterminalSymbol and right-hand sides of all nonterminal symbols referenced from the right-hand side recursively. For every nonterminal symbol in the set, the operation generates a unique nonterminal symbol name by appending a suffix ‘__NUMBER’ to a source nonterminal symbol name or changing an already existing suffix. The operation then defines right-hand sides for the new nonterminal symbols as right-hand sides of corresponding source nonterminal symbols with changing all nonterminal symbols in the right-hand sides to corresponding new nonterminal symbols.

Example

In the grammar

S: A E ;

A: . B
 | C C
;

B: C D D ;
C: . D ;

D: . B
 | .
;

E =*= A ;

the assignment ‘E =*= A ;’ is equivalent to the productions

E: . B__0
 | C__0 C__0
;

B__0: C__0 D__0 D__0 ;
C__0: . D__0 ;

D__0: . B__0
    | .
;

Adding the assignment ‘F =*= A ;’ or ‘F =*= E ;’ is equivalent to adding the productions

F: . B__1
 | C__1 C__1
;

B__1: C__1 D__1 D__1 ;
C__1: . D__1 ;

D__1: . B__1
    | .
;

7.1.7 Restrictions for Bottom-Up Parsing

When supplying a top-down template grammar to the adaptive bottom-up parser abu-parser, it performs basic consistency checks for the grammar:

  1. All leaves of right-hand sides of non-start nonterminal symbols must be output terminal symbols.

    Example

    The following top-down template grammar is valid for parsing by abu-parser:

    :n: = [ "__ER" "__START" "_S" ] ;
    
    START: C "__START" ;
    
    
    
    C: C0 ( "_S" < "__START" >
          | "__ER" [^ :n: ] #pt-__er_consume < "__START" >
          )
    ;
    
    
    
    C0: "%a" ( "%b" #pt-_S_1T2 #pn-S-0 < "_S" >
             | "%c" "%d" #pt-_S_2T3 #pn-S-1 < "_S" >
             | #pt-__er [^ "%b" "%c" :n: ]~ #pn-__ER-0 < "__ER" >
             )
      | "%b" "%c" "%d" #pt-_S_3T3 #pn-S-2 < "_S" >
      | [^ "%a" "%b" :n: ]~ #pn-__ER-0 < "__ER" >
    ;
    

    The right-hand side of the nonterminal symbol C0 has the output terminal symbol leaves < "_S" > and < "__ER" >. The right-hand side of the nonterminal symbol C has the output terminal symbol leaves < "__START" >.

    The right-hand side of the nonterminal symbol START does not have an output terminal symbol leaf—that nonterminal symbol is the start one (i.e. the first nonterminal symbol defined in the grammar).

  2. Every input terminal symbol class in right-hand sides of non-start nonterminal symbols must conform to one condition among the following conditions:
    • The input terminal symbol class is empty.
    • The input terminal symbol class contains only virtual terminal symbols and/or the end-of-stream marker $$. Virtual terminal symbols are terminal symbols that have a prefix specified by the option --term-prefix=STR. The default prefix is ‘%’.
    • The input terminal symbol class contains only virtual nonterminal symbols. They are terminal symbols that do not have a prefix specified by the option --term-prefix=STR. The default prefix is ‘%’.

    Example 1

    Provided the terminal symbol prefix is ‘%’, the input terminal symbol class

    [ "%a" "%b" "%c" "_A" "_B" $$ ]
    

    is invalid for parsing by abu-parser.

    Valid input terminal symbol classes can be:

    [ "%a" "%b" "%c" $$ ]
    [ "_A" "_B" ]
    

    Example 2

    Provided the terminal symbol prefix is ‘%’, the input terminal symbol class

    [^ "_C" "_D" ]
    

    is valid for parsing by abu-parser if a set of terminal symbols defined by a grammar and input terminal symbol sequence is

    $$ "%e" "%f" "_C" "_D"
    

    However, that input terminal symbol class is invalid for parsing by abu-parser if a set of terminal symbols defined by a grammar and input terminal symbol sequence is

    $$ "%e" "%f" "_C" "_D" "_E"
    

    because, in this case, the input terminal symbol class contains the virtual terminal symbols ‘%e’ and ‘%f’ (along with $$) and the virtual nonterminal symbol ‘_E’.

  3. Every put-back terminal symbol class in right-hand sides of non-start nonterminal symbols must be empty or contain virtual terminal symbols and/or $$.

    Example

    Provided the terminal symbol prefix is ‘%’, the put-back terminal symbol class

    [ "%a" "%b" "%c" "_A" "_B" $$ ]~
    

    is invalid for parsing by abu-parser.

    A valid put-back terminal symbol class can be

    [ "%a" "%b" "%c" $$ ]~
    
  4. All virtual terminal symbol sequences led out by right-hand sides of non-start nonterminal symbols must terminate with #pt-… markers. See Ending a Terminal Production, for more information on #pt-… markers.

    Example

    Provided the terminal symbol prefix is ‘%’, the production

    C0: C1 ( "_A" "%e" "%e" #pt-_S_1T2 #pn-S-0 < "_S" >
           | "_B" "%f" "%f" #pn-S-1 < "_S" >
           | "_C" #pn-S-2 < "_S" >
           )
    ;
    

    is invalid for parsing by abu-parser because the virtual terminal symbol sequence "%f" "%f" does not end with a #pt-… marker.


7.2 Bottom-Up Template Grammar

A bottom-up template grammar has the format of a top-down template grammar (see Top-Down Template Grammar) with a number of differences described in this section.

The main semantic difference between a top-down template grammar and bottom-up template grammar is the following: a top-down template grammar selects an execution alternative from a subset of execution alternatives with FIRST sets containing a look-ahead terminal symbol, whereas a bottom-up template grammar allows for delayed selection of an execution alternative based on terminal symbols consumed while an execution alternative was indeterminate.

Example

Consider the grammar

S: "a" "b" "c"
 | "a" "b" "d" . .
;

If this is a top-down template grammar, it cannot deterministically select the alternative ‘"a" "b" "c"’ or ‘"a" "b" "d" . .’, because they both start with the same terminal symbol "a". If this is a bottom-up template grammar, it can deterministically select one of the alternatives after processing their common prefix ‘"a" "b"’.

A bottom-up template grammar can have an associated source PCFG with productions inferred from the productions of the bottom-up template grammar. Named terminal symbol segments can mark the productions of a source PCFG with terminal symbols at the right-hand side (see Named Segments). The specifiers #l-… and #r… mark the productions of a source PCFG with nonterminal symbols at the right-hand side (see Marking a Left-Hand Side and Marking a Right-Hand Side).

The adaptive bottom-up parser abu-parser cannot use a bottom-up template grammar directly. A bottom-up template grammar requires conversion to a top-down template grammar for using by abu-parser. If a bottom-up template grammar contains a source PCFG markup, the conversion preserves source PCFG information. The conversion typically involves the following steps:

  1. Adding a source PCFG production markup to the bottom-up template grammar by the rege-markup-cfg tool. See rege-markup-cfg, for more information.
  2. Converting a bottom-up template grammar with a source PCFG production markup to a factored PCFG by the rege-vit tool for the ability to process entire parse units up to specified length. See rege-vit, for more information. This is an optional step.
  3. Converting the factored PCFG or a bottom-up template grammar with a source PCFG production markup to a top-down template grammar by the rege-bottom-up tool. See rege-bottom-up, for more information. The adaptive bottom-up parser abu-parser can use the top-down template grammar.

Example

If the file bu.rg contains a bottom-up template grammar (e.g. from the previous example), the commands

$ rege-markup-cfg -o bu-markup.rg bu.rg
$ rege-bottom-up -o td.rg --cfg-markup bu-markup.rg

create the file td.rg that contains a top-down template grammar for using by abu-parser.


7.2.1 Production Left-Hand Side

The left-hand side of a production of a bottom-up template grammar contains a nonterminal symbol and, optionally, an #l-… marker for specifying a nonterminal symbol at the left-hand side of a corresponding production in a source PCFG. The former nonterminal symbol can be a compound one (see Compound Nonterminal Symbols).

Example

S #l-S: RHS ;

Here a nonterminal symbol of a bottom-up template grammar and a nonterminal symbol of a source PCFG are the same nonterminal symbol S.

The rege-markup-cfg tool typically adds #l-… markers to a bottom-up template grammar. See Marking a Left-Hand Side, for more information on #l-… markers.

If a nonterminal symbol at the left-hand side of the first production of a bottom-up template grammar does not have a length specification, the rege-bottom-up tool considers the nonterminal symbol the start one.

If a nonterminal symbol at the left-hand side of the first production of a bottom-up template grammar has a length specification, rege-bottom-up determines a stem nonterminal symbol name by removing the length specification and treats all nonterminal symbols with the stem name as start ones. A particular start nonterminal symbol for processing a parse unit has length equal to the length of the parse unit measured in terminal symbols.

Example

If a bottom-up template grammar begins with productions

S/3 #l-S: RHS1 ;
S/5 #l-S: RHS2 ;
S/9 #l-S: RHS3 ;

and a parse unit consists of 5 terminal symbols, the nonterminal symbol S/5 will be a start nonterminal symbol for processing the parse unit.


7.2.2 Compound Nonterminal Symbols

Nonterminal symbols of a bottom-up template grammar have the forms:

STEM
STEM/LENGTH
STEM-CONTEXT
STEM-CONTEXT/LENGTH

The above forms use the notations listed below.

STEM

A stem nonterminal symbol name. It is a sequence of English letters, digits, and the characters ‘_’ starting with an English letter or ‘_’. Examples: S, Expr10, COPY__2. Stem names that begin with ‘_’ are for internal use by QSMM tools. A source PCFG learned by the adaptive bottom-up parser abu-parser uses stem names as nonterminal symbols.

CONTEXT

A context within a stem nonterminal symbol name. The context is a sequence of English letters, digits, and the characters ‘_’. The examples of a stem nonterminal symbol name followed by a context are H-15 and CombinedExpr-subgram2.

A stem nonterminal symbol name, its context, and length (see below) make up a nonterminal symbol name used for testing the equality of nonterminal symbols to find matching productions while parsing.

Nonterminal symbols in a source PCFG learned by abu-parser do not include contexts. For this reason, contexts do not take part in calculating parse probabilities of training parse units.

LENGTH

Expected length of a terminal symbol sequence parsed by a nonterminal symbol. The parser does not check whether actual length of a terminal symbol sequence is equal to its expected length. The examples of nonterminal symbol length specification are START/12, A-17/9, and BinaryOp-domA/10.

A stem nonterminal symbol name, its context, and length make up a nonterminal symbol name used for testing the equality of nonterminal symbols to find matching productions while parsing.

Nonterminal symbols in a source PCFG learned by abu-parser do not include length specifications.


7.2.3 Nonterminal Symbol Classes

A bottom-up template grammar can contain nonterminal symbol classes. They are similar to terminal symbol classes with the following differences:

  1. Nonterminal symbol classes can only be inclusive ones.
  2. The grammar must contain definitions of nonterminal symbols belonging to nonterminal symbol classes.

Nonterminal symbol classes can take part in symbol class expressions. See Symbol Class Expressions, for more information.

Example 1

[ A B C3 D ]

This is a nonterminal symbol class containing the nonterminal symbols A, B, C3, and D. The grammar should contain their definitions anywhere in its text using productions of the form

 A: ... ;
 B: ... ;
C3: ... ;
 D: ... ;

Example 2

[ L2_0 L2_1 :L1: :W: ]

This is a nonterminal symbol class containing the nonterminal symbols L2_0 and L2_1 and the named nonterminal symbol classes L1 and W. The grammar must contain definitions of the named nonterminal symbol classes earlier in its text.

A bottom-up template grammar can contain nonterminal symbol classes instead of ordinary nonterminal symbols in production right-hand sides.

Example

S: [ A B ] [ C D ]
 | [:W:] [:W:] [:W:]
;

7.2.4 Specifiers

A bottom-up template grammar can contain the following specifiers:

#l-…

A marker for the left-hand side of a production of a source PCFG. The production has nonterminal symbols at the right-hand side.

#r…

A marker for the right-hand side of a production of a source PCFG. The production has nonterminal symbols at the right-hand side.

#d

An operator for deferring an input terminal symbol for use in special cases.

The specifiers #l-… and #r… are for use in a bottom-up template grammar only. The rege-markup-cfg tool adds them to a bottom-up template grammar. The rege-bottom-up tool converts them to #pn-… specifiers in a top-down template grammar.


7.2.4.1 Marking a Left-Hand Side

The #l-… specifier marks the left-hand side of a production of a source PCFG. The production has nonterminal symbols at the right-hand side.

The specifier has the format:

#l-NonterminalSymbolOfSourcePCFG

where NonterminalSymbolOfSourcePCFG is the name of a nonterminal symbol at the left-hand side of a production of a source PCFG. That name is a sequence of English letters, digits, and the characters ‘_’.

There are a few kinds of places where inserting a #l-… specifier is necessary:

  1. At the left-hand side of a production of a bottom-up template grammar.

    Example

    A/10 #l-A: B/3 C/3 D/4 ... ;
    

    The #l-A specifier here sets A as a nonterminal symbol at the left-hand side of a source PCFG production for the expression ‘B/3 C/3 D/4’. The source PCFG production might have the form

    A: B C D ... ;
    
  2. Before ‘(’ … ‘)’ containing a set of alternatives separated by ‘|’.

    Example

    A #l-A: B C D #l-_A_1C ( E ...
                           | F ...
                           | G ...
                           ) ...
    ;
    

    The #l-_A_1C specifier here sets _A_1C as a nonterminal symbol at the left-hand side of source PCFG productions for the expression ‘E … | F … | G …’. The source PCFG productions might have the form

    _A_1C: E ...
         | F ...
         | G ...
    ;
    

    If the right-hand side of a nonterminal symbol of a bottom-up template grammar is a set of alternatives separated by ‘|’, an #l-… specifier just after the nonterminal symbol contains a source nonterminal symbol at the left-hand side of source PCFG productions separated by ‘|’.

    Example

    A #l-A: E ...
          | F ...
          | G ...
    ;
    

    The #l-A specifier here sets A as a nonterminal symbol at the left-hand side of source PCFG productions for the expression ‘E … | F … | G …’. The source PCFG productions might have the form

    A: E ...
     | F ...
     | G ...
    ;
    
  3. At the beginning of a subexpression quantified by ‘*’.

    Example

    S #l-S: B C ( #l-_S_1A D ... )* ...
    

    The #l-_S_1A specifier here sets _S_1A as a nonterminal symbol at the left-hand side of a source PCFG production for a repeatable expression ‘D …’. The source PCFG production might have the form

    _S_1A: D ... ;
    

7.2.4.2 Marking a Right-Hand Side

The #r… specifier marks a right-hand side of a production of a source PCFG. The right-hand side consists of nonterminal symbols.

The specifier has the format:

#rIndexOfRightHandSide

where IndexOfRightHandSide is a non-negative integer number. It is the identifier of a right-hand side of a nonterminal symbol in a source PCFG.

There are a few kinds of places where inserting an #r… specifier is necessary:

  1. At the end of the right-hand side of a production in a bottom-up template grammar if that right-hand side is not a set of alternatives separated by ‘|’.

    Example

    A #l-A: B C D #r0 ;
    
  2. At the end of each alternative in a set of alternatives separated by ‘|’.

    Example 1

    A #l-A: E #r2
          | F F #r0
          | G G G #r1
    ;
    

    The source PCFG productions might have the form

    A: F F
     | G G G
     | E
    ;
    

    Example 2

    A #l-A: B C D #l-_A_1C ( F F #r1
                           | G G G #r2
                           | E #r0
                           ) ...
    ;
    

    The source PCFG productions for the nonterminal symbol _A_1C might have the form

    _A_1C: E
         | F F
         | G G G
    ;
    
  3. At the end of a subexpression quantified by ‘*’.

    Example

    S #l-S: B C ( #l-_S_1A D D #r0 )* ...
    

7.2.5 Error Nonterminal Symbol

A bottom-up template grammar can contain the special nonterminal symbol error in production right-hand sides. That nonterminal symbol represents a parse error. The nonterminal symbol makes it possible to change the flow of grammar execution on encountering a parse error. The selection of an error nonterminal symbol to handle a parse error must be deterministic.

Note: bottom-up template grammars containing the error nonterminal symbol are for direct processing by the rege-bottom-up tool after optional adding to them a source PCFG production markup by the rege-markup-cfg tool with passing the option --error-nont. The rege-vit tool ignores the error nonterminal symbol.

Example 1

S: A
 | B
 | C
 | error .
;

A: "a" ;

B: "b" "c"
 | "b" "d"
;

C: "c" "c" "c" ;

This grammar consumes any terminal symbol if a training terminal symbol sequence does not start with the terminal symbol "a", "b", and "c" or if a training terminal symbol sequence starts with the terminal symbol "b" not followed by the terminal symbol "c" or "d".

Example 2

S: "a" ( "b"
       | error . .
       )? "c"
;

This grammar is equivalent to the grammar

S: "a" ( "b"
       | [^ "b" "c" ] .
       )? "c"
;

Example 3

S: A* ( error [^ "d" ]* )? "d" ;

A: "a" "b"
 | "a" "c"
;

Normally, this grammar consumes any number of elements ‘( "a" "b" | "a" "c" )’ finalized by "d". If an element does not start with "a" or starts with "a" not followed by "b" or "c" or if a sequence of ‘( "a" "b" | "a" "c" )’ does not end with "d", the grammar consumes terminal symbols until encountering "d".


7.3 PCFG Format

The pcfg-generate-seq and pcfg-predict-eval tools take a PCFG (Probabilistic Context-Free Grammar) for processing. Some other tools can generate PCFGs, if requested.

Example

This is a PCFG:

S: "a"              [0.5]
 | "b" "b"          [0.33]
 | "c" "c" "c" D_1  [0.17]
;

D_1: "delta"
   | "delta" D_1
;

Nonterminal symbols are (unquoted) sequences of English letters, digits, and the characters ‘_’ starting with an English letter or ‘_’. In the above example, the nonterminal symbols are S and D_1.

Terminal symbols are character sequences quoted using single or double quotation marks. Use the escape character ‘\’ to insert a single or double quotation mark or ‘\’ into a terminal symbol. In the above example, the terminal symbols are ‘a’, ‘b’, ‘c’, and ‘delta’.

Every set of right-hand sides of productions for a nonterminal symbol at the left-hand side starts with the nonterminal symbol followed by the character ‘:’ and ends with the character ‘;’. A nonterminal symbol at the left-hand side of the first production in a PCFG is its start nonterminal symbol.

The characters ‘|’ can delimit right-hand sides of productions with the same nonterminal symbol at their left-hand side. The productions can also be separate ones each ending with ‘;’.

A production can have relative probability specified in square brackets after its right-hand side before ‘|’ or ‘;’. The default relative probability is 1.

Example

The notation

S: "a"              [0.5]  
 | "b" "b"          [0.33]
 | "c" "c" "c" D_1  [0.17]
;

is equivalent to

S: "a"              [0.5]  ;
S: "b" "b"          [0.33] ;
S: "c" "c" "c" D_1  [0.17] ;

7.4 atd-parser

This program is a probabilistic adaptive top-down parser. It processes a training terminal symbol sequence from left to right multiple times to synthesize a grammar based on a template grammar (see Top-Down Template Grammar). A training terminal symbol sequence usually consists of parse units immediately following one another, where each parse unit corresponds to an expansion of start nonterminal symbol of a top-down template grammar. The synthesis method is iterative determinization of top-down template grammar.

The parser internally generates adaptive assembler routines for nonterminal symbols of a top-down template grammar. The assembler routines parse terminal symbol sequences for the nonterminal symbols and increment frequencies of productions of a PCFG for the top-down template grammar. Changing production frequencies results in changing spur. An assembler routine can call other assembler routines for nested nonterminal symbols. See Assembler Instruction Set for the description of an instruction set used in the assembler routines. See Assembler Program Structure for the description of their building blocks.

See mk-rg-vit.sh for the description of a script that generates a top-down template grammar for dividing a text into words. The top-down template grammar provides one-level segmenting a terminal symbol sequence for probabilistic parsing.


7.4.1 Examples

This subsection contains the examples of learning simple grammars for dividing terminal symbol sequences into words. The examples use grammar files located in the directory $prefix/share/qsmm/samples/gram (installed from the directory samples/gram in the package distribution) and auxiliary programs described in pcfg-generate-seq and mk-rg-vit.sh.

To reproduce the examples, execute the following preparation commands in a temporary directory:

$ mkdir seq log td-templ td-learn
$ prefix=/usr  # use a different prefix, if necessary 

Continue by executing commands for the examples below.

Example 1

$ cat "$prefix/share/qsmm/samples/gram/3.pcfg"

  S: A B
  ;
  
  A: "a" "b" "c"
   | "d" "c" "b" "a"
  ;

  B: "e"
   | "f" "e"
  ;

$ pcfg-generate-seq -i1 -n2000 -o seq/3-2k.seq "$prefix/share/qsmm/samples/gram/3.pcfg"
$ mk-rg-vit.sh 6 6 2 >td-templ/3.rg

$ atd-parser -i1 -n20000 --det-niter-goal=50 --od=td-learn/3_det.rg  \
             --oo=log/3.log td-templ/3.rg seq/3-2k.seq

$ atd-parser -i1 --op=td-learn/3_out.pcfg --oo          \
             --simplify td-learn/3_det.rg seq/3-2k.seq

  [0]: p_td 0.70731857, p_rd 1.00000000, p_wp 0.81804014, p_np 0.79479479, cp 0

$ cat td-learn/3_out.pcfg

  S: "d" "c" "b" "a" L2_1  [0.51629073]  // 206
   | "a" "b" "c" L3_1      [0.48370927]  // 193
  ;  // 399

  L2_1: "f" "e"  [0.47572816]  // 98   0.75
      | "e"      [0.52427184]  // 108  0.63533835
  ;  // 206

  L3_1: "f" "e"  [0.50777202]  // 98  0.75
      | "e"      [0.49222798]  // 95  0.61904762
  ;  // 193

Example 2

$ cat "$prefix/share/qsmm/samples/gram/5.pcfg"

  S: B C
   | B C C
   | D C B
   | D D C
  ;
  
  B: "a" "a"
  ;
  
  C: "c" "b" "c"
  ;
  
  D: "d" "b" "b" "d"
  ;

$ pcfg-generate-seq -i1 -n10000 -o seq/5-10k.seq "$prefix/share/qsmm/samples/gram/5.pcfg"
$ mk-rg-vit.sh 5 5 3 2 >td-templ/5.rg

$ atd-parser -i1 --det-niter-goal=50 --od=td-learn/5_det.rg  \
             --oo=log/5.log td-templ/5.rg seq/5-10k.seq

$ atd-parser -i1 --op=td-learn/5_out.pcfg --oo           \
             --simplify td-learn/5_det.rg seq/5-10k.seq

  [0]: p_td 0.58834791, p_rd 1.00000000, p_wp 0.82003105, p_np 0.81757230, cp 0

$ cat td-learn/5_out.pcfg

  S: "a"              [0.42766108]  // 1812  1
   | "c" "b" "c"      [0.35850838]  // 1519  1
   | "d" "b" "b" "d"  [0.21383054]  // 906   1
  ;  // 4237

Example 3

$ cat "$prefix/share/qsmm/samples/gram/6.pcfg"

  S: B C
   | B D D
   | B E E E
  ;
  
  B: "a" "b"
   | "b" "b"
  ;
  
  C: "a" "c"
   | "c" "c"
  ;
  
  D: "a" "d"
   | "d" "d"
  ;

  E: "a" "e"
   | "e" "e"
  ;

$ pcfg-generate-seq -i1 -n40000 -o seq/6-40k.seq "$prefix/share/qsmm/samples/gram/6.pcfg"
$ cat "$prefix/share/qsmm/samples/gram/6.rg"

  S: ( . .
     | . .
     ) ( . .
       | . . ( . . | . . )
       | . . ( . . | . . ) ( . . | . . )
       | . ( .
           | . ( . . | . . )
           | . ( . . | . . ) ( . . | . . )
           )
       )
  ;

$ atd-parser -i1 -n80000 --det-niter-goal=50 --od=td-learn/6_det.rg               \
             --oo=log/6.log "$prefix/share/qsmm/samples/gram/6.rg" seq/6-40k.seq

$ atd-parser -i1 --or=td-learn/6_resi.rg --oo td-learn/6_det.rg seq/6-40k.seq

  [0]: p_td 0.67223945, p_rd 0.96721932, p_wp 0.70524366, p_np 0.69389439, cp 108

$ cat td-learn/6_resi.rg

  S: ( "b" "b"
     | "a" "b"
     ) ( "a" ( "c"
             | "d" ( "d" "d"
                   | "a" "d"
                   )
             | "e" ( "e" "e"
                   | "a" "e"
                   ) ( "e" "e"
                     | "a" "e"
                     )
             )
       | "d" "d" ( "a" "d"
                 | "d" "d"
                 )
       | "e" "e" ( "e" "e"
                 | "a" "e"
                 ) ( "a" "e"
                   | "e" "e"
                   )
       | "c" "c"
       )
  ;

Example 4

$ cat "$prefix/share/qsmm/samples/gram/9.pcfg"

  S: "l" "a" "z" "y"
   | "f" "o" "x"
   | "f" "o" "x" "y"
  ;

$ pcfg-generate-seq -i1 -n5000 -o seq/9-5k.seq "$prefix/share/qsmm/samples/gram/9.pcfg"
$ mk-rg-vit.sh 5 5 3 2 >td-templ/9.rg

$ atd-parser -i1 --det-niter-goal=50 --od=td-learn/9_det.rg  \
             --oo=log/9.log td-templ/9.rg seq/9-5k.seq

$ atd-parser -i1 --op=td-learn/9_out.pcfg --oo          \
             --simplify td-learn/9_det.rg seq/9-5k.seq

  [0]: p_td 0.56923116, p_rd 0.77034971, p_wp 0.84928628, p_np 0.84733894, cp 25

$ cat td-learn/9_out.pcfg

  S: "y" "f" "o" "x"  [0.33406917]  // 454  0.96864589
   | "f" "o" "x"      [0.32303164]  // 439  0.73741149
   | "y" "l" "a" "z"  [0.15820456]  // 215  0.50772377
   | "l" "a" "z" "y"  [0.18469463]  // 251
  ;  // 1359

Example 5

$ cat "$prefix/share/qsmm/samples/gram/10.pcfg"

  S: "c" "i" "l" "i"
   | "c" "i" "r" "c"
   | "c" "i" "t" "i"
   | "l" "i" "b" "e"
   | "l" "i" "f" "e"
   | "l" "i" "v" "e"
   | "v" "i" "l" "l"
   | "v" "i" "r" "u"
   | "v" "i" "v" "o"
  ;

$ pcfg-generate-seq -i1 -n40000 -o seq/10-40k.seq "$prefix/share/qsmm/samples/gram/10.pcfg"
$ mk-rg-vit.sh 5 5 3 2 >td-templ/10.rg

$ atd-parser -i1 -n80000 --det-niter-goal=50 --od=td-learn/10_det.rg  \
             --oo=log/10.log td-templ/10.rg seq/10-40k.seq

$ atd-parser -i1 --op=td-learn/10_out.pcfg --oo            \
             --simplify td-learn/10_det.rg seq/10-40k.seq

  [0]: p_td 0.55845396, p_rd 0.82352984, p_wp 0.67576938, p_np 0.66497500, cp 48

$ cat td-learn/10_out.pcfg

S: "c" "i" "t" "i"  [0.1132]  // 1132  0.67919697
 | "c" "i" "l" "i"  [0.1121]  // 1121  0.67233259
 | "c" "i" "r" "c"  [0.108]   // 1080  0.64847044
 | "l" "i" L3_2     [0.3334]  // 3334
 | "v" "i" L3_0     [0.3333]  // 3333
;  // 10000

L3_0: "v" "o"  [0.3360336]   // 1120  1
    | "r" "u"  [0.33183318]  // 1106  1
    | "l" "l"  [0.33213321]  // 1107
;  // 3333

L3_2: "f" "e"  [0.34523095]  // 1151  1
    | "v" "e"  [0.33023395]  // 1101  1
    | "b" "e"  [0.32453509]  // 1082
;  // 3334

Example 6

$ cat "$prefix/share/qsmm/samples/gram/12.pcfg"

  W: "h" "e" A    [0.67]
   | "d"          [0.20]
   | "i" "k" "j"  [0.13]
  ;
  
  A: "e" "h" "j" [0.67]
   | "c"         [0.33]
  ;

$ pcfg-generate-seq -i1 -n10000 -o seq/12-10k.seq "$prefix/share/qsmm/samples/gram/12.pcfg"
$ mk-rg-vit.sh 5 5 3 2 >td-templ/12.rg

$ atd-parser -i1 --det-niter-goal=50 --od=td-learn/12_det.rg  \
             --oo=log/12.log td-templ/12.rg seq/12-10k.seq

$ atd-parser -i1 --op=td-learn/12_out.pcfg --oo            \
             --simplify td-learn/12_det.rg seq/12-10k.seq

  [0]: p_td 0.68237916, p_rd 1.00000000, p_wp 0.84284780, p_np 0.84216843, cp 0

$ cat td-learn/12_out.pcfg

  S: "d"           [0.18908451]  // 537   1
   | "i" "k" "j"   [0.13485915]  // 383   1
   | "h" "e" L3_0  [0.67605634]  // 1920
  ;  // 2840

  L3_0: "e" "h" "j"  [0.66458333]  // 1276  1
      | "c"          [0.33541667]  // 644   1
  ;  // 1920

Example 7

$ cat "$prefix/share/qsmm/samples/gram/13.pcfg"

  S: "b" "i" "g"
   | "b" "l" "o" "c" "k"
   | "c" "a" "n"
   | "c" "i" "t" "y"
   | "f" "l" "a" "t" "s"
   | "l" "i" "v" "e"
   | "o" "f"
   | "o" "r"
   | "p" "l" "a" "c" "e"
  ;

$ pcfg-generate-seq -i1 -n200000 -o seq/13-200k.seq            \
                    "$prefix/share/qsmm/samples/gram/13.pcfg"

$ mk-rg-vit.sh 5 5 6 2 >td-templ/13.rg

$ atd-parser -i1 --det-niter-goal=50 --od=td-learn/13_det.rg  \
             --oo=log/13.log td-templ/13.rg seq/13-200k.seq

$ atd-parser -i1 --op=td-learn/13_out.pcfg --oo             \
             --simplify td-learn/13_det.rg seq/13-200k.seq

  [0]: p_td 0.36151913, p_rd 0.70814220, p_wp 0.66418539, p_np 0.66117331, cp 49

$ cat td-learn/13_out.pcfg

  S: "f" "l" "a" "t" "s"  [0.10183488]  // 6166   1
   | "l" "i" "v" "e"      [0.10039802]  // 6079   1
   | "p" "l" "a" "c" "e"  [0.10029893]  // 6073   1
   | "y"                  [0.10021635]  // 6068   1
   | "c" "i" "t"          [0.10021635]  // 6068   0.75748802
   | "o" "f"              [0.1010091]   // 6116   0.75675161
   | "o" "r"              [0.09831707]  // 5953   0.74324839
   | "c" "a" "n"          [0.09823449]  // 5948   0.74251198
   | _S_8T2 L3_3          [0.19947481]  // 12078
  ;  // 60549

  L3_3: "g"          [0.50322901]  // 6078  1
      | "o" "c" "k"  [0.49677099]  // 6000  1
  ;  // 12078

  _S_8T2: "b" "i"  [0.50322901]  // 6078  0.75322888
        | "b" "l"  [0.49677099]  // 6000  0.74677112
  ;  // 12078

Example 8

$ cat "$prefix/share/qsmm/samples/gram/14.pcfg"

  S: "a"
   | "b" "i" "g"
   | "c" "a" "n"
   | "c" "i" "t" "y"
   | "i" "f"
   | "i" "n"
   | "i" "s"
   | "l" "i" "v" "e"
   | "o" "f"
   | "o" "r"
   | "t" "h" "e"
   | "t" "h" "e" "n"
   | "y" "o" "u"
  ;

$ pcfg-generate-seq -i1 -n500000 -o seq/14-500k.seq            \
                    "$prefix/share/qsmm/samples/gram/14.pcfg"

$ mk-rg-vit.sh 4 4 5 3 2 >td-templ/14.rg

$ atd-parser -i1 --det-niter-goal=50 --od=td-learn/14_det.rg  \
             --oo=log/14.log td-templ/14.rg seq/14-500k.seq

$ atd-parser -i1 --op=td-learn/14_out.pcfg --oo             \
             --simplify td-learn/14_det.rg seq/14-500k.seq

  [0]: p_td 0.39224628, p_rd 0.86458056, p_wp 0.59397760, p_np 0.59276837, cp 53

$ cat td-learn/14_out.pcfg

  S: "t" "h" "e"      [0.14164605]  // 28337  1
   | "l" "i" "v" "e"  [0.07155532]  // 14315  1
   | "y" "o" "u"      [0.07155032]  // 14314  1
   | "b" "i" "g"      [0.07103547]  // 14211  1
   | "o" "r"          [0.07153033]  // 14310  0.75098025
   | "a"              [0.07254505]  // 14513  0.75027592
   | "o" "f"          [0.07125041]  // 14254  0.74901975
   | "n"              [0.07140036]  // 14284  0.66639098
   | "i" L3_1         [0.21334133]  // 42680
   | "c" L3_4         [0.14414536]  // 28837
  ;  // 200055

  L3_1: "s"  [0.33348172]  // 14233  1
      | "f"  [0.33479381]  // 14289  0.50145782
      | "n"  [0.33172446]  // 14158  0.41377197
  ;  // 42680

  L3_4: "a" "n"      [0.50216735]  // 14481  1
      | "i" "t" "y"  [0.49783265]  // 14356  1
  ;  // 28837

7.4.2 Synopsis

To learn a PCFG and residual top-down grammar by iterative determinization of a top-down template grammar, use the commands:

atd-parser -iPOSITIVE_RANDOM_SEED [ -nTRAINING_SEQ_LENGTH ]                         \
           --det-niter-goal=NUMBER_OF_ITERATIONS --od=DETERMINIZED_TD_GRAMMAR_FILE  \
           --oo[=LOG_FILE] INPUT_TD_GRAMMAR_FILE INPUT_SEQ_FILE

atd-parser --op=LEARNED_PCFG_FILE --oo --simplify       \
           DETERMINIZED_TD_GRAMMAR_FILE INPUT_SEQ_FILE

atd-parser --or=RESIDUAL_TD_GRAMMAR_FILE [ --simplify ]  \
           DETERMINIZED_TD_GRAMMAR_FILE INPUT_SEQ_FILE

In the above command line formats:

INPUT_TD_GRAMMAR_FILE

The name of a file containing an input top-down template grammar. See Top-Down Template Grammar, for more information. The filename ‘-’ means stdin.

DETERMINIZED_TD_GRAMMAR_FILE

The name of a file containing a determinized top-down template grammar. The filename ‘-’ means stdin or stdout.

INPUT_SEQ_FILE

The name of a file containing a sequence of terminal symbol names separated by whitespace characters. The filename ‘-’ means stdin.

See Command-Line Options, for descriptions of options and their arguments mentioned in the command line formats.

Parse Statistics Format

On passing the option --oo[=FILE], the parser dumps overall parse statistics or parse statistics for each determinization iteration to a file or stdout.

Overall parse statistics looks like this:

[0]: p_td 0.29952870, p_rd 0.71248166, p_wp 0.56714492, p_np 0.56526226, cp 893

The fields of this line have the following meanings:

[idx]

Top-down template grammar index.

It is possible to supply a list of top-down template grammars to the parser. In this case, the options --predict and --os[=FILE] turn on predicting the next terminal symbols using an ensemble of top-down template grammars, and overall parse statistics contains lines corresponding to each top-down template grammar from the list. After the lines, there goes a line similar to the following one:

p_epredict 0.27998545

The line contains observed probability of a terminal symbol correctly predicted using an ensemble of top-down template grammars.

p_td

The probability of parsing a training terminal symbol sequence by a learned PCFG. It is weighted probability of all productions in the PCFG where weights are production frequencies.

p_rd

Weighted probability of productions with terminal symbols at the right-hand side in a learned PCFG where weights are production frequencies. The probability p_td is weighted probability of p_rd and productions with nonterminal symbols at the right-hand side.

p_wp

The sum of estimated probabilities of terminal symbols correctly predicted in a training terminal symbol sequence divided by sequence length.

p_np

The actual number of terminal symbols correctly predicted in a training terminal symbol sequence divided by sequence length.

cp

Average cycle length counted in terminal symbols consumed from a training terminal symbol sequence. Average cycle length is equal to total length of cycles divided by the number of cycles. A cycle here is parsing the same training terminal symbol subsequence by the same group of terminal symbols, terminal symbol classes, and ‘.’ contained in a top-down template grammar. The parser increments total length of cycles and the number of cycles only if the previous occurrence of that group was parsing a different training terminal symbol subsequence.

Parse statistics for a determinization iteration looks like this:

Iteration 24 of 50 (48.0 %):
P: p_td 0.21248701, p_rd 0.33389827, p_wp 0.67163360, p_np 0.63650000, cp 709
T: p_td 0.09378993, p_rd 0.11626595, p_wp 0.63718393, p_np 0.59475417, cp 728
n_removable_rd 1283, n_removed_rd 48(+6), iter_time 1s

The first line contains the ordinal number of a current iteration, the goal number of iterations, and the percentage of completed iterations. The line beginning with ‘P:’ (“Pass”) contains parse statistics for a current iteration. The line beginning with ‘T:’ (“Total”) contains aggregate parse statistics for last iterations up to a current iteration. The option --det-niter-keep=INT specifies the number of last iterations for aggregating parse statistics. See the table above for the description of fields in the lines beginning with ‘P:’ and ‘T:’.

The fourth line contains the following fields:

n_removable_rd

The number of terminal symbols removable from terminal symbol classes of a top-down template grammar at a current determinization iteration without reducing terminal symbol coverage of the top-down template grammar.

n_removed_rd

The number (less than or equal to n_removable_rd) of terminal symbols actually removed from terminal symbol classes of a top-down template grammar at a current determinization iteration and, in round brackets, the number of implicitly removed terminal symbols. Implicitly removed terminal symbols are unreachable terminal symbols and terminal symbols not present in an input terminal symbol sequence and a set of reachable output terminal symbols.

iter_time

Approximate number of seconds a determinization iteration was executing.

Stack Trace Format

The parser dumps a stack trace on stack overflow or encountering an unexpected terminal symbol.

Example for an Unexpected Terminal Symbol

Using the file unexpect.rg containing the top-down template grammar

S: . A . ;
A: . . ( "a" B | "s" B ) ;
B: . . . ( C | D ) ;
C: "c" . . D ;
D: "d" . ;

to parse the terminal symbol sequence ‘a b c s e f g h i j’ results in the following stack trace:

$ atd-parser unexpect.rg - <<< 'a b c s e f g h i j'
STACK TRACE
#2 [0]  S: . >>> A <<< .
        "a"
#1 [1]  A: . . ("a" B | "s" >>> B <<<)
        "b" "c" "s"
#0 [4]  B: . . . (>>> C | D <<<)
        "e" "f" "g"
Unexpected terminal symbol [7]: "h"

The bottom line of a stack trace indicates an offset (‘[7]’) in a training terminal symbol sequence for an unexpected terminal symbol and indicates the unexpected terminal symbol itself ("h"). The pairs of lines above the bottom line correspond to parse stack frames.

A number after ‘#’ indicates the index of a parse stack frame, where frame ‘#0’ is the current stack frame, frame ‘#1’ is the previous stack frame, and so on. A number in square brackets (e.g. ‘[4]’) after the index of a parse stack frame indicates an offset in a training terminal symbol sequence. The offset corresponds to the beginning of parsing a nonterminal symbol. The nonterminal symbol itself ended with ‘:’ (e.g. ‘B:’) follows the number in square brackets. A regular expression (e.g. ‘. . . (>>> C | D <<<)’) for the nonterminal symbol follows it. In the regular expression, the markers ‘>>>’ and ‘<<<’ indicate a subexpression with a parse error.

The second line in a pair of lines for a parse stack frame lists terminal symbols (e.g. ‘"e" "f" "g"’) consumed while parsing the regular expression before encountering a parse error.

Example for Stack Overflow

Using the file stack_overflow.rg containing the top-down template grammar

S: . A ;
A: . . B ;
B: . . . C ;
C: . . . . A ;

to parse the sequence ‘a b c d e f g h i j k l m n’ with stack size 4 results in the following stack trace:

$ atd-parser --stack-size=4 stack_overflow.rg - <<< 'a b c d e f g h i j k l m n'
STACK OVERFLOW
#3 [0]  S: . >>> A <<<
        "a"
#2 [1]  A: . . >>> B <<<
        "b" "c"
#1 [3]  B: . . . >>> C <<<
        "d" "e" "f"
#0 [6]  C: . . . . >>> A <<<
        "g" "h" "i" "j"
Terminal symbol [10]: "k"

The bottom line of a stack trace indicates an offset (‘[10]’) in a training terminal symbol sequence for a terminal symbol led to creating a new parse stack frame resulted in exceeding the maximum allowed number of parse stack frames. The terminal symbol itself ("k") follows the offset.


7.4.3 Command-Line Options

The adaptive top-down parser atd-parser supports the following command line options:

--det-interim

Create a separate set of output files at each iteration of determinization of a top-down template grammar. The files have the suffix ‘.ITER’, where ITER is an iteration index. By default, the parser overwrites the same output files at each iteration.

--det-niter-goal=INT

The number of determinization iterations to perform. The actual number of iterations cannot exceed the number of terminal symbols removable from a top-down template grammar without reducing its terminal symbol coverage.

--det-niter-keep=INT

The number of last determinization iterations to keep aggregate statistics. If that number is equal to 1, use statistics from the last iteration only. If that number is greater than the number of already performed iterations, keep aggregate statistics for the already performed iterations. The default value is the goal number of iterations.

--det-niter-max=INT

Limit on the number of iterations of determinization of a top-down template grammar. The parser stops on reaching the limit. If that number is less than the goal number of iterations, iterative determinization terminates prematurely. Special value 0 means no limit. The default value is 0.

--det-ratio=FLOAT

Minimum ratio for the number of terminal symbols to attempt to remove from terminal symbol classes at each determinization iteration relative to the number of removable terminal symbols. The default value is 0.

--det-shape=linear|exp

The shape of a function for the number of terminal symbols removable from terminal symbol classes at a given iteration of determinization of a top-down template grammar:

linear

Remove approximately equal numbers of terminal symbols at each iteration.

exp

Remove more terminal symbols at beginning iterations and less terminal symbols at ending iterations.

The default value is ‘linear’.

--eos-marker

Enable the end-of-stream marker $$. It is a special terminal symbol a top-down template grammar consumes after consuming all terminal symbols from a training terminal symbol sequence or current parse unit before finishing parsing a start nonterminal symbol. On omitting this option, the parser stops processing a training terminal symbol sequence or current parse unit on attempting to consume the next terminal symbol from it if there are no more terminal symbols to consume.

--fq-span=window|total

Event history span for output frequencies of PCFG productions and terminal symbol n-grams:

window

Event history window.

total

Entire event history.

The default value is ‘total’.

--input-parse-units

Interpret an input terminal symbol sequence as consisting of parse units separated by empty lines. By default, interpret an input terminal symbol sequence as a single stream of terminal symbols.

--kt=FLOAT

The temperature of the environment state identification engine. The default value is 2.

-N, --npass=INT

The number of training passes. The parser reinitializes the environment state identification engine at each training pass and accumulates PCFG production frequencies for all training passes at a determinization iteration. Using multiple training passes usually requires a shorter training terminal symbol sequence to achieve the same quality of grammar synthesis. Performing multiple training passes in parallel is possible but not implemented. The default value is 1.

-n, --nstep=INT

The length of a training terminal symbol sequence. If an input terminal symbol sequence ends earlier, the parser processes it again from the beginning. For correct repeated processing an input terminal symbol sequence, it should consist of an integer number of parse units, that is, it should end with a complete parse unit. In parse unit mode (see the option --input-parse-units), parsing finishes at a parse unit boundary. By default, the length of a training terminal symbol sequence is equal to the length of an input terminal symbol sequence.

--od[=FILE]

Dump a determinized top-down template grammar to a file or stdout. The grammar does not contain subexpressions starting with empty terminal symbol classes ‘[]’. This option turns on iterative determinization of a top-down template grammar.

--ode[=FILE]

Dump a determinized top-down template grammar to a file or stdout. The grammar can contain subexpressions starting with empty terminal symbol classes ‘[]’. This option turns on iterative determinization of a top-down template grammar.

--oe[=FILE]

Dump terminal symbol expansion sequences for nonterminal symbols of a top-down template grammar to a file or stdout.

--og[=FILE]

Dump an initial context-free grammar to a file or stdout.

--on[=FILE]

Dump terminal symbol n-grams to a file or stdout.

--oo[=FILE]

Dump parse statistics to a file or stdout. See “Parse Statistics Format of Top-Down Parser”, for more information.

--op[=FILE]

Dump a learned PCFG to a file or stdout.

--or[=FILE]

Dump a residual regular expression grammar to a file or stdout.

--os[=FILE]

Dump a combined sequence consisting of pairs of terminal symbols from an actual (training) terminal symbol sequence and predicted terminal symbol sequence to a file or stdout. See pcfg-predict-eval, for the format of a combined sequence. This option turns on terminal symbol prediction mode.

--ot[=FILE]

Dump PCFG parse trees to a file or stdout.

--plain-pcfg

Remove output and put-back terminal symbols from a learned PCFG.

--predict

Predict the next symbol in a training terminal symbol sequence on processing each symbol from it. This option turns on terminal symbol prediction mode.

--profile-tol=FLOAT

Generate output signal choice trees with specified maximum difference between desired profile probabilities of output signals and their actual profile probabilities. Special value 0 means to use Huffman trees as output signal choice trees. The default value is 0.005.

--recurs=left|right

Recursion type for context-free grammars to dump: left or right. The default value is ‘left’.

-i, --seed=INT

A seed for the pseudo-random number generator. A non-negative value switches parser operation to adaptive mode. A negative value switches parser operation to random mode. The default value is 0.

--simplify

Partially simplify a determinized regular expression grammar or residual regular expression grammar or fully simplify a learned PCFG. By default, do not simplify the grammars.

--stack-size=INT

Maximum nesting level of nonterminal symbols of a top-down template grammar while parsing. Parsing aborts on exceeding that level. The default value is 32.

--terse

Use condensed format to dump productions of regular expression grammars. By default, dump the productions in indented format.

--ww=INT

The length (width) of the cycle event history window and grammar event history window counted in terminal symbols. By default, the parser sets and adjusts that length automatically.


7.4.4 Assembler Instruction Set

Assembler programs for adaptive parsing terminal symbol sequences consist of jmp, jprob, and joe built-in instructions, choice instruction blocks, and user instructions described in this subsection.


7.4.4.1 abrt Instruction

This instruction signals a parse error—encountering an unexpected look-ahead terminal symbol. On executing the instruction, the parser aborts processing a training terminal symbol sequence and dumps a parse stack trace for a current expansion of a start nonterminal symbol to help understand the reason of the error. The instruction does not have arguments.


7.4.4.2 call Instruction

This instruction has the syntax

        call    NONT, ORD

The instruction calls an assembler routine for parsing a nonterminal symbol NONT. Execution continues just after the instruction on finishing parsing the nonterminal symbol. The parameter ORD is the ordinal number of an AST node for the nonterminal symbol in an AST for a regular expression. The parser uses that ordinal number to mark a part of the regular expression containing a parse error in a stack trace dumped on executing an abrt instruction.

Example:

        call    A, 2

This instruction calls an assembler routine for parsing the nonterminal symbol A. The AST node of an occurrence of that nonterminal symbol in a regular expression has ordinal number 2.


7.4.4.3 peek Instruction

This instruction has the syntax

        peek    ORD

The instruction fetches a look-ahead terminal symbol from a training terminal symbol sequence and returns an outcome equal to the numeric identifier of the look-ahead terminal symbol. The parameter ORD is the ordinal number of an AST node for a ‘?’ or ‘*’ quantifier or a set of alternatives separated by ‘|’ requiring look-ahead terminal symbol analysis to select a branch for transferring control. The parser uses that ordinal number to mark a regular expression part containing a parse error in a stack trace dumped on executing an abrt instruction.

Example:

        peek    3

This instruction returns the identifier of the next terminal symbol from a training terminal symbol sequence to select a control transfer target for an AST node with ordinal number 3.


7.4.4.4 popdwr Instruction

This instruction has the syntax

        popdwr  NUM

The instruction pops NUM terminal symbols from the stack of deferred terminal symbols and prepends every popped terminal symbol to the beginning of a training terminal symbol sequence, as the wr instruction (see wr Instruction) does. The added terminal symbols become available for fetching by the rd and scn instructions (see rd Instruction and scn Instruction) in the order of pushing the terminal symbols to the stack of deferred terminal symbols by the pushd instructions (see pushd Instruction).

Example:

        popdwr  5

This instruction pops five terminal symbols from the stack of deferred terminal symbols and prepends the popped terminal symbols to the beginning of a training terminal symbol sequence. An rd instruction following the popdwr instruction will read the prepended terminal symbols.


7.4.4.5 prod Instruction

This instruction has the syntax

        prod    NONT_QUOTED, RHS

The instruction increments the frequency of a production in a PCFG corresponding to a regular expression grammar and updates the spur accordingly. The production has a nonterminal symbol NONT_QUOTED specified in double quotation marks at the left-hand side. The production has a right-hand side with zero-based index RHS.

Example:

        prod    "B", 4

This instruction increments the frequency of a PCFG production with the nonterminal symbol B at the left-hand side and the fifth right-hand side for that nonterminal symbol.


7.4.4.6 pushd Instruction

This instruction consumes a terminal symbol from a training terminal symbol sequence and pushes the terminal symbol to the stack of deferred terminal symbols. The popdwr instruction (see popdwr Instruction) pops terminal symbols from the stack of deferred terminal symbols. The pushd instruction does not have arguments.


7.4.4.7 rd Instruction

This instruction has the syntax

        rd      NONT_QUOTED, RHS, POS, LENGTH

The instruction consumes LENGTH symbols from a training terminal symbol sequence, increments the frequency of a PCFG production with an auxiliary nonterminal symbol at the left-hand side and a consumed terminal symbol sequence at the right-hand side, and updates the spur accordingly. The parameters NONT_QUOTED, RHS, and POS identify the auxiliary nonterminal symbol in a right-hand side of a production of a PCFG corresponding to a regular expression grammar.

The parameter NONT_QUOTED is a PCFG nonterminal symbol specified in double quotation marks. The nonterminal symbol is at the left-hand side of a PCFG production containing the auxiliary nonterminal symbol in a right-hand side. The parameter RHS is zero-based index of a right-hand side containing the auxiliary nonterminal symbol. The parameter POS is zero-based position of the auxiliary nonterminal symbol in the right-hand side.

Example:

        rd      "E", 2, 3, 4

This instruction consumes a sequence of four terminal symbols from a training terminal symbol sequence, increments the frequency of a PCFG production for an auxiliary nonterminal symbol at the left-hand side and a consumed terminal symbol sequence at the right-hand side, and updates the spur accordingly. The occurrence of the auxiliary nonterminal symbol is at zero-based position 3 in a right-hand side at zero-based index 2 for the PCFG nonterminal symbol E at the left-hand side. For example, the auxiliary nonterminal symbol could be the symbol _E_2T4 in the following fragment of a context-free grammar:

E: A
 | B
 | _E_1T C C _E_2T4 D
;

7.4.4.8 ret Instruction

This instruction finishes the execution of an assembler routine parsing a nonterminal symbol of a regular expression grammar. If the assembler routine is the topmost routine parsing a start nonterminal symbol, the parser calls the routine again to repeat parsing the start nonterminal symbol for the next parse unit or the remaining part of a training terminal symbol sequence. If the assembler routine is not the topmost one, a caller assembler routine continues parsing a parent nonterminal symbol. The instruction does not have arguments.


7.4.4.9 scn Instruction

This instruction has the syntax

        scn     NONT_QUOTED, RHS, POS, LENGTH

The instruction scans the next terminal symbols in a training terminal symbol sequence and behaves as the rd instruction (see rd Instruction) but does not remove processed terminal symbols from a training terminal symbol sequence.

The parameter LENGTH specifies the number of terminal symbols to scan in a training terminal symbol sequence. The parameters NONT_QUOTED, RHS, and POS identify an occurrence of an auxiliary nonterminal symbol in a PCFG corresponding to a regular expression grammar. The right-hand sides of the auxiliary nonterminal symbol are terminal symbol sequences scanned by the scn instruction.

The parameter NONT_QUOTED is a PCFG nonterminal symbol specified in double quotation marks. The nonterminal symbol is at the left-hand side of a PCFG production containing the auxiliary nonterminal symbol in a right-hand side. The parameter RHS is zero-based index of a right-hand side containing the auxiliary nonterminal symbol. The parameter POS is zero-based position of the auxiliary nonterminal symbol in the right-hand side.


7.4.4.10 wr Instruction

This instruction has the syntaxes

        wr      TERM_IDX
        wr      TERM_IDX, ORD

The instruction prepends a PCFG terminal symbol with index TERM_IDX to the beginning of a training terminal symbol sequence. A subsequent instruction peek (see peek Instruction), rd (see rd Instruction), or scn (see scn Instruction) will read the prepended terminal symbol. If a series of wr instructions outputs multiple terminal symbols, subsequent peek, rd, and scn instructions will read the terminal symbols in reverse order.

The optional parameter ORD specifies the ordinal number of a wr instruction that outputs a particular terminal symbol. Ordinal numbers make it possible to distinguish occurrences of wr instructions that output the same terminal symbol.


7.4.5 Assembler Program Structure

An assembler program for parsing a terminal symbol sequence consists of blocks, where every block is either a primitive block or a complex block. The assembler program can begin with a prod instruction and end with a ret instruction.

A primitive block is an rd, scn, wr, or call instruction.

A complex block corresponds to a ‘?’ or ‘*’ quantifier or a set of alternatives separated by ‘|’. Every complex block begins with a look-ahead analysis sub-block. An expression under the ‘?’ or ‘*’ quantifier or every alternative separated by ‘|’ is a sequence of blocks.

Look-Ahead Analysis Sub-Block

A look-ahead analysis sub-block provides branching based on a look-ahead terminal symbol. The sub-block begins with a peek instruction for fetching a look-ahead terminal symbol. A series of joe instructions after the peek instruction transfers control on particular look-ahead terminal symbols. A jmp or abrt instruction finalizes the series.

When a set of expected look-ahead terminal symbols is equal to a set of all possible terminal symbols, the jmp instruction transfers control on a remaining look-ahead terminal symbol not tested by the preceding joe instructions. Otherwise, the abrt instruction aborts parsing a terminal symbol sequence on encountering an unexpected terminal symbol.

Example

        ; FIRST: [ "a" "b" "c" ]
        peek    1
        joe     0, t1_0 ; "a"
        joe     1, t1_1 ; "b"
        joe     2, a3   ; "c"
        abrt

This assembler program fragment can analyze a look-ahead terminal symbol for the regular expression ‘"a" | [ "a" "b" ] | [ "a" "b" "c" ]’.

Jump targets of the joe instructions and an optional jmp instruction following them can be:

  • choice instruction blocks usually finalized by a jmp instruction; case instructions in the blocks along with the jmp instruction probabilistically transfer control to target branches of the look-ahead analysis sub-block. The case instructions have equal probabilities or custom probabilities specified using the notation [RelativeProbability] (see Alternatives) in a regular expression grammar. The choice instruction blocks always contain at least two case instructions
  • jprob instructions usually followed by jmp instructions. They probabilistically transfer control to two target branches of the look-ahead analysis sub-block. The jprob instructions have default probability 0.5 or custom probabilities specified using the notation [RelativeProbability] (see Alternatives) or notation [Probability] (see Loops) in a regular expression grammar
  • target branches of the look-ahead analysis sub-block if their choice is deterministic on particular look-ahead terminal symbols

Example

The following code fragment contains definitions of t1_0 and t1_1 labels referenced in the previous example with peek, joe, and abrt instructions:

t1_0:
        ; "a"
        choice
        case    3.333333333333333E-01, a1
        case    3.333333333333333E-01, a2
        end     choice
        jmp     a3
t1_1:
        ; "b"
        jprob   0.5, a2
        jmp     a3

|’ Alternatives

A block for a set of alternatives separated by ‘|’ has the following structure:

        A look-ahead analysis sub-block transferring control to one
        of the labels aI0, aI1, ..., aIn

aI0:    prod    NONT_QUOTED, 0  ; increments the frequency of a
                                ; production for alternative I0

        Code for alternative I0

        jmp     eJ

aI1:    prod    NONT_QUOTED, 1  ; increments the frequency of a
                                ; production for alternative I1

        Code for alternative I1

        jmp     eJ

        ...

aIn:    prod    NONT_QUOTED, n  ; increments the frequency of a
                                ; production for alternative In

        Code for alternative In

eJ:     Code for an expression following the set of
        alternatives separated by `|'

?’ Quantifier

A block for the ‘?’ quantifier has the following structure:

        A look-ahead analysis sub-block transferring control to
        the label sI or bI

sI:     prod    NONT_QUOTED, 0  ; increments the frequency of an empty
                                ; production on omitting the execution
                                ; of the quantified expression
        jmp     eJ

bI:     prod    NONT_QUOTED, 1  ; increments the frequency of a
                                ; production corresponding to the
                                ; execution of the quantified
                                ; expression

        Code for the quantified expression

eJ:     Code for an expression following the `?' quantifier

*’ Quantifier

A block for the ‘*’ quantifier has the following structure:

rJ:     A look-ahead analysis sub-block transferring control to
        the label bI or sI

bI:     prod    NONT_QUOTED, 1  ; increments the frequency of a
                                ; production corresponding to a repeat
                                ; of the quantified expression

        Code for the quantified expression

        jmp     rJ

sI:     prod    NONT_QUOTED, 0  ; increments the frequency of an empty
                                ; production on finishing repeating the
                                ; quantified expression

        Code for an expression following the `*' quantifier

7.5 abu-parser

This program is a probabilistic adaptive bottom-up parser. Its main purpose is the synthesis of a PCFG based on a bottom-up template grammar. The synthesis method is iterative determinization of a top-down template grammar generated from a bottom-up template grammar. Compared to a top-down template grammar, a bottom-up template grammar makes it possible to specify parsing behavior in a more convenient way. The bottom-up parser operates in parse unit mode and does not support parsing a single stream of terminal symbols.

As opposed to the probabilistic adaptive top-down parser atd-parser (see atd-parser), the bottom-up parser adaptively processes training parse units to increase the probability of a source PCFG intended for parsing in the bottom-up direction rather than the probability of a derived PCFG intended for parsing in the top-down direction. For that, a top-down template grammar used by the bottom-up parser contains references to the productions of a source PCFG inferred from a bottom-up template grammar.

A top-down template grammar supplied to the bottom-up parser requires conversion from a bottom-up template grammar by the rege-markup-cfg tool, optionally by the rege-vit tool, and by the rege-bottom-up tool. See Bottom-Up Template Grammar, for more information on conversion steps.


7.5.1 Examples

This subsection contains the examples of learning PCFGs using bottom-up template grammars in the files bu-1-14-uni-no-quant.rg and bu-uni-alt-1.rg located in the directory $prefix/share/qsmm/samples/gram installed from the directory samples/gram in the package distribution.

The bottom-up template grammar bu-1-14-uni-no-quant.rg is the unification of all PCFGs in the files *.pcfg in that directory except for the file 7.pcfg. The bottom-up template grammar bu-uni-alt-1.rg is an alternative way of representing the unification of the PCFGs.

To reproduce the examples, execute in a temporary directory the preparation commands listed below. See rege-markup-cfg, rege-vit, and rege-bottom-up for descriptions of referenced tools.

$ mkdir seq log td-learn bu-learn
$ prefix=/usr  # use a different prefix, if necessary

$ rege-markup-cfg -o markup-bu-1-14-uni-no-quant.rg                          \
                  "$prefix/share/qsmm/samples/gram/bu-1-14-uni-no-quant.rg"

$ rege-vit -o vit-markup-bu-1-14-uni-no-quant.rg --cfg-markup  \
           16 markup-bu-1-14-uni-no-quant.rg

$ rege-bottom-up -o td-1-14-uni-no-quant.rg --cfg-markup --template  \
                 vit-markup-bu-1-14-uni-no-quant.rg

$ rege-markup-cfg -o markup-bu-uni-alt-1.rg --nont-class             \
                  "$prefix/share/qsmm/samples/gram/bu-uni-alt-1.rg"

$ rege-vit -o vit-markup-bu-uni-alt-1.rg --cfg-markup 16 markup-bu-uni-alt-1.rg
$ rege-bottom-up -o td-uni-alt-1.rg --cfg-markup --template vit-markup-bu-uni-alt-1.rg

The above commands convert the bottom-up template grammar $prefix/share/qsmm/samples/gram/bu-1-14-uni-no-quant.rg to the top-down template grammar td-1-14-uni-no-quant.rg and convert the bottom-up template grammar $prefix/share/qsmm/samples/gram/bu-uni-alt-1.rg to the top-down template grammar td-uni-alt-1.rg.

See Files {bu,td}-1-14-uni-no-quant.rg, for contents of the former two grammars. See Files {bu,td}-uni-alt-1.rg, for contents of the latter two grammars.

Continue by executing commands for the examples below. The examples use the auxiliary programs described in pcfg-generate-seq and pcfg-predict-eval.

Example 1

$ cat "$prefix/share/qsmm/samples/gram/1.pcfg"

  S: A B
  ;

  A: "a" "b" "c" "d"
   | "d" "c" "b" "a"
  ;

  B: "e" "f" "g" "h"
   | "h" "g" "f" "e"
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                              \
                    -o seq/1-10k-unit.seq "$prefix/share/qsmm/samples/gram/1.pcfg"

Using the Unified Template Grammar

$ abu-parser -i1 -n20000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/1a_det.rg --oo=log/1a.log  \
             td-1-14-uni-no-quant.rg seq/1-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/1a_out.pcfg --oo --simplify  \
             td-learn/1a_det.rg seq/1-10k-unit.seq

  p_td 0.82778218, p_so 0.75789709, p_rd 0.75789709, cp 3

$ cat bu-learn/1a_out.pcfg

  S: A B  // 1250
  ;

  A: "d" "c" "b" "a"  [0.508]  // 635
   | "a" "b" "c" "d"  [0.492]  // 615
  ;  // 1250

  B: "h" "g" "f" "e"  [0.508]  // 635
   | "e" "f" "g" "h"  [0.492]  // 615
  ;  // 1250

Using the Alternative Template Grammar

$ abu-parser -i1 -n80000 --viterbi --det-niter-goal=100 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/1b_det.rg --oo=log/1b.log   \
             td-uni-alt-1.rg seq/1-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/1b_out.pcfg --oo --simplify  \
             td-learn/1b_det.rg seq/1-10k-unit.seq

  p_td 0.84953738, p_so 0.82036536, p_rd 0.82036536, cp 3

$ cat bu-learn/1b_out.pcfg

  S: B1 B2  // 1250
  ;

  B1: W4_2  // 1250
  ;

  B2: W4_3  [0.508]  // 635
    | W4_4  [0.492]  // 615
  ;  // 1250

  W4_2: "d" "c" "b" "a"  [0.508]  // 635
      | "a" "b" "c" "d"  [0.492]  // 615
  ;  // 1250

  W4_3: "h" "g" "f" "e"  // 635
  ;

  W4_4: "e" "f" "g" "h"  // 615
  ;

Example 2

$ cat "$prefix/share/qsmm/samples/gram/2.pcfg"

  S: L00 L01
  ;

  L00: L10 L11
     | L11 L10
  ;

  L01: L12 L13
     | L13 L12
  ;

  L10: "a" "b" "c" "d"
  ;

  L11: "e" "f" "g" "h"
  ;

  L12: "d" "c" "b" "a"
  ;

  L13: "h" "g" "f" "e"
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                              \
                    -o seq/2-10k-unit.seq "$prefix/share/qsmm/samples/gram/2.pcfg"

Using the Unified Template Grammar

$ abu-parser -i1 -n10000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/2a_det.rg --oo=log/2a.log  \
             td-1-14-uni-no-quant.rg seq/2-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/2a_out.pcfg --oo --simplify  \
             td-learn/2a_det.rg seq/2-10k-unit.seq

  p_td 0.85728227, p_so 0.88162347, p_rd 1.00000000, cp 3

$ cat bu-learn/2a_out.pcfg

  S: L00 L01  // 625
  ;

  L00: L10 L11  [0.5136]  // 321
     | L11 L10  [0.4864]  // 304
  ;  // 625

  L01: L13 L12  [0.504]  // 315
     | L12 L13  [0.496]  // 310
  ;  // 625

  L10: "e" "f" "g" "h"  // 625
  ;

  L11: "a" "b" "c" "d"  // 625
  ;

  L12: "d" "c" "b" "a"  // 625
  ;

  L13: "h" "g" "f" "e"  // 625
  ;

Using the Alternative Template Grammar

$ abu-parser -i1 -n10000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/2b_det.rg --oo=log/2b.log  \
             td-uni-alt-1.rg seq/2-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/2b_out.pcfg --oo --simplify  \
             td-learn/2b_det.rg seq/2-10k-unit.seq

  p_td 0.82776840, p_so 0.88162347, p_rd 1.00000000, cp 0

$ cat bu-learn/2b_out.pcfg

  S: B1 B2  // 625
  ;

  B1: W4_1 W4_3  [0.5136]  // 321
    | W4_3 W4_1  [0.4864]  // 304
  ;  // 625

  B2: W4_2 W4_4  [0.504]  // 315
    | W4_4 W4_2  [0.496]  // 310
  ;  // 625

  W4_1: "e" "f" "g" "h"  // 625
  ;

  W4_2: "h" "g" "f" "e"  // 625
  ;

  W4_3: "a" "b" "c" "d"  // 625
  ;

  W4_4: "d" "c" "b" "a"  // 625
  ;

Example 3

$ cat "$prefix/share/qsmm/samples/gram/3.pcfg"

  S: A B
  ;

  A: "a" "b" "c"
   | "d" "c" "b" "a"
  ;

  B: "e"
   | "f" "e"
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                              \
                    -o seq/3-10k-unit.seq "$prefix/share/qsmm/samples/gram/3.pcfg"

Using the Alternative Template Grammar

$ abu-parser -i1 -n20000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/3b_det.rg --oo=log/3b.log  \
             td-uni-alt-1.rg seq/3-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/3b_out.pcfg --oo --simplify  \
             td-learn/3b_det.rg seq/3-10k-unit.seq

  p_td 0.90778245, p_so 0.79357088, p_rd 1.00000000, cp 0

$ cat bu-learn/3b_out.pcfg

  S: W2_1 W3_2  [0.25727182]  // 513
   | B1 W2_9    [0.25325978]  // 505
   | B1 B2      [0.25125376]  // 501
   | W2_1 B4    [0.23821464]  // 475
  ;  // 1994

  B1: W4_2  // 1006
  ;

  B2: W1_1  // 501
  ;

  B4: W2_5  // 475
  ;

  W1_1: "e"  // 501
  ;

  W2_1: "a" "b"  // 988
  ;

  W2_5: "c" "e"  // 475
  ;

  W2_9: "f" "e"  // 505
  ;

  W3_2: "c" "f" "e"  // 513
  ;

  W4_2: "d" "c" "b" "a"  // 1006
  ;

Example 4

$ cat "$prefix/share/qsmm/samples/gram/5.pcfg"

  S: B C
   | B C C
   | D C B
   | D D C
  ;

  B: "a" "a"
  ;

  C: "c" "b" "c"
  ;

  D: "d" "b" "b" "d"
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                              \
                    -o seq/5-10k-unit.seq "$prefix/share/qsmm/samples/gram/5.pcfg"

Using the Unified Template Grammar

$ abu-parser -i1 -n40000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/5a_det.rg --oo=log/5a.log  \
             td-1-14-uni-no-quant.rg seq/5-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/5a_out.pcfg --oo --simplify  \
             td-learn/5a_det.rg seq/5-10k-unit.seq

  p_td 1.00000000, p_so 0.68039575, p_rd 1.00000000, cp 4

$ cat bu-learn/5a_out.pcfg

  S: B C C  [0.26477935]  // 318
   | D C B  [0.26311407]  // 316
   | D D C  [0.24562864]  // 295
   | B C    [0.22647794]  // 272
  ;  // 1201

  B: "a" "a"  // 906
  ;

  C: "c" "b" "c"  // 1519
  ;

  D: "d" "b" "b" "d"  // 906
  ;

Using the Alternative Template Grammar

$ abu-parser -i1 -n640000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/5b_det.rg --oo=log/5b.log   \
             td-uni-alt-1.rg seq/5-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/5b_out.pcfg --oo --simplify  \
             td-learn/5b_det.rg seq/5-10k-unit.seq

  p_td 1.00000000, p_so 0.80941299, p_rd 1.00000000, cp 5

$ cat bu-learn/5b_out.pcfg

  S: W2_1 W3_2 W3_2  [0.26477935]  // 318
   | W4_5 W3_2 W2_1  [0.26311407]  // 316
   | W4_5 W4_5 W3_2  [0.24562864]  // 295
   | W2_1 W3_2       [0.22647794]  // 272
  ;  // 1201

  W2_1: "a" "a"  // 906
  ;

  W3_2: "c" "b" "c"  // 1519
  ;

  W4_5: "d" "b" "b" "d"  // 906
  ;

Example 5

$ cat "$prefix/share/qsmm/samples/gram/6.pcfg"

  S: B C
   | B D D
   | B E E E
  ;

  B: "a" "b"
   | "b" "b"
  ;

  C: "a" "c"
   | "c" "c"
  ;

  D: "a" "d"
   | "d" "d"
  ;

  E: "a" "e"
   | "e" "e"
  ;

$ pcfg-generate-seq -i1 -n80000 --separate-parse-units                              \
                    -o seq/6-80k-unit.seq "$prefix/share/qsmm/samples/gram/6.pcfg"

Using the Unified Template Grammar

$ abu-parser -i1 -n80000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/6a_det.rg --oo=log/6a.log  \
             td-1-14-uni-no-quant.rg seq/6-80k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/6a_out.pcfg --oo --simplify  \
             td-learn/6a_det.rg seq/6-80k-unit.seq

  p_td 0.82044141, p_so 0.57534250, p_rd 0.98219605, cp 6

$ cat bu-learn/6a_out.pcfg

  S: B E E E          [0.33058223]  // 4406
   | B D D            [0.17136855]  // 2284
   | B C C            [0.16851741]  // 2246
   | "a" "b" "a" "c"  [0.08883553]  // 1184
   | "b" "b" "c" "c"  [0.08133253]  // 1084
   | "a" "b" "c" "c"  [0.08013205]  // 1068
   | "b" "b" "a" "c"  [0.07923169]  // 1056
  ;  // 13328

  B: "b" "b"  [0.51242167]  // 4579
   | "a" "b"  [0.48757833]  // 4357
  ;  // 8936

  C: "a" "d"  [0.75]  // 3369
   | "d" "d"  [0.25]  // 1123
  ;  // 4492

  D: "d" "d"  [0.7515324]  // 3433
   | "a" "d"  [0.2484676]  // 1135
  ;  // 4568

  E: "e" "e"  [0.50174005]  // 6632
   | "a" "e"  [0.49825995]  // 6586
  ;  // 13218

Using the Alternative Template Grammar

$ abu-parser -i1 -n80000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/6b_det.rg --oo=log/6b.log  \
             td-uni-alt-1.rg seq/6-80k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/6b_out.pcfg --oo --simplify  \
             td-learn/6b_det.rg seq/6-80k-unit.seq

  p_td 0.78683710, p_so 0.64378074, p_rd 0.93880311, cp 19

$ cat bu-learn/6b_out.pcfg

  S: W2_12 B2           [0.17534514]  // 2337
   | B3 B2              [0.16454082]  // 2193
   | B3 W2_4            [0.08883553]  // 1184
   | W4_5 B5 B5         [0.08583433]  // 1144
   | W4_5 B5 W2_1       [0.08238295]  // 1098
   | W2_12 W2_7         [0.08133253]  // 1084
   | B3 W2_7            [0.08013205]  // 1068
   | W2_12 W2_4         [0.07923169]  // 1056
   | B3 W2_1 B6 B6      [0.02183373]  // 291
   | B3 B6 B6 W2_1      [0.02108343]  // 281
   | B3 W2_1 W2_1 W2_1  [0.0210084]   // 280
   | B3 B6 W2_1 W2_1    [0.0202581]   // 270
   | B3 B6 B6 B6        [0.01995798]  // 266
   | B3 W2_1 B6 W2_1    [0.01995798]  // 266
   | B3 B6 W2_1 B6      [0.01988295]  // 265
   | B3 W2_1 W2_1 B6    [0.01838235]  // 245
  ;  // 13328

  B2: W4_3  [0.50419426]  // 2284
    | W4_4  [0.49580574]  // 2246
  ;  // 4530

  B3: W2_2  // 6609
  ;

  B5: W2_6  // 3386
  ;

  B6: W2_9  // 3253
  ;

  W2_1: "a" "e"  // 4337
  ;

  W2_2: "a" "b"  // 6609
  ;

  W2_4: "a" "c"  // 2240
  ;

  W2_6: "e" "e"  [0.66302422]  // 2245
      | "a" "e"  [0.33697578]  // 1141
  ;  // 3386

  W2_7: "c" "c"  // 2152
  ;

  W2_9: "e" "e"  // 3253
  ;

  W2_12: "b" "b"  // 4477
  ;

  W4_3: "d" "d" "d" "d"  [0.5030648]  // 1149
      | "d" "d" "a" "d"  [0.4969352]  // 1135
  ;  // 2284

  W4_4: "a" "d" "a" "d"  [0.5]  // 1123
      | "a" "d" "d" "d"  [0.5]  // 1123
  ;  // 2246

  W4_5: "b" "b" "e" "e"  [0.50579839]  // 1134
      | "b" "b" "a" "e"  [0.49420161]  // 1108
  ;  // 2242

To evaluate the correctness of the learned PCFG above, we can compare the probability of a terminal symbol correctly predictable in parse units in the file seq/6-80k-unit.seq using the PCFG in the file $prefix/share/qsmm/gram/6.pcfg and the probability of a terminal symbol correctly predictable using the learned PCFG in the file bu-learn/6b_out.pcfg.

$ pcfg-predict-eval "$prefix/share/qsmm/samples/gram/6.pcfg"                        \
                    seq/6-80k-unit.seq seq/6-80k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.69436388,

$ pcfg-predict-eval bu-learn/6b_out.pcfg                                            \
                    seq/6-80k-unit.seq seq/6-80k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.70663111,

The probability of a correctly predictable terminal symbol is even slightly less for the original PCFG compared to the learned PCFG. The reason of this small decrease might be pseudo-randomness of parse units in the file seq/6-80k-unit.seq.

Example 6

$ cat "$prefix/share/qsmm/samples/gram/8.pcfg"

  S: C B C B
   | C C B B
   | C B B C
  ;

  B: "a" "b"
  ;

  C: "a" "b" "c"
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                              \
                    -o seq/8-10k-unit.seq "$prefix/share/qsmm/samples/gram/8.pcfg"

Using the Unified Template Grammar

$ abu-parser -i1 -n320000 --viterbi --det-niter-goal=100 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/8a_det.rg --oo=log/8a.log    \
             td-1-14-uni-no-quant.rg seq/8-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/8a_out.pcfg --oo --simplify  \
             td-learn/8a_det.rg seq/8-10k-unit.seq

  p_td 0.89477660, p_so 0.77924711, p_rd 0.94080204, cp 4

$ cat bu-learn/8a_out.pcfg

  S: D C B  // 1000
  ;

  B: "b" "a" "b"      [0.352]  // 352
   | "b" "c" "a" "b"  [0.337]  // 337
   | "b" "a" "b" "c"  [0.311]  // 311
  ;  // 1000

  C: "b" "a"      [0.648]  // 648
   | "b" "c" "a"  [0.352]  // 352
  ;  // 1000

  D: "a" "b" "c" "a"  // 1000
  ;

To evaluate the correctness of the learned PCFG above, we can compare the probability of a terminal symbol correctly predictable in parse units in the file seq/8-10k-unit.seq using the PCFG in the file $prefix/share/qsmm/gram/8.pcfg and the probability of a terminal symbol correctly predictable using the learned PCFG in the file bu-learn/8a_out.pcfg.

$ pcfg-predict-eval "$prefix/share/qsmm/samples/gram/8.pcfg"                        \
                    seq/8-10k-unit.seq seq/8-10k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.93426667,

$ pcfg-predict-eval bu-learn/8a_out.pcfg                                            \
                    seq/8-10k-unit.seq seq/8-10k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.91651161,

The probability of a correctly predictable terminal symbol is greater for the original PCFG compared to the learned PCFG. To evaluate the measure of correctness of the learned PCFG in percents, we can treat as correctness 0% the probability of a terminal symbol correctly predictable using a random PCFG for parse units in the file seq/8-10k-unit.seq and treat as correctness 100% the probability of a terminal symbol correctly predictable using the original PCFG in the file $prefix/share/qsmm/samples/gram/8.pcfg.

$ abu-parser -i-1 --viterbi --ops=bu-learn/8_rand.pcfg   \
             td-1-14-uni-no-quant.rg seq/8-10k-unit.seq

$ pcfg-predict-eval bu-learn/8_rand.pcfg                                            \
                    seq/8-10k-unit.seq seq/8-10k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.64024028,

$ bc <<< 'scale=1; max=0.93426667; learned=0.91651161; rand=0.64024028;
          (learned-rand)*100/(max-rand)'

  93.9

Using the Alternative Template Grammar

$ abu-parser -i1 -n320000 --viterbi --det-niter-goal=50 --det-niter-keep=1  \
             --randomize-det-iter --od=td-learn/8b_det.rg --oo=log/8b.log   \
             td-uni-alt-1.rg seq/8-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/8b_out.pcfg --oo --simplify  \
             td-learn/8b_det.rg seq/8-10k-unit.seq

  p_td 0.91735279, p_so 0.84526556, p_rd 0.96239338, cp 2

$ cat bu-learn/8b_out.pcfg

  S: W2_1 W3_1 W2_1 W3_1  [0.648]  // 648
   | W2_1 W3_1 W3_1 W2_1  [0.352]  // 352
  ;  // 1000

  W2_1: "a" "b"  // 2000
  ;

  W3_1: "c" "a" "b"  [0.8445]  // 1689
      | "a" "b" "c"  [0.1555]  // 311
  ;  // 2000

To evaluate the correctness of the learned PCFG above, we can compare the probability of a terminal symbol correctly predictable in parse units in the file seq/8-10k-unit.seq using the PCFG in the file $prefix/share/qsmm/gram/8.pcfg and the probability of a terminal symbol correctly predictable using the learned PCFG in the file bu-learn/8b_out.pcfg.

$ pcfg-predict-eval "$prefix/share/qsmm/samples/gram/8.pcfg"                        \
                    seq/8-10k-unit.seq seq/8-10k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.93426667,

$ pcfg-predict-eval bu-learn/8b_out.pcfg                                            \
                    seq/8-10k-unit.seq seq/8-10k-unit.seq | grep prob_wpredict_max

      "prob_wpredict_max"    : 0.94543205,

The probability of a correctly predictable terminal symbol is less for the original PCFG compared to the learned PCFG. This condition may indicate that the original PCFG is less optimal compared to the learned PCFG.

Example 7

$ cat "$prefix/share/qsmm/samples/gram/12.pcfg"

  W: "h" "e" A    [0.67]
   | "d"          [0.20]
   | "i" "k" "j"  [0.13]
  ;

  A: "e" "h" "j" [0.67]
   | "c"         [0.33]
  ;

$ pcfg-generate-seq -i1 -n10000 --separate-parse-units                                \
                    -o seq/12-10k-unit.seq "$prefix/share/qsmm/samples/gram/12.pcfg"

Using the Alternative Template Grammar

$ abu-parser -i1 -n10000 --viterbi --det-niter-goal=50 --det-niter-keep=1    \
             --randomize-det-iter --od=td-learn/12b_det.rg --oo=log/12b.log  \
             td-uni-alt-1.rg seq/12-10k-unit.seq

$ abu-parser -i1 --viterbi --ops=bu-learn/12b_out.pcfg --oo --simplify  \
             td-learn/12b_det.rg seq/12-10k-unit.seq

  p_td 0.95077196, p_so 0.77508709, p_rd 1.00000000, cp 6

$ cat bu-learn/12b_out.pcfg

  S: W2_1 B7  [0.44929577]  // 1276
   | W2_1 B2  [0.22676056]  // 644
   | W1_2     [0.18908451]  // 537
   | W3_3     [0.13485915]  // 383
  ;  // 2840

  B2: W1_1  // 644
  ;

  B7: W3_1  // 1276
  ;

  W1_1: "c"  // 644
  ;

  W1_2: "d"  // 537
  ;

  W2_1: "h" "e"  // 1920
  ;

  W3_1: "e" "h" "j"  // 1276
  ;

  W3_3: "i" "k" "j"  // 383
  ;

7.5.2 Synopsis

To learn a source PCFG by iterative determinization of a top-down template grammar converted from a bottom-up template grammar, use the commands:

abu-parser -iPOSITIVE_RANDOM_SEED [ -nTRAINING_SEQ_LENGTH ] --viterbi    \
           --det-niter-goal=NUMBER_OF_ITERATIONS --det-niter-keep=1      \
           --randomize-det-iter --od=DETERMINIZED_TD_GRAMMAR_FILE        \
           --oo[=LOG_FILE] INPUT_TD_GRAMMAR_FILE INPUT_PARSE_UNITS_FILE

abu-parser --viterbi --ops=LEARNED_PCFG_FILE --oo --simplify    \
           DETERMINIZED_TD_GRAMMAR_FILE INPUT_PARSE_UNITS_FILE

To generate a random source PCFG for a top-down template grammar converted from a bottom-up template grammar, use the command:

abu-parser -iNEGATIVE_RANDOM_SEED --viterbi --ops=RANDOM_PCFG_FILE  \
           INPUT_TD_GRAMMAR_FILE INPUT_PARSE_UNITS_FILE

In the above command line formats:

INPUT_TD_GRAMMAR_FILE

The name of a file containing an input top-down template grammar (see Top-Down Template Grammar) converted by the rege-bottom-up tool (see rege-bottom-up) from a bottom-up template grammar with source PCFG markup. The filename ‘-’ means stdin.

DETERMINIZED_TD_GRAMMAR_FILE

The name of a file containing a determinized top-down template grammar. The filename ‘-’ means stdin or stdout.

INPUT_PARSE_UNITS_FILE

The name of a file containing input parse units separated by empty lines. The filename ‘-’ means stdin. Input parse units are sequences of terminal symbol names separated by whitespace characters (including single newline characters, as multiple consecutive newline characters separate two parse units).

See Command-Line Options, for descriptions of options and their arguments mentioned in the command line formats.

Parse Statistics Format

On passing the option --oo[=FILE], the parser dumps overall parse statistics or parse statistics for each determinization iteration to a file or stdout.

Overall parse statistics looks like this:

p_td 0.53287683, p_so 0.26498707, p_rd 0.68541645, cp 17

The fields of this line have the following meanings:

p_td

The probability of parsing training parse units by a learned top-down PCFG. It is weighted probability of all productions in the PCFG where weights are production frequencies.

p_so

The probability of parsing training parse units by a learned source PCFG. It is weighted probability of all productions in the PCFG where weights are production frequencies.

p_rd

Weighted probability of productions with terminal symbols at the right-hand side in a learned top-down PCFG where weights are production frequencies. The probability p_td is weighted probability of p_rd and productions with nonterminal symbols at the right-hand side in a learned top-down PCFG.

cp

Average cycle length counted in training parse units. It is equal to total length of cycles divided by the number of cycles. A cycle here is leading out the same production of a source PCFG. The parser increments total length of cycles and the number of cycles on leading out a production of a source PCFG only if a nonterminal symbol at the left-hand side of the production had the previous led out right-hand side with a different index.

Parse statistics for a determinization iteration looks like this:

Iteration 30 of 50 (60.0 %):
P: p_td 0.68479463, p_so 0.34150993, p_rd 0.93313912, cp 35
T: p_td 0.68479463, p_so 0.34150993, p_rd 0.93313912, cp 35
n_removable_rd 129, n_removed_rd 6(+0), iter_time 1s

The first line contains the ordinal number of a current iteration, the goal number of iterations, and the percentage of completed iterations. The line beginning with ‘P:’ (“Pass”) contains parse statistics for a current iteration. The line beginning with ‘T:’ (“Total”) contains aggregate parse statistics for last iterations up to a current iteration. In the example, the lines beginning with ‘P:’ and ‘T:’ are equal because of passing the option --det-niter-keep=1. See the table above for the description of fields in the lines.

The fourth line contains the following fields:

n_removable_rd

The number of terminal symbols removable from terminal symbol classes of a top-down template grammar at a current determinization iteration without reducing terminal symbol coverage of the top-down template grammar.

n_removed_rd

The number (less than or equal to n_removable_rd) of terminal symbols actually removed from terminal symbol classes of a top-down template grammar at a current determinization iteration and, in round brackets, the number of implicitly removed terminal symbols. Implicitly removed terminal symbols are unreachable terminal symbols and terminal symbols not present in input parse units and a set of reachable output terminal symbols.

iter_time

Approximate number of seconds a determinization iteration was executing.


7.5.3 Command-Line Options

The adaptive bottom-up parser abu-parser supports the following command line options:

--det-interim

Create a separate set of output files at each iteration of determinization of a top-down template grammar. The files have the suffix ‘.ITER’, where ITER is an iteration index. By default, the parser overwrites the same output files at each iteration.

--det-niter-goal=INT

The number of determinization iterations to perform. The actual number of iterations cannot exceed the number of terminal symbols removable from a top-down template grammar without reducing its terminal symbol coverage.

--det-niter-keep=INT

The number of last determinization iterations to keep aggregate statistics. If that number is equal to 1, use statistics from the last iteration only. If that number is greater than the number of already performed iterations, keep aggregate statistics for the already performed iterations. The default value is the goal number of iterations.

--det-niter-max=INT

Limit on the number of iterations of determinization of a top-down template grammar. The parser stops on reaching the limit. If that number is less than the goal number of iterations, iterative determinization terminates prematurely. Special value 0 means no limit. The default value is 0.

--det-ratio=FLOAT

Minimum ratio for the number of terminal symbols to attempt to remove from terminal symbol classes at each determinization iteration relative to the number of removable terminal symbols. The default value is 0.

--fq-span=window|total

Event history span for output frequencies of PCFG productions and terminal symbol n-grams:

window

Event history window.

total

Entire event history.

The default value is ‘total’.

--kt=FLOAT

The temperature of the environment state identification engine. The default value is 1.

-N, --npass=INT

The number of training passes. The parser reinitializes the environment state identification engine at each training pass and accumulates PCFG production frequencies for all training passes at a determinization iteration. Using multiple training passes usually requires a shorter training terminal symbol sequence to achieve the same quality of grammar synthesis. Performing multiple training passes in parallel is possible but not implemented. The default value is 1.

-n, --nstep=INT

The length of a training terminal symbol sequence. If an input terminal symbol sequence ends earlier, the parser processes it again from the beginning. Parsing finishes at a parse unit boundary. By default, the length of a training terminal symbol sequence is equal to the length of an input terminal symbol sequence.

--od[=FILE]

Dump a determinized top-down template grammar to a file or stdout. The grammar does not contain subexpressions starting with empty terminal symbol classes ‘[]’. This option turns on iterative determinization of a top-down template grammar.

--ode[=FILE]

Dump a determinized top-down template grammar to a file or stdout. The grammar can contain subexpressions starting with empty terminal symbol classes ‘[]’. This option turns on iterative determinization of a top-down template grammar.

--og[=FILE]

Dump an initial top-down context-free grammar to a file or stdout.

--on[=FILE]

Dump n-grams of terminal symbols from a source PCFG to a file or stdout.

--oo[=FILE]

Dump parse statistics to a file or stdout. See “Parse Statistics Format of Bottom-Up Parser”, for more information.

--op[=FILE]

Dump a learned derived (top-down) PCFG to a file or stdout.

--ops[=FILE]

Dump a learned source PCFG to a file or stdout.

--or[=FILE]

Dump a residual top-down template grammar to a file or stdout.

--ot[=FILE]

Dump parse trees for a derived (top-down) PCFG to a file or stdout.

--ots[=FILE]

Dump parse trees for a source PCFG to a file or stdout.

--plain-pcfg

Remove output and put-back terminal symbols from a learned derived (top-down) PCFG.

--profile-tol=FLOAT

Generate output signal choice trees with specified maximum difference between desired profile probabilities of output signals and their actual profile probabilities. Special value 0 means to use Huffman trees as output signal choice trees. The default value is 0.005.

--randomize-det-iter

Use a different random seed at each determinization iteration. By default, use the same random seed at each determinization iteration.

--recurs=left|right

Recursion type for an initial top-down context-free grammar and learned top-down (derived) PCFG to dump: left or right. The default value is ‘left’.

-i, --seed=INT

A seed for the pseudo-random number generator. A non-negative value switches parser operation to adaptive mode. A negative value switches parser operation to random mode. The default value is 0.

--simplify

Simplify a learned derived (top-down) PCFG and learned source PCFG.

--stack-size=INT

Maximum nesting level of nonterminal symbols of a top-down template grammar while parsing. Parsing aborts on exceeding that level. The default value is 32.

--term-prefix=STR

A prefix for virtual terminal symbols in a top-down template grammar. Terminal symbols with the prefix in a top-down template grammar are terminal symbols of a bottom-up template grammar with the prefix removed. The parser prepends the prefix to every terminal symbol in training parse units and removes the prefix from terminal symbols put in a learned source PCFG. The default value is ‘%’.

--terse

Use condensed format to dump productions of regular expression grammars. By default, dump the productions in indented format.

--viterbi

Provide parsing entire parse units by selecting start nonterminal symbols corresponding to parse unit lengths counted in terminal symbols. On omitting this option, the parser always uses the same start nonterminal symbol.

--ww=INT

The length (width) of the cycle event history window and grammar event history window counted in parse units. By default, the parser sets and adjusts that length automatically.


7.5.4 Assembler Instruction Set

Assembler instruction set of the adaptive bottom-up parser abu-parser includes all assembler instructions of the adaptive top-down parser atd-parser described in Assembler Instruction Set and contains two additional instructions nprod and tprod for referencing the productions of a source PCFG inferred from a bottom-up template grammar.


7.5.4.1 nprod Instruction

This instruction has the syntax

        nprod   NONT_QUOTED, RHS, ORD

The instruction increments the frequency of a production of a source PCFG with nonterminal symbols at the right-hand side and updates the spur accordingly. The production has a nonterminal symbol NONT_QUOTED at the left-hand side. The parameter RHS is zero-based index of a right-hand side for the nonterminal symbol as specified for the production in the source PCFG. The parameter ORD is the ordinal number of an nprod instruction with the same parameters NONT_QUOTED and RHS.

An nprod instruction corresponds to a #pn-… specifier in a top-down template grammar. See Ending a Nonterminal Production, for more information on #pn-… specifiers.

Example:

        nprod   "S", 5, 2

This instruction corresponds to an occurrence of #pn-S-5 specifier in a regular expression of a top-down template grammar. The occurrence has ordinal number 2.


7.5.4.2 tprod Instruction

This instruction has the syntax

        tprod   NONT_QUOTED, ORD

The instruction increments the frequency of a production of a source PCFG with a nonterminal symbol NONT_QUOTED at the left-hand side and terminal symbols at the right-hand side and updates the spur accordingly. The parameter ORD is the ordinal number of a tprod instruction with the same parameter NONT_QUOTED.

A tprod instruction corresponds to a #pt-… specifier in a top-down template grammar. See Ending a Terminal Production, for more information on #pt-… specifiers.

Example:

        tprod   "_W2_10_1T2", 3

This instruction corresponds to an occurrence of #pt-_W2_10_1T2 specifier in a regular expression of a top-down template grammar. The occurrence has ordinal number 3.


7.6 rege-markup-cfg

This tool marks up the productions of a source PCFG in a bottom-up template grammar. The productions can have terminal symbols at the right-hand side or nonterminal symbols at the right-hand side.

The tool adds terminal symbol segment names (see Named Segments) acting as nonterminal symbols at the left-hand side of productions of a source PCFG with terminal symbols at the right-hand side.

Example

If a production right-hand side contains the expression

( . . ) ( . . . )

the rege-markup-cfg tool may convert it to the expression

_S_1T2: . . _S_2T3: . . .

where the terminal symbol segment names _S_1T2 and _S_2T3 act as nonterminal symbols of a source PCFG.

For source PCFG productions with nonterminal symbols at the right-hand side, rege-markup-cfg adds the markers #l… (see Marking a Left-Hand Side) and #r… (see Marking a Right-Hand Side).

Example

The rege-markup-cfg tool converts the production

S: A ( B
     | C
     | D
     ) E F
 | G (H I)* J
;

to the production

S #l-S: A #l-_S_1C ( B #r0
                   | C #r1
                   | D #r2
                   ) E F #r0
      | G (#l-_S_2A H I #r0)* J #r1
;

To mark up source PCFG productions for the ‘?’ quantifier, rege-markup-cfg changes the expression to two alternatives separated by ‘|’, where the first alternative is the empty one, and the second alternative is a subexpression under the ‘?’ quantifier.

Example

The rege-markup-cfg tool converts the production

S: A (B C)? D
;

to the production

S #l-S: A #l-_S_1Q ( #r0
                   | B C #r1
                   ) D #r0
;

Example

$ cat sample-rege-markup-cfg.rg

  S: A B
  ;

  A: .
   | . .
   | . . .
   | . . . .
  ;

  B = A ;

$ rege-markup-cfg sample-rege-markup-cfg.rg

  S #l-S: A B #r0
  ;

  A #l-A: _A_1T: . #r0
        | _A_2T2: . . #r1
        | _A_3T3: . . . #r2
        | _A_4T4: . . . . #r3
  ;

  B #l-B: _B_1T: . #r0
        | _B_2T2: . . #r1
        | _B_3T3: . . . #r2
        | _B_4T4: . . . . #r3
  ;

Synopsis

For usual cases, use the command line format:

rege-markup-cfg [ -o OUTPUT_BU_GRAMMAR_FILE ] [ --nont-class ] INPUT_BU_GRAMMAR_FILE

where INPUT_BU_GRAMMAR_FILE is the name of a file containing an input bottom-up template grammar (see Bottom-Up Template Grammar); the filename ‘-’ means stdin.

Command-Line Options

The rege-markup-cfg tool supports the following command line options:

--error-nont

Allow using the error nonterminal symbol in a regular expression grammar. See Error Nonterminal Symbol, for more information.

--nont-class

Allow using nonterminal symbol classes in a regular expression grammar. See Nonterminal Symbol Classes, for more information.

--out-cfg=FILE

Dump a context-free grammar to a file. The filename ‘-’ means stdout. The context-free grammar is a source PCFG that does not contain production probabilities and productions with terminal symbols at the right-hand side. A markup added to a regular expression grammar corresponds to the source PCFG. This option conflicts with the option --nont-class. By default, do not dump the context-free grammar.

-o, --out-gram-markup=FILE

Dump a regular expression grammar containing the markup of source PCFG productions to a file. By default, dump the regular expression grammar to stdout.

--recurs=left|right

Recursion type for a context-free grammar dumped using the option --out-cfg=FILE: left or right. The default value is ‘left’.


7.7 rege-vit

This tool generates a factored context-free grammar for processing entire parse units up to specified length (in terminal symbols) according to a regular expression grammar. Nonterminal symbols of the context-free grammar contain length specifications after the character ‘/’. The length specifications determine exact lengths of terminal symbol sequences consumed by the nonterminal symbols.

Example

This example uses a regular expression grammar from rege-markup-cfg.

$ rege-markup-cfg sample-rege-markup-cfg.rg | rege-vit --cfg-markup 5 -

  S/2 #l-S: A/1 B/1 #r0
  ;

  S/3 #l-S: A/1 B/2 #r0
          | A/2 B/1 #r0
  ;

  S/4 #l-S: A/1 B/3 #r0
          | A/2 B/2 #r0
          | A/3 B/1 #r0
  ;

  S/5 #l-S: A/1 B/4 #r0
          | A/2 B/3 #r0
          | A/3 B/2 #r0
          | A/4 B/1 #r0
  ;

  A/1 #l-A: _A_1T: . #r0
  ;

  A/2 #l-A: _A_2T2: . . #r1
  ;

  A/3 #l-A: _A_3T3: . . . #r2
  ;

  A/4 #l-A: _A_4T4: . . . . #r3
  ;

  B/1 #l-B: _B_1T: . #r0
  ;

  B/2 #l-B: _B_2T2: . . #r1
  ;

  B/3 #l-B: _B_3T3: . . . #r2
  ;

  B/4 #l-B: _B_4T4: . . . . #r3
  ;

Synopsis

For usual cases, use the command line format:

rege-vit [ -o OUTPUT_FACTORED_CFG_FILE ] --cfg-markup  \
         MAX_PARSE_UNIT_LENGTH INPUT_BU_GRAMMAR_FILE

where:

MAX_PARSE_UNIT_LENGTH

Maximum supported length of a parse unit counted in terminal symbols.

INPUT_BU_GRAMMAR_FILE

The name of a file containing an input bottom-up template grammar (see Bottom-Up Template Grammar). The filename ‘-’ means stdin. As required by the option --cfg-markup, the bottom-up template grammar should contain source PCFG markup inserted by the rege-markup-cfg tool (see rege-markup-cfg).

Command-Line Options

The rege-vit tool supports the following command line options:

--cfg-markup

Fetch source PCFG markup from an input regular expression grammar and generate a factored context-free grammar containing corresponding markup. On omitting this option, an input regular expression grammar must not contain source PCFG markup.

--dump-first

Indicate expected sets of terminal and nonterminal symbols in comments in an intermediate grammar dumped by the option --out-gram-interm=FILE.

-o, --out-pcfg=FILE

Dump a factored context-free grammar to a specified file. By default, dump the grammar to stdout.

--out-gram-interm=FILE

Dump to a file an intermediate grammar converted from an input regular expression grammar. The filename ‘-’ means stdout.

--template

Replace all terminal symbols and terminal symbol classes in a factored context-free grammar with the terminal symbol placeholder ‘.’.


7.8 rege-bottom-up

This tool converts a bottom-up template grammar to a top-down template grammar.

Example

$ cat sample-rege-bottom-up.rg

  S: A B
   | A C
  ;

  A: "a"
   | "a" "a"
  ;

  B: "b"
   | "b" "b"
  ;

  C: "c"
   | "c" "c"
  ;

$ rege-markup-cfg sample-rege-bottom-up.rg |
  rege-bottom-up --cfg-markup --er-vnont-scope=grammar -

  :c0: = [ "_S" ]
  ;
  :c1: = [ "_A" ]
  ;
  :c2: = [ "_B" "_C" ]
  ;
  :n: = [ "__ER" "__START" :c0: :c1: :c2: ]
  ;
  START: C "__START"
  ;

  C: C0 ( "_S" < "__START" >
        | "__ER" [^ :n: ] #pt-__er_consume < "__START" >
        )
  ;

  C0: C1 ( "_A" C2 ( "_B" #pn-S-0 < "_S" >
                   | "_C" #pn-S-1 < "_S" >
                   | "__ER" #pn-__ER-0 < "__ER" >
                   )
         | "__ER" #pn-__ER-0 < "__ER" >
         )
  ;

  C1: "%a" ( "%a" ( #pt-_A_2T2 [ "%b" "%c" ]~ #pn-A-1 < "_A" >
                  | #pt-__er [ $$ "%a" ]~ #pn-__ER-0 < "__ER" >
                  )
           | #pt-_A_1T [ "%b" "%c" ]~ #pn-A-0 < "_A" >
           | #pt-__er $$~ #pn-__ER-0 < "__ER" >
           )
    | [^ "%a" :n: ]~ #pn-__ER-0 < "__ER" >
  ;

  C2: "%b" ( "%b" ( #pt-_B_2T2 [ $$ "%a" ]~ #pn-B-1 < "_B" >
                  | #pt-__er [ "%b" "%c" ]~ #pn-__ER-0 < "__ER" >
                  )
           | #pt-_B_1T [ $$ "%a" ]~ #pn-B-0 < "_B" >
           | #pt-__er "%c"~ #pn-__ER-0 < "__ER" >
           )
    | "%c" ( "%c" ( #pt-_C_2T2 [ $$ "%a" ]~ #pn-C-1 < "_C" >
                  | #pt-__er [ "%b" "%c" ]~ #pn-__ER-0 < "__ER" >
                  )
           | #pt-_C_1T [ $$ "%a" ]~ #pn-C-0 < "_C" >
           | #pt-__er "%b"~ #pn-__ER-0 < "__ER" >
           )
    | [ $$ "%a" ]~ #pn-__ER-0 < "__ER" >
  ;

Synopsis

For usual cases, use the command line format:

rege-bottom-up [ -o OUTPUT_TD_GRAMMAR_FILE ] --cfg-markup        \
               [ --er-vnont-scope=grammar|nont ] [ --template ]  \
               INPUT_BU_GRAMMAR_FILE

where INPUT_BU_GRAMMAR_FILE is the name of a file containing an input bottom-up template grammar (see Bottom-Up Template Grammar); the filename ‘-’ means stdin.

As required by the option --cfg-markup, the bottom-up template grammar should contain source PCFG markup inserted by the rege-markup-cfg tool (see rege-markup-cfg). After inserting the source PCFG markup, the bottom-up grammar could have been converted to a factored context-free grammar by the rege-vit tool (see rege-vit).

Command-Line Options

The rege-bottom-up tool supports the following command line options:

--cfg-markup

Fetch source PCFG markup from a bottom-up (input) template grammar and insert #pt… and #pn… specifiers for postfix production markup into a top-down (output) template grammar. On omitting this option, a bottom-up template grammar must not contain source PCFG markup.

--dump-first

Indicate expected sets of terminal and nonterminal symbols in comments in an intermediate grammar dumped by the option --out-gram-interm=FILE.

--er-vnont-scope=grammar|nont|leaf

The scope of uniqueness of error virtual nonterminal symbols ‘__ER…’:

grammar

One error virtual nonterminal symbol ‘__ER’ per the entire top-down template grammar.

nont

One error virtual nonterminal symbol ‘__ERidx’ per one nonterminal symbol of a top-down template grammar, where idx is a nonterminal symbol index.

leaf

One error virtual nonterminal symbol ‘__ERidx’ per one leaf of a regular expression for a nonterminal symbol of a top-down template grammar, where idx is the ordinal number of an error virtual nonterminal symbol.

The scopes ‘grammar’ and ‘nont’ enable the use of recursive nonterminal symbols in a bottom-up (input) template grammar.

The default value is ‘leaf’.

--in-seq=FILE

Extend a set of known terminal symbols extracted from a bottom-up (input) template grammar with terminal symbols contained in a terminal symbol sequence in a specified file. A set of known terminal symbols affects the interpretation of terminal symbol placeholders ‘.’ and exclusive terminal symbol classes. As a result of this, a set of known terminal symbols may affect the number of branches generated for parsing a set of terminal symbol sequences beginning with overlapping terminal symbol classes in a bottom-up template grammar.

-o, --out-gram-final=FILE

Dump a top-down (output) template grammar to a specified file. By default, dump the grammar to stdout.

--out-gram-interm=FILE

Dump to a file an intermediate grammar converted from a bottom-up (input) template grammar. The filename ‘-’ means stdout.

--remove-la

Where possible, remove put-back (lookahead) terminal symbols from a top-down (output) template grammar by introducing branches selectable nondeterministically.

--template

Replace all virtual terminal symbols and virtual terminal symbol classes in a top-down (output) template grammar with a generic virtual terminal symbol class denoted by [ :t: ]. Get rid of error virtual nonterminal symbols ‘__ER…’.

--terse

Use condensed format to dump the productions of a top-down (output) template grammar. By default, dump the productions in indented format.


7.9 pcfg-generate-seq

This tool generates a pseudo-random terminal symbol sequence according to a specified PCFG. The tool expands the start nonterminal symbol of the PCFG to produce a parse unit. If sequence limit not reached, the tool repeats expanding the start nonterminal symbol.

Example

$ cat sample.pcfg

  S: "a"              [0.5]
   | "b" "b"          [0.33]
   | "c" "c" "c" D_1  [0.17]
  ;

  D_1: "delta"
     | "delta" D_1
  ;

$ pcfg-generate-seq -i1 -n40 -o sample.seq sample.pcfg
$ cat sample.seq

  a c c c delta delta delta a a c c c delta a a a a a a b b a c c c
  delta delta delta a b b b b a a c c c delta a

Synopsis

In the usual case, use the command line format:

pcfg-generate-seq -iRANDOM_SEED -nLENGTH -o OUTPUT_SEQ_FILE   \
                  [ --separate-parse-units ] INPUT_PCFG_FILE

where INPUT_PCFG_FILE is the name of a file containing a PCFG (see PCFG Format); the filename ‘-’ means stdin.

Command-Line Options

The pcfg-generate-seq tool supports the following command line options:

-l INT

The maximum length of an output terminal symbol sequence, in characters. That length includes newline characters and delimiters between terminal symbols. No limit by default.

-n INT

The maximum length of an output terminal symbol sequence, in terminal symbols. No limit by default.

-N INT

The maximum length of an output terminal symbol sequence, in parse units. No limit by default.

-o FILE

Output a generated terminal symbol sequence to a specified file. By default, output the sequence to stdout.

-R, --margin-right=INT

If possible, limit the length of every line in an output terminal symbol sequence by a specified number of characters. Special value 0 means no right margin. The default value is 70.

-i, --seed=INT

A seed for the pseudo-random number generator. The default value is 0.

--separate-parse-units

If there is a right margin, separate generated parse units with empty lines. If there is no right margin, start every parse unit on a new line. The option -R, --margin-right=INT sets or removes the right margin. By default, do not separate generated parse units in a special way.

--separator-term=STR

Separate terminal symbols using a specified string. By default, separate terminal symbols by spaces.

--truncate[=no|parse-unit|term]

The mode of truncation of a generated character sequence if its length exceeds maximum length specified by the options -l INT, -n INT, and -N INT:

no

Ensure that the generated character sequence ends with a complete parse unit.

parse-unit

Permit the truncation of the last parse unit in the generated character sequence but ensure that the sequence ends with a complete terminal symbol name.

term

Permit the truncation of the last terminal symbol name in the generated character sequence.

On omitting the option argument, the tool uses --truncate=parse-unit. On omitting the option, the tool ensures that a generated character sequence ends with a complete parse unit.


7.10 pcfg-predict-eval

This tool evaluates the accuracy of prediction of every next symbol in a terminal symbol sequence by comparing the number of correctly predicted terminal symbols with a calculated upper bound on the number of terminal symbols predictable using a specified PCFG.

Example

The file predict_eval.pcfg contains the following PCFG:

$ cat predict_eval.pcfg

  S: "a" B "d"
  ;

  B: "b"
   | "c" "c"
  ;

Suppose, this PCFG has generated the following terminal symbol sequence stored in the file actual.seq:

$ cat actual.seq

  a c c d a b d

In this terminal symbol sequence, an upper bound on the number of correctly predictable terminal symbols is 6, as all 4 terminal symbols outside of subsequences ‘c c’ and ‘b’ are constant according to the PCFG, the sum of average numbers of correctly predictable terminal symbols at the second and sixth positions is 0.5+0.5=1, and the second ‘c’ always follows the first ‘c’ thereby adding 1 to the number of correctly predictable terminal symbols. An upper bound on the number of correctly predictable terminal symbols divided by sequence length is prob_wpredict_max=6.0/7=0.85714286.

While reading the terminal symbol sequence, a test program was trying to predict the next terminal symbol the PCFG generates. Suppose, the test program has predicted the following terminal symbol sequence and stored it in the file predicted.seq:

$ cat predicted.seq

  a c b d a d d

In this terminal symbol sequence, the number of correctly predicted terminal symbols is 5, because the terminal symbols ‘b’ and ‘d’ at the third and sixth positions differ from the terminal symbols ‘c’ and ‘b’ at the same positions in the actual terminal symbol sequence in the file actual.seq, and terminal symbols at all other positions are equal. The number of correctly predicted terminal symbols divided by sequence length is prob_npredict_actual=5.0/7=0.71428571.

The following command calculates and prints the aforementioned numbers prob_wpredict_max and prob_npredict_actual:

$ pcfg-predict-eval predict_eval.pcfg actual.seq predicted.seq

  {
      "seq_len"              : 7,
      "wpredict_max"         : 6.00000000,
      "npredict_actual"      : 5,
      "prob_wpredict_max"    : 0.85714286,
      "prob_npredict_actual" : 0.71428571
  }

Synopsis

Use the command line formats:

pcfg-predict-eval [options] PCFG_FILE ACTUAL_SEQ_FILE PREDICTED_SEQ_FILE
pcfg-predict-eval [options] PCFG_FILE COMBINED_SEQ_FILE

where:

PCFG_FILE

A PCFG (see PCFG Format) without left recursion. Along with a terminal symbol sequence generated according to the PCFG, they specify an upper bound on the number of correctly predictable terminal symbols. The tool may hang if the PCFG has an empty production.

ACTUAL_SEQ_FILE

An actual terminal symbol sequence. It is a terminal symbol sequence produced by a PCFG in PCFG_FILE. The sequence consists of (unquoted) terminal symbol names separated by spaces or single newline characters. Multiple consecutive newline characters separate parse units.

PREDICTED_SEQ_FILE

A predicted terminal symbol sequence for calculating prediction accuracy. The sequence consists of (unquoted) terminal symbol names separated by spaces or single newline characters. Multiple consecutive newline characters separate parse units. The number of terminal symbols in the sequence must be equal to the number of terminal symbols in a sequence in ACTUAL_SEQ_FILE. Parse unit segmentations in the two sequences must be at the same terminal symbol positions. Specify this argument equal to ACTUAL_SEQ_FILE to only calculate an upper bound on the number of terminal symbols correctly predictable in a terminal symbol sequence.

COMBINED_SEQ_FILE

A terminal symbol sequence combined from an actual terminal symbol sequence and predicted terminal symbol sequence. The combined sequence consists of terminal symbol pairs separated by spaces or single newline characters. Multiple consecutive newline characters separate parse units.

The first element of a pair is a quoted actual terminal symbol. The second element of a pair is a quoted predicted terminal symbol or ‘?’ if a predicted terminal symbol is unknown. Use the escape character ‘\’ to insert ‘"’ or ‘\’ into a quoted terminal symbol name. Allowed delimiters between an actual terminal symbol name and predicted terminal symbol name:

:

Any actual terminal symbol and predicted terminal symbol.

==

The actual terminal symbol equal to the predicted terminal symbol.

!=

The actual terminal symbol different from the predicted terminal symbol.

Output JSON Fields

The fields of JSON output have the following meaning:

seq_len

The number of terminal symbols in the actual or predicted terminal symbol sequence.

wpredict_max

An upper bound on the number of correctly predictable terminal symbols.

npredict_actual

The number of correctly predicted terminal symbols contained in the predicted terminal symbol sequence.

npredict_ngram

The number of terminal symbols correctly predicted in the actual terminal symbol sequence by applying the n-gram approach. The tool prints this field on passing the option --ngrams.

wpredict_rand

The number of correctly predicted terminal symbols in random mode. The tool prints this field on passing the option --prob-rand=FLOAT. This field is equal to the argument of that option multiplied by the field seq_len.

prob_wpredict_max

This field is equal to wpredict_max/seq_len.

prob_npredict_actual

This field is equal to npredict_actual/seq_len.

prob_npredict_ngram

This field is equal to npredict_ngram/seq_len. The tool prints the field on passing the option --ngrams.

prob_npredict_rand

This field is equal to the argument of --prob-rand=FLOAT option. The tool prints the field on passing this option.

efficiency_ngram, %

This field is equal to (npredict_actual-npredict_ngram)*100/(wpredict_max-npredict_ngram) except for the following special cases: if npredict_actual<npredict_ngram, the field is equal to 0; if npredict_actual>wpredict_max, the field is equal to 100. The program prints the field on passing the option --ngrams.

efficiency_rand, %

This field is equal to (prob_npredict_actual-prob_npredict_rand)*100/(prob_wpredict_max-prob_npredict_rand) except for the following special cases: if prob_npredict_actual<prob_npredict_rand, the field is equal to 0; if prob_npredict_actual>prob_wpredict_max, the field is equal to 100. The program prints the field on passing the option --prob-rand=FLOAT.

Dumping Processing Steps

The option --intermediate dumps details about calculating an upper bound on the number of correctly predictable terminal symbols while processing every terminal symbol from an actual and predicted terminal symbol sequence.

Example

$ pcfg-predict-eval --intermediate predict_eval.pcfg actual.seq predicted.seq
step 0: actual "a", predicted "a", prob_max 1.00000000, npredict 1, wpredict_max 1.00000000
step 1: actual "c", predicted "c", prob_max 0.50000000, npredict 2, wpredict_max 1.50000000
step 2: actual "c", predicted "b", prob_max 1.00000000, npredict 2, wpredict_max 2.50000000
step 3: actual "d", predicted "d", prob_max 1.00000000, npredict 3, wpredict_max 3.50000000
step 4: actual "a", predicted "a", prob_max 1.00000000, npredict 4, wpredict_max 4.50000000
step 5: actual "b", predicted "d", prob_max 0.50000000, npredict 4, wpredict_max 5.00000000
step 6: actual "d", predicted "d", prob_max 1.00000000, npredict 5, wpredict_max 6.00000000

{
    "seq_len"              : 7,
    "wpredict_max"         : 6.00000000,
    "npredict_actual"      : 5,
    "prob_wpredict_max"    : 0.85714286,
    "prob_npredict_actual" : 0.71428571
}

For every pair of terminal symbols read from the actual and predicted terminal symbol sequence, the tool prints a line with the following fields:

step

The index (position) of a terminal symbol in the actual or predicted terminal symbol sequence. Indices start with 0.

actual

A terminal symbol read from the actual terminal symbol sequence.

predicted

A terminal symbol read from the predicted terminal symbol sequence.

prob_max

The probability of correct prediction of a terminal symbol in the field actual based on the input PCFG and previous terminal symbols read from the actual terminal symbol sequence.

npredict

The number of times terminal symbols in the fields actual and predicted were equal (up to the current line).

wpredict_max

The sum of prob_max fields up to the current line.

Dumping Survived Stacks

The option --dump-stacks along with --intermediate prints survived stacks of expanding the start nonterminal symbol of an input PCFG before processing every terminal symbol from the actual terminal symbol sequence and after processing the last terminal symbol from that sequence.

Example

$ pcfg-predict-eval --dump-stacks --intermediate predict_eval.pcfg actual.seq predicted.seq
1.00000000  "a" <- S [0]

step 0: actual "a", predicted "a", prob_max 1.00000000, npredict 1, wpredict_max 1.00000000

0.50000000  "b" <- B [1] <- S [0]
0.50000000  "c" <- B [1] <- S [0]

step 1: actual "c", predicted "c", prob_max 0.50000000, npredict 2, wpredict_max 1.50000000

1.00000000  "c" <- B [1] <- S [0]

step 2: actual "c", predicted "b", prob_max 1.00000000, npredict 2, wpredict_max 2.50000000

1.00000000  "d" <- S [0]

step 3: actual "d", predicted "d", prob_max 1.00000000, npredict 3, wpredict_max 3.50000000

1.00000000  "a" <- S [4]

step 4: actual "a", predicted "a", prob_max 1.00000000, npredict 4, wpredict_max 4.50000000

0.50000000  "b" <- B [5] <- S [4]
0.50000000  "c" <- B [5] <- S [4]

step 5: actual "b", predicted "d", prob_max 0.50000000, npredict 4, wpredict_max 5.00000000

1.00000000  "d" <- S [4]

step 6: actual "d", predicted "d", prob_max 1.00000000, npredict 5, wpredict_max 6.00000000

1.00000000  "a" <- S [7]

The description of every survived stack (e.g. ‘0.50000000 "b" <- B [5] <- S [4]’) begins with its probability followed by stack content in reverse order—from a terminal symbol (in the actual terminal symbol sequence) to the start nonterminal symbol. Numbers in square brackets after nonterminal symbols are indices of terminal symbols (in the actual terminal symbol sequence) that initiated expansions of the nonterminal symbols. A number in square brackets can precede another number in square brackets indicating a sub-step incremented on encountering productions with empty right-hand sides for a nonterminal symbol at the left-hand side.

Dumping Possible Terminal Symbols

The option --dump-terms along with --intermediate prints probabilities of possible terminal symbols calculated before processing every terminal symbol from the actual terminal symbol sequence and after processing the last terminal symbol of that sequence.

Example

$ pcfg-predict-eval --dump-terms --intermediate predict_eval.pcfg actual.seq predicted.seq
1.00000000  "a" *

step 0: actual "a", predicted "a", prob_max 1.00000000, npredict 1, wpredict_max 1.00000000

0.50000000  "b" *
0.50000000  "c" *

step 1: actual "c", predicted "c", prob_max 0.50000000, npredict 2, wpredict_max 1.50000000

1.00000000  "c" *

step 2: actual "c", predicted "b", prob_max 1.00000000, npredict 2, wpredict_max 2.50000000

1.00000000  "d" *

step 3: actual "d", predicted "d", prob_max 1.00000000, npredict 3, wpredict_max 3.50000000

1.00000000  "a" *

step 4: actual "a", predicted "a", prob_max 1.00000000, npredict 4, wpredict_max 4.50000000

0.50000000  "b" *
0.50000000  "c" *

step 5: actual "b", predicted "d", prob_max 0.50000000, npredict 4, wpredict_max 5.00000000

1.00000000  "d" *

step 6: actual "d", predicted "d", prob_max 1.00000000, npredict 5, wpredict_max 6.00000000

1.00000000  "a" *

The description of a possible terminal symbol (e.g. ‘0.50000000 "b" *’) begins with its probability followed by the terminal symbol itself. If the probability is equal to a maximum probability among probabilities of all possible terminal symbols, the description ends with ‘*’. The field prob_max is equal to the maximum probability.

If the actual terminal symbol sequence conforms to an input PCFG, every terminal symbol of that sequence belongs to a set of possible terminal symbols determined just before reading the terminal symbol from the sequence. If the terminal symbol does not belong to the set, the tool reports an error ‘step INDEX: no expansion stacks survived on processing terminal symbol STRING’.

You can combine the option --dump-terms with --dump-stacks.

All Command-Line Options

The pcfg-predict-eval tool supports the following command line options:

--dump-stacks

Print survived stacks of expanding the start nonterminal symbol of a PCFG. On passing the option --intermediate, the tool prints the survived stacks before processing every terminal symbol from the actual terminal symbol sequence and after processing the last terminal symbol of that sequence. Without the option --intermediate, the tool prints the stacks survived after processing the last terminal symbol only. See “Dumping Survived Stacks”, for more information. You can combine the option --dump-stacks with --dump-terms. By default, do not print the survived stacks.

--dump-terms

Print probabilities of possible terminal symbols. On passing the option --intermediate, the tool prints the probabilities before processing every terminal symbol from the actual terminal symbol sequence and after processing the last terminal symbol of that sequence. Without the option --intermediate, the tool prints the probabilities after processing the last terminal symbol only. See “Dumping Possible Terminal Symbols”, for more information. You can combine the option --dump-terms with --dump-stacks. By default, do not print probabilities of possible terminal symbols.

--intermediate

Print information about processing steps, survived stacks, and probabilities of possible terminal symbols for every processed terminal symbol from the actual terminal symbol sequence. See “Dumping Processing Steps”, for fields printed in every processing step. By default, only print survived stacks and probabilities of possible terminal symbols after processing the last terminal symbol.

-n INT

Process not more than a specified number of terminal symbols from the actual terminal symbol sequence or predicted terminal symbol sequence or process not more than a specified number of symbol pairs from the combined terminal symbol sequence. By default, process all sequence symbols.

--ngrams

Calculate the number of terminal symbols correctly predicted in the actual terminal symbol sequence based on collected n-grams and calculate the efficiency (accuracy) of prediction using the n-gram approach. This mode slows down processing terminal symbol sequences. By default, do not apply the n-gram approach and do not print JSON fields related to n-grams.

-o FILE

Dump processing results to a specified file. By default, dump processing results to stdout.

--prob-rand=FLOAT

The probability of a terminal symbol correctly predicted in random mode. This is a lower bound to compare with the probability of a terminal symbol correctly predicted in adaptive mode to calculate prediction efficiency (accuracy). By default, do not calculate prediction efficiency relative to the probability of a terminal symbol correctly predicted in random mode.

-R, --margin-right=INT

If possible, limit the length of every line of printed processing results by a specified number of characters. By default, do not limit the line lengths.


8 Example Programs

This chapter describes two example programs demonstrating the use of actors. This manual does not include the source code of these example programs. The source code is available in the directory samples in the package distribution. The command make install installs the source code of the example programs to the directory $prefix/share/qsmm/samples. If the configure script has configured QSMM to install example programs, the command make install installs their binaries with adding the prefix ‘qsmm-example-’ to names of the binaries (to prevent possible clashes with binaries belonging to other packages). See the file INSTALL in the root of the package distribution for information on the configure script.


8.1 pic-guess

This program reduces the actor algorithm to a simple method of finding values for a set of boolean variables to maximize an objective function depending on the variables.

The program uncovers the bitmap of ‘A’, ‘B’, ‘C’, ‘D’, or ‘E’ letter by generating a trial bitmap and passing it to an opaque function returning a measure of similarity between a trial bitmap and bitmaps of the letters hard-coded into the program. The opaque function also returns a flag indicating whether the trial bitmap is equal to one of the five letter bitmaps. If it is so, program execution finishes. All bitmaps have size 8x8.

The measure of similarity between a trial bitmap and the five letter bitmaps is equal to the maximum measure of similarity among the measures of similarity between the trial bitmap and each letter bitmap. The measure of similarity between a trial bitmap and letter bitmap is the number of equal bits at the same locations in the two bitmaps divided by 64 and multiplied by a predefined weight for the letter bitmap. You pass the five predefined weights on the command line. The program should detect a bitmap with a maximum predefined weight using a minimum number of trials (steps).

Spur accumulated by the actor is equal to ln x, where x is the measure of similarity between the last trial bitmap and the five letter bitmaps. The actor uses ey as the relative probability of an output signal, where y is a spur increment over a cycle type. The row and column of a bit in a trial bitmap specify an action choice state. Every action choice state has two output signals specifying the cycle directions as possible values of a bit—the presence or absence of a dot at that location. Every trial (step) consists of generating bits for all locations in a trial bitmap, calculating the measure of similarity for the trial bitmap, and updating the spur according to that measure.

The command line has the format:

qsmm-example-pic-guess weight_A weight_B weight_C weight_D weight_E seed

where weight_A, ..., weight_E are predefined weights for the bitmaps of ‘A’, ..., ‘E’, and seed is a random seed. If the random seed is non-negative, the actor operates adaptively, otherwise it operates randomly.

For example, when calling the program using the command line

$ qsmm-example-pic-guess 0.95 0.95 1 0.95 0.95 seed

where seed is in the range 1 to 20, the program correctly uncovers the letter ‘C’ in 17 of 20 runs.

For example, the call

$ qsmm-example-pic-guess 0.95 0.95 1 0.95 0.95 20

results in the output

   X  X  X  X  X  X

X  X  X  X  X  X  X  X

X  X

X  X

X  X

X  X

X  X  X  X  X  X  X  X

   X  X  X  X  X  X



Step: 746

Press [Q] to exit

where 746 is the number of trial bitmaps generated to detect the bitmap of ‘C’.

The file samples/pic_guess.c in the package distribution contains source code of this example program. The command make builds the example program if the configure script has configured QSMM to use the ncurses library. See the file INSTALL in the root of the package distribution for information on the configure script.


8.2 test

This program demonstrates basic features of actor algorithms used in QSMM. The paper “An Approach to Optimal Action Generation for a System that Interacts with the Environment” describes them. Starting from QSMM version 1.16, the package distribution does not include that paper, because despite being informative, the paper contains serious unfixed mistakes.

The program performs interaction between a system and an environment represented by a deterministic finite automaton. The system is either homogeneous or consists of two subsystems, where the first subsystem identifies a current environment state, and the second subsystem generates an adaptive action based on the current state. The program can read the description of a deterministic finite automaton representing the environment from a file specified by a program argument or generate the automaton randomly on the fly.

The files test.c, eemat.h, eemat.c, findcyc_ee.h, and findcyc_ee.c in the subdirectory samples in the root of the package distribution contain source code of this example program.

The Format of an Automaton File

A text file describes a deterministic finite automaton representing an environment. A text file example is below:

Non-empty line #1
Non-empty line #2
       ...
Non-empty line #n

2 5 3 0
1 0 0 0 0
1/3 2/4
2/1 1/2
0/4 1/0

The parser of an automaton file ignores all lines before the first empty line. The first line after that empty line has the format

number_of_input_signals number_of_output_signals number_of_states initial_state_index

Indices of signals and states start from 0.

The second line after the empty line contains floating-point numbers specifying spur increments for all output signals. The increments take place when the automaton emits corresponding output signals.

Starting from the third line after the empty line, there go descriptions of transitions between states on receiving input signals. The third line corresponds to transitions from state 0, the fourth—from state 1, the fifth—from state 2, and so on. Each line contains number pairs corresponding to input signals. The first pair corresponds to input signal 0, the second—to input signal 1, the third—to input signal 2, and so on. Each pair has the format

target_state/output_signal

and specifies a transition from a source state to a target state with emitting an output signal on receiving an input signal.

Generating Random Automatons

Use the following command to generate a random deterministic finite automaton:

qsmm-example-test -o out_file -i random_seed [ -C VAL ] num_in_sig num_out_sig num_states

This command creates a file out_file containing the description of a deterministic finite automaton generated using seed random_seed. The automaton has specified numbers of input signals, output signals, and states. If a random seed not specified, the program uses a standard fixed random seed. The first output signal has spur increment 1, and all other output signals have spur increment 0.

If the program receives the option -C VAL, and VAL is not 0, the automaton has its state graph connected. If VAL is positive, the program simplifies the automaton, makes it to have not more than VAL cycles in the graph, and finds the best cycle in the graph. See a description of -C VAL option in “Options Common for Both System Types” for what the automaton simplification is. Continuous repeating the best cycle supplies the maximum amount of spur to the system. If VAL is relatively small, the program may not generate the automaton at one push. If an attempt to generate the automaton fails, the program prints a warning message and makes another attempt. If VAL is relatively large, an attempt to generate the automaton may take a long time, so the impression can be that the program has hung.

The special option argument VAL=‘c’ makes the program provide state graph connectivity and find the best cycle in the graph using an algorithm analogous to Viterbi one. The special option argument VAL=‘cs’ makes the program provide state graph connectivity, simplify the state graph by a method also used when VAL is positive, and find the best cycle in the graph by an algorithm analogous to Viterbi one.

The program writes the random seed value to comment lines before the first empty line in out_file. If the option -C VAL has a non-zero VAL, the program also writes to the comment lines information on the best cycle in the state graph:

  • best cycle length as the number of cycle steps;
  • an increment in spur the system receives on repeating the best cycle;
  • average spur increment per step of the best cycle;
  • a list of steps of the best cycle; a description of each step contains a step index stp, an automaton state index stt, an input signal inp received when the automaton was in this state, an output signal out emitted, and a spur increment spr corresponding to the output signal.

Performing the Interaction

Use the following command to run a test of algorithm efficiency consisting of num_passes passes with a new random deterministic finite automaton that has specified numbers of input signals, output signals, and states generated at each pass:

qsmm-example-test -t num_passes [ -C VAL ] [ additional options ]  \
                  num_in_sig num_out_sig num_states

On passing the option -C VAL with a non-zero VAL, the program provides connectivity for generated automaton state graphs and finds best cycles in them. An example of a test log printed by the command is below:

$ qsmm-example-test -t10 -Ccs 20 20 20
    DFA inputs: 20
   DFA outputs: 20
    DFA states: 20
 Input signals: dfa-state
        Passes: 10
Steps per pass: 10000
         Large: off
 R. prob. type: 1
 N-gram length: 1
 Algorithms v.: 0
       K*temp.: 1.000000000000000E+00
   Max. cycles: -2
   Random seed: 0

pass       earned     random      maximal cl    % efr   % efa
---- ------------ ---------- ------------ -- -------- -------
   1     5821.000    331.000     7500.000  4 1758.610  76.580
   2     5826.000    441.000    10000.000  2 1321.088  56.334
   3     5656.000    359.000     6666.667  3 1575.487  83.977
   4     6443.000    414.000    10000.000  2 1556.280  62.894
   5     7901.000    462.000    10000.000  2 1710.173  77.993
   6     5949.000    329.000     7142.857  7 1808.207  82.479
   7     4272.000    281.000     6666.667  3 1520.285  62.499
   8     8781.000    411.000    10000.000  2 2136.496  87.288
   9     8144.000    648.000    10000.000  2 1256.790  80.154
  10     4671.000    270.000     6000.000  5 1730.000  76.806

TOTL    63464.000   3946.000    83976.190  3 1608.312  74.369

stddev efr:  252.956
stddev efa:   10.430

The log begins with a description of test modes used followed by a table, where each row corresponds to a test pass, followed by a summary row. The columns of the table have the following meaning:

pass

A test pass index. In the summary row—‘TOTL’.

earned

The amount of spur the system received during interaction with the automaton according to the algorithm. In the summary row—the sum of values in the column.

random

The amount of spur the system received during random interaction with the automaton when the system was equiprobably selecting output signals from a set of allowed signals. In the summary row—the sum of values in the column.

maximal

The amount of spur the system would receive during the most optimal interaction with the automaton. The program calculates this amount on passing the option -C VAL with a non-zero VAL. Otherwise, the amount is equal to the number of steps in a test pass. In the summary row—the sum of values in the column.

cl

Best cycle length. The program calculates the length on passing the option -C VAL with a non-zero VAL. Otherwise, the length is equal to 0. In the summary row—the average length of best cycles for all test passes.

% efr

Relative efficiency equal to (earned/random)*100%. For the summary row, the formula uses the variables from that row.

% efa

Actual efficiency equal to (earned-random)/(maximal-random)*100%. For the summary row, the formula uses the variables from that row.

At the end of the log, the program prints a standard deviation of values in the column ‘% efr’ and a standard deviation of values in the column ‘% efa’.

Running Multiple Test Passes for a Single Automaton

Use the following command to run a specific number of test passes for an automaton defined in FILE according to the format described in “The Format of an Automaton File”:

qsmm-example-test -t num_passes [ -C VAL ] [ additional options ] -f FILE

The program verifies the connectivity of an automaton state graph. If VAL is positive, the program also verifies that the number of cycles in the graph is less than or equal to VAL. If VAL is not 0, the program prepends the test log with information on the best cycle in the automaton state graph as described in “Generating Random Automatons”.

Options Common for Both System Types

Below there is a description of program options applicable to both system types: a homogeneous system and a system comprised of two subsystems, where the first subsystem is an environment state identification subsystem, and the second subsystem is an action emission subsystem.

-C, --ncycle-max=VAL

Parameters related to automaton state graphs: state connectivity, simplification, limiting the number of cycles, and best cycle search. In the description of test modes—‘Max. cycles’. Supported option arguments:

0

Do not provide the state connectivity, do not perform the simplification, do not limit the number of cycles in the graph, and do not find the best cycle. This is default mode.

>0

Provide the state connectivity, perform the simplification, limit the number of cycles in the graph by VAL, and find the best cycle.

“c”

Provide the state connectivity and find the best cycle by an algorithm analogous to Viterbi one. In the description of test modes—‘Max. cycles: −1’.

“cs”

Provide the state connectivity, perform the simplification, and find the best cycle by an algorithm analogous to Viterbi one. In the description of test modes—‘Max. cycles: −2’.

The simplification of an automaton state graph consists in replacing transitions from (source) states to other states with transitions to the same (source) states on condition that resulting transitions do not yield positive spur increments, and each replacement does not break graph connectivity.

On searching the best cycle in the state graph, the program prints in the table column ‘maximal’ the maximum amount of spur the system would receive during the most optimal interaction with the automaton.

-f FILE

A file with an automaton definition. On omitting this option, generate a random automaton. In the description of test modes—‘Automaton file’.

-i, --seed=INT

A seed to initialize the pseudo-random number generator. The default value is 0. In the description of test modes—‘Random seed’.

--kt=FLOAT

The temperature (multiplied by some constant) of the homogeneous system or the temperature of the environment state identification subsystem and action emission subsystem. The default value is 1. This option requires testing mode turned on by the option -t, --test=INT. In the description of test modes—‘K*temp.’.

-n, --nstep-pass=INT

The number of steps of interaction with a deterministic finite automaton at each test pass. The automaton receives an input signal and emits an output signal in each step. The default value is 10000. This option requires testing mode turned on by the option -t, --test=INT. In the description of test modes—‘Steps per pass’.

-o FILE

A file to write program output to instead of stdout.

--out-step-efa=FILE

A file to write a table consisting of lines where each line contains two numbers separated by a space: step index and the actual efficiency (‘% efa’) of interaction between a system and deterministic finite automaton calculated for the step range from 0 to the step index. By default, do not write the table. This option requires testing mode turned on by the option -t, --test=INT.

--out-step-efr=FILE

A file to write a table consisting of lines where each line contains two numbers separated by a space: step index and the relative efficiency (‘% efr’) of interaction between a system and deterministic finite automaton calculated for the step range from 0 to the step index. By default, do not write the table. This option requires testing mode turned on by the option -t, --test=INT.

-t, --test=INT

Perform the test a specified number of passes. This option turns on testing mode. On passing the option -f FILE, the program uses a supplied automaton for all test passes. Otherwise, at each test pass, the program generates a new random automaton with the number of input signals, output signals, and states specified by arguments at the end of command line. In the description of test modes—‘Passes’.

The Case of a Homogeneous System

A system interacting with an automaton is homogeneous unless the program receives the option -s, --nstate=INT. For this kind of a system, the program supports a special list of options described below. All options require testing mode turned on by the option -t, --test=INT.

-c, --compat=0|1|2|3

Compatibility level of algorithms assigned to the field compat of qsmm_actor_desc_s structure. The default value is 0. This option conflicts with the option -L, --large[=INT]. In the description of test modes—‘Algorithms v.’.

-I, --input=dfa-state|dfa-out

The type of informational signals for the system:

dfa-state

automaton states (default mode)

dfa-out

automaton output signals

In the description of test modes—‘Input signals’.

-l, --ngram-length=INT

The length of a system state n-gram. The default value is 1. If the type of informational signals for the system is ‘dfa-out’, n-gram length 2 may lead to better efficiency. In the description of test modes—‘N-gram length’.

-L, --large[=INT]

Use a large actor with a specified tree arity. The default value is 2. By default, use a small actor. In the description of test modes—‘Large’ and ‘Tree arity’.

-P, --relprob-type=0|1|2|3

The type of a function returning the relative probability of an output signal:

0

QSMM_RELPROB_USER1 without a helper function provided

1

QSMM_RELPROB_BUILTIN1 (default mode)

2

QSMM_RELPROB_BUILTIN2

3

QSMM_RELPROB_BUILTIN3

In the description of test modes—‘R. prob. type’.

The Case of a System Comprised of Two Subsystems

If the program receives the option -s, --nstate=INT specifying the number of tracked environment states, a system interacting with an automaton representing an environment consists of two subsystems, where the first subsystem identifies a current environment state, and the second subsystem generates an adaptive action based on the current state. For the interaction with the automaton to be efficient, the number of interaction steps in each test pass should be much greater than in the case of a homogeneous system. In this mode of operation the program supports the following special list of options.

--kt-env=FLOAT

The temperature (multiplied by some constant) of the environment state identification subsystem. The default value is 1 unless overridden by the option --kt=FLOAT. In the description of test modes—‘K*temp. env.’.

--kt-iee=FLOAT

The temperature (multiplied by some constant) of the action emission subsystem. The default value is 1 unless overridden by the option --kt=FLOAT. In the description of test modes—‘K*temp. opt.’.

-s, --nstate=INT

The number of tracked environment states. To achieve better efficiency, specify that number twice or more times greater than the number of states of a deterministic finite automaton representing an environment. This option requires testing mode turned on by the option -t, --test=INT. In the description of test modes—‘Tracked states’.

How to Produce Efficiency Plots

In QSMM 1.19, the program test supports a simple method for producing the plots of dependency of actual efficiency of interaction with deterministic finite automatons on interaction step index. The paper “An Approach to Optimal Action Generation for a System that Interacts with the Environment” mentioned at the beginning of test includes similar plots.

To generate a dataset FILE for creating a plot (e.g. by the program gnuplot), pass the new option --out-step-efa=FILE to the program test. The dataset contains two columns: the number of steps in a test pass and corresponding actual efficiency (in percents) of interaction with deterministic finite automatons.

Example:

$ qsmm-example-test -t20 -s20 -n100000 -Ccs -o test.log      \
                    --out-step-efa=ds_10_10_10_s20 10 10 10

$ tail -n8 test.log
  18    73419.000  10324.000   100000.000  3  711.149  70.359
  19    49915.000   6017.000    71428.571  7  829.566  67.110
  20    84545.000  15664.000   100000.000  7  539.741  81.674

TOTL  1117415.000 163148.000  1701428.571  4  684.909  62.035

stddev efr:  283.697
stddev efa:   23.567
$ wc -l <ds_10_10_10_s20
100000
$ head -n4 ds_10_10_10_s20
0 0
1 -9.66851
2 -2.12572
3 -3.17173
$ tail -n4 ds_10_10_10_s20
99996 62.0346
99997 62.0346
99998 62.0346
99999 62.0347

9 Auxiliary Programs

This chapter describes auxiliary programs, which are not part of core QSMM functionality. This manual does not include the source code of these auxiliary programs. The source code is available in the directory tools in the package distribution.

The command make install installs the script mk-rg-vit.sh. If the configure script has configured QSMM to install example programs, the command make install installs binaries of the auxiliary programs with adding the prefix ‘qsmm-example-’ to names of the binaries (to prevent possible clashes with binaries belonging to other packages). See the file INSTALL in the root of the package distribution for information on the configure script.


9.1 osct

This program prints an output signal choice tree a large actor uses to generate output signals with various profile probabilities. By default, it is a Huffman tree generated for a list of declared profile probabilities of output signals.

As the profile probability of an output signal determined by the structure of a Huffman tree is equal to tree arity raised to integer power equal to negative depth of a tree node for the output signal, actual profile probability of an output signal can be substantially different from its declared profile probability. On passing the option -t, --tolerance=FLOAT, a large actor restructures the Huffman tree by node splitting and adding leaves for output signals so that multiple leaves can correspond to a single output signal. As a result of this restructuring, the output signal choice tree provides selecting output signals with actual profile probabilities that differ from declared profile probabilities by a value less than the argument of that option.

Run the program using the following command line formats:

qsmm-example-osct [OPTIONS] -N NSIG_OUT
qsmm-example-osct [OPTIONS] -f SIG_WEIGHT_FILE
qsmm-example-osct [OPTIONS] WEIGHT1 ... WEIGHTn

where WEIGHT1WEIGHTn are declared relative profile probabilities of output signals.

Example

The following command prints an output signal choice tree for selecting one of five output signals with equal declared profile probabilities:

$ qsmm-example-osct -N 5

  +---+---+--- [0.12500000] 1
  |   |   |
  |   |   +--- [0.12500000] 0
  |   |
  |   +--- [0.25000000] 4
  |
  +---+--- [0.25000000] 3
      |
      +--- [0.25000000] 2

Numbers in ‘[’ … ‘]’ are actual profile probabilities of tree leaves, and numbers after ‘]’ are indices of output signals corresponding to tree leaves.

As declared profile probability of every output signal is 1.0/5=0.2, actual profile probabilities 0.125 and 0.25 indicated in the output signal choice tree above differ from the declared profile probability significantly—by 0.2-0.125=0.075 and 0.25-0.2=0.05 respectively. Passing the option -t 0.005 makes the differences be less than 0.005:

$ qsmm-example-osct -N 5 -t 0.005 --ow=weights

  +---+---+--- [0.12500000] 1
  |   |   |
  |   |   +---+--- [0.06250000] 1
  |   |       |
  |   |       +--- [0.06250000] 0
  |   |
  |   +---+--- [0.12500000] 0
  |       |
  |       +--- [0.12500000] 4
  |
  +---+---+--- [0.12500000] 2
      |   |
      |   +--- [0.12500000] 3
      |
      +---+---+--- [0.06250000] 3
          |   |
          |   +--- [0.06250000] 4
          |
          +---+---+---+--- [0.01562500] 4
              |   |   |
              |   |   +--- [0.01562500] 2
              |   |
              |   +---+---+--- [0.00781250] 1
              |       |   |
              |       |   +--- [0.00781250] 0
              |       |
              |       +--- [0.01562500] 3
              |
              +--- [0.06250000] 2

The above tree has multiple leaves for each output signal. The created file weights contains four columns: the index of an output signal, its declared profile probability, its actual profile probability, and absolute difference between the two profile probabilities.

$ cat weights

  0 0.20000000 0.19531250 0.00468750
  1 0.20000000 0.19531250 0.00468750
  2 0.20000000 0.20312500 0.00312500
  3 0.20000000 0.20312500 0.00312500
  4 0.20000000 0.20312500 0.00312500

The above table shows that the maximum difference between the declared profile probability and an actual profile probability is 0.0046875, which is considerably less than 0.075 for the non-restructured (original) tree.

The program supports the following command line options:

--arity=INT

Generate an output signal choice tree with a specified arity. It is the maximum number of child nodes of every tree node. The default value is 2.

-f FILE

Read declared relative profile probabilities of output signals from a specified file. The filename ‘-’ means stdin. Each line of the file should contain the index of an output signal and its declared relative profile probability separated by a space. Declared profile probabilities of output signals not present in the file are zero.

-N INT

Use equal declared profile probabilities for a specified number of output signals. Each declared profile probability is equal to 1 divided by the number of output signals.

--ot=FILE

Dump a generated output signal choice tree to a specified file. By default, dump the tree to stdout.

--ow[=FILE]

Dump to a specified file or stdout a table where each line contains the index of an output signal, its declared profile probability, its actual profile probability, and absolute difference between the two probabilities.

-t, --tolerance=FLOAT

Restructure a Huffman tree to obtain an output signal choice tree where absolute difference between a declared profile probability and actual profile probability for every output signal is less than a specified value. On omitting this option, use a Huffman tree as an output signal choice tree.


9.2 mk-rg-vit.sh

This script generates top-down template grammars for segmenting symbol sequences into words. The script has the following command line format:

mk-rg-vit.sh MAX_WORD_LENGTH MAX_SEGMENT_LENGTH N_PROD_1 ... N_PROD_n

The script arguments:

MAX_WORD_LENGTH

Maximum word length in terminal symbols.

MAX_SEGMENT_LENGTH

Maximum word segment length in terminal symbols. A word segment is a sequence of ‘.’ inside a regular expression. A word segment corresponds to a part of a word. Specify this argument equal to MAX_WORD_LENGTH to generate word segments with all allowed lengths.

N_PROD_i

The maximum number of possible terminal symbols to consider at position i in a word. Each possible terminal symbol determines parsing a remaining word part. For all j>i, if arguments N_PROD_j are absent on the command line, the script considers them equal to N_PROD_i.

The script dumps a generated regular expression grammar to stdout.

Example

$ mk-rg-vit.sh 4 3 2
S: .
 | .
 | . L3_0
 | . L3_1
 | . .
 | . .
 | . . L2_0
 | . . L2_1
 | . . .
 | . . .
;

L2_0: .
    | .
    | . .
    | . .
;

L2_1 = L2_0 ;

L3_0: .
    | .
    | . ( .
        | .
        | . .
        | . .
        )
    | . ( .
        | .
        | . .
        | . .
        )
    | . .
    | . .
    | . . .
    | . . .
;

L3_1 = L3_0 ;

Nonterminal symbols Li_j correspond to remaining parts of a word, where i is the maximum length of a remaining part in terminal symbols, and j is the index of a copy of the remaining part. To reduce the size of a generated grammar, it contains productions for copies with indices greater than 0 by shallow copying a production with index 0 (see Cloning Nonterminal Symbols).

See Examples, for using the script mk-rg-vit.sh to generate top-down template grammars for dividing terminal symbol sequences into words.


9.3 pcfg-reach

The purpose of this program is debugging removing unreachable productions from a PCFG and simplifying it.

To remove unreachable productions from a PCFG, use the following command line format:

qsmm-example-pcfg-reach [ --dump-prob ] PCFG_FILE [ RETAIN_NONT_1 ... RETAIN_NONT_n ]

where PCFG_FILE is the name of a file with the PCFG (see PCFG Format), and RETAIN_NONT_1, ..., RETAIN_NONT_n are nonterminal symbols to retain in a resulting PCFG even if they are unreachable. The option --dump-prob turns on printing probabilities of productions in a resulting PCFG.

Example

The file reachable.pcfg contains the following PCFG:

$ cat reachable.pcfg

  S: "s" A    [0.3]
   | A A      [0.7]
  ;

  A: "b"      [0.6]
   | "a" "b"  [0.4]
  ;

  B: "c"      [0.5]
   | "b" C    [0.5]
  ;

  C: "e"      [0.8]
   | "d" B    [0.2]
  ;

This command prints a PCFG with unreachable productions removed:

$ qsmm-example-pcfg-reach --dump-prob reachable.pcfg

  S: "s" A  [0.3]
   | A A    [0.7]
  ;

  A: "b"      [0.6]
   | "a" "b"  [0.4]
  ;

To remove unreachable productions from a PCFG and simplify it, use the command line format:

qsmm-example-pcfg-reach --simplify PCFG_FILE [ RETAIN_NONT_1 ... RETAIN_NONT_n ]

where PCFG_FILE is the name of a file with the PCFG, and RETAIN_NONT_1, ..., RETAIN_NONT_n are nonterminal symbols to retain in a resulting PCFG even if they are subject to removal because of PCFG simplification.

Example

The file simplify.pcfg contains the following PCFG:

$ cat simplify.pcfg

  S: "a"
   | B
   | C "s" C "s" C
   | F F
  ;

  B: "b"
   | "b" "b"
  ;

  C: "c" ;
  D: ;
  E: "e" "e" "e" ;

  F: D "d" D
   | "d"
   | "f" "f" E "f" "f"
  ;

This command prints a simplified PCFG with unreachable productions removed:

$ qsmm-example-pcfg-reach --simplify simplify.pcfg

  S: "a"
   | "b"
   | "b" "b"
   | "c" "s" "c" "s" "c"
   | F F
  ;

  F: "d"
   | "f" "f" "e" "e" "e" "f" "f"
  ;

9.4 rege-asm

The purpose of this program is debugging generating an assembler program and context-free grammar for a regular expression possibly located at the right-hand side of a production of a regular expression grammar.

The instruction set of a generated assembler program includes instructions for analyzing look-ahead terminal symbols, consuming terminal symbols, incrementing frequencies of productions of a context-free grammar, transferring control to subroutines for parsing nonterminal symbols, and returning control from the subroutines. For more information, see Assembler Instruction Set and Assembler Instruction Set.

A sequence of subexpressions in a regular expression results in a sequence of code blocks for the subexpressions in a generated assembler program. Assembler code blocks for ‘?’ and ‘*’ quantifiers and sets of alternatives separated by ‘|’ have specific structure. See Assembler Program Structure, for more information.

Run the program using one of the following command line formats.

  1. Dumping an assembler program containing simplified instructions for a regular expression:
    qsmm-example-rege-asm [ --nterm-min=INT ] REGEX
    
  2. Dumping an assembler program containing normal instructions for a regular expression:
    qsmm-example-rege-asm [ --nterm-min=INT ] [ --eos-marker ] --dump-asm=extended REGEX
    
  3. Dumping a context-free grammar for a regular expression:
    qsmm-example-rege-asm --dump-gram[=specific|replace] [ --recurs=right ] REGEX
    
  4. Dumping statistics on a regular expression:
    qsmm-example-rege-asm --dump-stats REGEX
    

The argument REGEX is a regular expression. Refer to Productions, for the regular expression syntax.

Example

$ qsmm-example-rege-asm --dump-asm=extended '([ "a" "b" ] D D .)* [ "b" "c" ]'
        ; BEG: ([ "a" "b" ] D D .)* [ "b" "c" ]
        prod    "E", 0
        ; BEG: ([ "a" "b" ] D D .)*
r1:
        ; FIRST: [ "a" "b" "c" ]
        peek    1
        joe     0, b1   ; "a"
        joe     1, t1_1 ; "b"
        jmp     s1      ; "c"
t1_1:
        ; "b"
        jprob   0.5, b1
        jmp     s1
b1:
        prod    "_E_1A", 1
                        ; stochastic on "b"
        ; BEG: [ "a" "b" ] D D .
        rd      "_E_1A", 1, 1, 1
                        ; [ "a" "b" ]
        call    D, 4
        call    D, 5
        rd      "_E_1A", 1, 4, 1
                        ; .
        ; END: [ "a" "b" ] D D .
        jmp     r1
s1:
        prod    "_E_1A", 0
                        ; stochastic on "b"
        ; END: ([ "a" "b" ] D D .)*
        rd      "E", 0, 1, 1
                        ; [ "b" "c" ]
        ; END: ([ "a" "b" ] D D .)* [ "b" "c" ]
        ret

The program rege-asm supports the following command line options:

--dump-asm[=simple|extended]

Dump an assembler program for probabilistic parsing a terminal symbol sequence according to the regular expression:

simple

Dump an assembler program containing simplified instructions. The regular expression cannot contain terminal symbol classes and specific terminal symbols, but it can contain ‘.’.

extended

Dump an assembler program containing normal instructions and instructions for setting up a correspondence between parts of the assembler program and the productions of a context-free grammar for the regular expression. The regular expression can contain terminal symbol classes and specific terminal symbols.

On omitting the option or its argument, the program rege-asm uses --dump-asm=simple.

--dump-gram[=specific|dot|replace]

Dump a context-free grammar for the regular expression:

specific

Dump the grammar where auxiliary nonterminal symbols _E_iT and _E_iTj replace terminal symbol sequences (groups) containing at least one terminal symbol class or ‘.’.

dot

Dump the grammar where auxiliary nonterminal symbols _E_iT and _E_iTj replace terminal symbol sequences (groups) containing at least one terminal symbol class.

replace

Dump the grammar where auxiliary nonterminal symbols _E_iT and _E_iTj replace any terminal symbol sequence.

In _E_iT and _E_iTj, i is the ordinal number of an auxiliary nonterminal symbol, and j is sequence length if it is greater than 1.

On omitting the option argument, the program uses --dump-gram=dot. On omitting the option, the program does not dump a context-free grammar.

--dump-stats

Dump statistics on the regular expression.

--eos-marker

Enable the use of the end-of-stream marker $$ in the regular expression. The end-of-stream marker becomes an extra element of a set of known terminal symbols.

--nterm-min=INT

The minimum number of terminal symbols. On passing the option --dump-asm=extended, the program rege-asm generates an assembler program referencing terminal symbols contained in the regular expression and, optionally, referencing the end-of-stream marker $$ (on passing the option --eos-marker). Pass the option --nterm-min=INT to generate an assembler program for a larger set of terminal symbols on passing the option --dump-asm=extended or generate an assembler program for a specified number of terminal symbols on passing the option --dump-asm=simple. The default minimum number of terminal symbols for generated assembler programs is 2.

--recurs=left|right

Recursion type for the productions of a context-free grammar dumped on passing the option --dump-gram[=specific|dot|replace]: left or right. By default, generate left-recursive productions.


9.5 rege-test

The purpose of this program is debugging parsing a regular expression grammar, dumping a parsed grammar with optional printing its FIRST sets, simplifying a regular expression grammar, and dumping assembler programs representing the nonterminal symbols of a regular expression grammar.

Run the program using one of the following command line formats.

  1. Dumping a parsed regular expression grammar with optional removing unreachable productions from it:
    qsmm-example-rege-test [ --nont-class ] [ --eos-marker ]
                           [ --simplify=reachable ] [ --dump-ord ]
                           [ --terse ] ( --retain=NONT )*
                           REGEX_GRAMMAR_FILE
    
  2. Partially simplifying a regular expression grammar:
    qsmm-example-rege-test --simplify [ --eos-marker ]
                           ( --retain=NONT )* REGEX_GRAMMAR_FILE
    
  3. Dumping the FIRST sets of a regular expression grammar:
    qsmm-example-rege-test --dump-first [ --dump-ord ]
                           [ --eos-marker ] REGEX_GRAMMAR_FILE
    
  4. Checking the correctness of a regular expression grammar and returning zero exit status if the grammar is correct or dumping a list of errors and returning non-zero exit status if the grammar has a syntax error:
    qsmm-example-rege-test --quiet [ --eos-marker ] REGEX_GRAMMAR_FILE
    
  5. Dumping assembler programs for the nonterminal symbols of a regular expression grammar:
    qsmm-example-rege-test --dump-asm [ --eos-marker ]
                           [ --term-prefix=STR ] REGEX_GRAMMAR_FILE
    

The argument REGEX_GRAMMAR_FILE specifies the name of a file containing a regular expression grammar. If that argument is ‘-’, the program reads a regular expression grammar from stdin. See Top-Down Template Grammar and Bottom-Up Template Grammar, for the regular expression grammar format.

The program rege-test supports the following command line options:

--dump-asm

Dump assembler programs for the nonterminal symbols of the regular expression grammar.

--dump-first

Include FIRST sets in a dumped regular expression grammar as comments. By default, dump a regular expression grammar without FIRST sets.

--dump-ord

Include ordinal numbers of AST nodes in a dumped regular expression grammar as comments. By default, dump a regular expression grammar without ordinal numbers of AST nodes.

--eos-marker

Enable the use of the end-of-stream marker $$ in the regular expression grammar. The end-of-stream marker becomes an extra element of a set of known terminal symbols.

--nont-class

Enable the use of nonterminal symbol classes in the regular expression grammar. See Nonterminal Symbol Classes, for more information. This mode is incompatible with the options --dump-asm, --dump-first, and --simplify[=all].

--simplify[=reachable|all]

Simplify the regular expression grammar before processing:

reachable

Retain only reachable productions in the grammar.

all

Remove unreachable productions and partially simplify a remaining grammar.

On omitting the option argument, the program uses --simplify=all. On omitting the option, the program does not simplify a parsed grammar.

-S, --retain=NONT

Retain a specified nonterminal symbol in the regular expression grammar when simplifying it using the option --simplify[=reachable|all]. The option -S, --retain=NONT can occur multiple times on the command line. On omitting this option, when simplifying a parsed grammar, the program may remove any nonterminal symbol from it except for start nonterminal symbols.

-q, --quiet

Do not dump a parsed regular expression grammar—only return zero exit status if the regular expression grammar is correct, or print error messages and return non-zero exit status if the grammar is incorrect. On omitting this option, the program can dump a regular expression grammar if the option --dump-asm is absent on the command line.

--term-prefix=STR

A prefix for names of virtual terminal symbols. If the name of a terminal symbol has the prefix, the terminal symbol is a virtual terminal symbol, otherwise the terminal symbol is a virtual nonterminal symbol. Currently, this option only affects whether or not wr instructions (see wr Instruction) in a generated assembler program have the second argument.

--terse

Dump regular expressions in the productions of a parsed regular expression grammar in condensed format. By default, dump the regular expressions in indented format.


9.6 parse-asm

This program is for debugging converting the text of an assembler program to a memory representation of the assembler program and converting the representation back to an assembler program text. The program parse-asm can also print the result of preprocessing an assembler program text. The program parse-asm does not convert a memory representation of an assembler program to a node probability profile.

Run the program using one of the following command line formats.

  1. Dumping the result of preprocessing an input text:
    qsmm-example-parse-asm -E [ASM_FILE]
    
  2. Dumping a parsed assembler program text:
    qsmm-example-parse-asm [other options] [ASM_FILE]
    

where ASM_FILE is the name of a text file; on omitting this argument, parse-asm reads a text from stdin.

The program parse-asm supports the following command line options:

--compound

Parse an assembler program comprised of procedures. See Compound Program, for more information. This option has no effect if the option -E is present.

-E

Only preprocess an input text and print a preprocessing result to stdout. On omitting this option, the program parse-asm preprocesses an input assembler program text, converts a preprocessing result to a memory representation of an assembler program, converts the representation back to an assembler program text, and prints it to stdout.

-R, --margin-right=INT

A right margin column for comments. This option has no effect if the option -E is present. By default, do not use a right margin.

--no-preprocess

Do not preprocess an assembler program text before converting it to a memory representation of an assembler program. This option has no effect if the option -E is present. By default, preprocess an assembler program text before converting it to a memory representation of an assembler program.

--no-space-after-comma

Do not print spaces after commas outside of comments and string literals. This option has no effect if the option -E is present. By default, print spaces after commas outside of comments and string literals.

--prob-prec=INT

The number of digits after the decimal point to print for probabilities. A non-negative number specifies fixed-point notation. A negative number specifies exponential notation with the number of digits after the decimal point equal to the absolute value of the negative number. This option has no effect if the option -E is present. The default value is 2.

--strip-comments

Do not print comments. This option has no effect if the option -E is present. Print comments by default.


9.7 asm-disasm

The purpose of this program is debugging assembling a node, assigning values to its controlled probability variables, and disassembling the node.

Run the program using the following command line format:

qsmm-example-asm-disasm [OPTIONS] [ASM_FILE]

where ASM_FILE is the name of a file with an assembler program text; on omitting this argument, asm-disasm reads an assembler program text from stdin. After assembling the node and optional assigning values to its controlled probability variables, asm-disasm disassembles the node and prints a disassembled program text to stdout.

To assemble a program, you need to specify its instruction set by passing a number of -I STR[/INT] options, where each option defines an instruction class. The parameter STR specifies an instruction class name. The program asm-disasm interprets characters ‘%’ in an instruction class name as equivalents to spaces. The parameter INT specifies the number of instruction outcomes. If not supplied, the default number of outcomes is 1.

For example, to define an instruction set containing the instructions ‘nop1’, ‘user 0’, and ‘user 1’ with one outcome and the instruction ‘test 3’ with three outcomes, you specify the following list of -I options:

-I nop1 -I 'user 0' -I 'user 1' -I 'test 3/3'

If an assembler program contains definitions of probability variables, you can assign values to them by passing a number of -P STR=FLOAT options, where STR is the name of a controlled probability variable, and FLOAT is its value. For example, to assign 0.05 to the variable var1 and 0.15 to the variable var2, you use the following list of -P options:

-P var1=0.05 -P var2=0.15

The program asm-disasm supports the following command line options:

--det-action

Restrict the action emission matrix to define only deterministic action emissions. If the assembler program contains probabilities, they correspond to the state transition matrix only.

--det-goto

Restrict the state transition matrix to define only deterministic state transitions. If the assembler program contains probabilities, they correspond to the action emission matrix only.

--dump-action=FILE

Dump the action emission matrix to a file. The filename ‘-’ means stdout. See Dumping the Action Emission Matrix, for the output format.

--dump-array-out=FILE

Dump elements of output probabilities arrays corresponding to choice instruction blocks. The filename ‘-’ means stdout.

--dump-goto=FILE

Dump the state transition matrix to a file. The filename ‘-’ means stdout. See Dumping the State Transition Matrix, for the output format.

--dump-var-out=FILE

Dump all output probability variables to a file. The filename ‘-’ means stdout.

-I, --instruction=STR[/INT]

Add an instruction class STR with INT outcomes to the instruction class set. The program converts all characters ‘%’ in STR to spaces. The default number of outcomes is 1.

-L, --large=E|I|EI

The use of large actors:

E

Use a large actor for the environment state identification engine only.

I

Use a large actor for the instruction emitting engine only.

EI

Use large actors for both the environment state identification engine and instruction emitting engine.

By default, the program uses small actors for the environment state identification engine and instruction emitting engine.

--no-var-ctrl

Do not register probability variables defined in the assembler program as controlled probability variables.

--prob-action-min=FLOAT

The minimum probability of jprob and case instructions for the action emission matrix to retain in a disassembled program.

--prob-goto-min=FLOAT

The minimum probability of jprob and case instructions for the state transition matrix to retain in a disassembled program.

--prob-prec-mat=INT

The number of digits after the decimal point to print for probabilities in the state transition matrix and action emission matrix. A positive number specifies fixed-point notation. A negative number specifies exponential notation with the number of digits after the decimal point equal to the absolute value of the negative number. Zero is equivalent to default value −15.

--prob-prec-var=INT

The number of digits after the decimal point to print for values of output probability variables and elements of output probabilities arrays. A positive number specifies fixed-point notation. A negative number specifies exponential notation with the number of digits after the decimal point equal to the absolute value of the negative number. Zero is equivalent to default value −15.

--template

Generate a disassembled program using the input assembler program as an assembler program template.

--use-stt

Include stt instructions in a disassembled program.

-P, --var=STR=FLOAT

Assign value FLOAT to a controlled probability variable STR defined in the assembler program.

--var-aux

Enable auxiliary probability variables.

-W

Show warnings generated while assembling the program.


Appendix A Files {bu,td}-1-14-uni-no-quant.rg

This appendix contains the bottom-up template grammar $prefix/share/qsmm/samples/gram/bu-1-14-uni-no-quant.rg and the corresponding top-down template grammar td-1-14-uni-no-quant.rg converted from the former grammar by the rege-markup-cfg, rege-vit, and rege-bottom-up tools for using with the probabilistic adaptive bottom-up parser abu-parser.

See Examples, for the conversion commands.

File bu-1-14-uni-no-quant.rg

S: A B
 | L00 L01
 | B
 | B C
 | B C C
 | B D D
 | B E E E
 | C B B C
 | C B C B
 | C C B B
 | D C B
 | D D C
 | "a"
 | "b" "i" "g"
 | "b" "l" "o" "c" "k"
 | "c" "a" "n"
 | "c" "i" "l" "i"
 | "c" "i" "r" "c"
 | "c" "i" "t" "i"
 | "c" "i" "t" "y"
 | "d"
 | "f" "l" "a" "t" "s"
 | "f" "o" "x"
 | "f" "o" "x" "y"
 | "h" "e" A
 | "i" "f"
 | "i" "k" "j"
 | "i" "n"
 | "i" "s"
 | "l" "a" "z" "y"
 | "l" "i" "b" "e"
 | "l" "i" "f" "e"
 | "l" "i" "v" "e"
 | "o" "f"
 | "o" "r"
 | "p" "l" "a" "c" "e"
 | "t" "h" "e"
 | "t" "h" "e" "n"
 | "v" "i" "l" "l"
 | "v" "i" "r" "u"
 | "v" "i" "v" "o"
 | "y" "o" "u"
;

A: "a" "b" "c"
 | "a" "b" "c" "d"
 | "b" "f" "g"
 | "c"
 | "d" "c" "b" "a"
 | "e" "h" "j"
;

B: "a" "a"
 | "a" "b"
 | "b" "b"
 | "b" "c" "c"
 | "e"
 | "e" "f" "g" "h"
 | "f" "e"
 | "h" "g" "f" "e"
;

C: "a" "b" "c"
 | "a" "c"
 | "c" "b" "b"
 | "c" "b" "c" 
 | "c" "c"
;

D: "a" "d"
 | "d" "b" "b" "d"
 | "d" "d"
;

E: "a" "e"
 | "e" "e"
;

L00: L10 L11
   | L11 L10
;

L01: L12 L13
   | L13 L12
;

L10: "a" "b" "c" "d"
;

L11: "e" "f" "g" "h"
;

L12: "d" "c" "b" "a"
;

L13: "h" "g" "f" "e"
;

File td-1-14-uni-no-quant.rg

:c0: = [ "_S/1" ]
;
:c1: = [ "_B/1" "__I1" "__I2" ]
;
:c2: = [ "_S/2" ]
;
:c3: = [ "_A/1" "_B/2" "__I3" "__I4" "__I5" "__I6" "__I7" ]
;
:c4: = [ "_B/1" ]
;
:c5: = [ "_S/3" ]
;
:c6: = [ "_A/1" "_B/1" "_B/3" "__I8" "__I9" "__I10" "__I11" "__I12" "__I13"
         "__I14" ]
;
:c7: = [ "_A/1" ]
;
:c8: = [ "_B/2" ]
;
:c9: = [ "_C/2" ]
;
:c10: = [ "_S/4" ]
;
:c11: = [ "_A/1" "_A/3" "_B/1" "_B/2" "_B/4" "__I15" "__I16" "__I17"
          "__I18" "__I19" "__I20" "__I21" "__I22" "__I23" "__I24" "__I25"
          "__I26" "__I27" ]
;
:c12: = [ "_B/3" ]
;
:c13: = [ "_C/3" ]
;
:c14: = [ "_S/5" ]
;
:c15: = [ "_A/1" "_A/3" "_A/4" "_B/1" "_B/2" "_B/3" "_D/2" "__I28" "__I29"
          "__I30" "__I31" ]
;
:c16: = [ "_A/3" ]
;
:c17: = [ "_B/4" ]
;
:c18: = [ "_C/2" "_D/2" ]
;
:c19: = [ "_D/2" ]
;
:c20: = [ "_S/6" ]
;
:c21: = [ "_A/3" "_A/4" "_B/1" "_B/2" "_B/3" "_B/4" "_C/2" "_D/2" "__I32" ]
;
:c22: = [ "_A/4" ]
;
:c23: = [ "_C/2" "_C/3" ]
;
:c24: = [ "_B/1" "_C/2" ]
;
:c25: = [ "_C/2" "_C/3" "_D/2" ]
;
:c26: = [ "_S/7" ]
;
:c27: = [ "_A/3" "_A/4" "_B/1" "_B/2" "_B/3" "_B/4" "_C/2" "_C/3" "_D/2"
          "_D/4" ]
;
:c28: = [ "_C/3" "_D/2" "_D/4" "_E/2" ]
;
:c29: = [ "_D/4" ]
;
:c30: = [ "_E/2" ]
;
:c31: = [ "_B/1" "_B/2" "_C/2" "_C/3" ]
;
:c32: = [ "_B/1" "_B/2" ]
;
:c33: = [ "_S/8" ]
;
:c34: = [ "_A/4" "_B/2" "_B/3" "_B/4" "_C/2" "_C/3" "_D/2" "_D/4" ]
;
:c35: = [ "_B/1" "_B/2" "_B/3" "_C/2" "_C/3" ]
;
:c36: = [ "_B/2" "_B/3" "_C/2" "_C/3" ]
;
:c37: = [ "_B/1" "_B/2" "_B/3" ]
;
:c38: = [ "_C/2" "_C/3" "_D/4" ]
;
:c39: = [ "_S/9" ]
;
:c40: = [ "_B/1" "_B/3" "_B/4" "_C/2" "_C/3" "_D/2" "_D/4" ]
;
:c41: = [ "_B/1" "_B/2" "_B/3" "_B/4" "_C/2" "_C/3" ]
;
:c42: = [ "_B/3" "_B/4" "_C/2" "_C/3" ]
;
:c43: = [ "_B/1" "_B/2" "_B/3" "_B/4" ]
;
:c44: = [ "_C/3" "_D/4" ]
;
:c45: = [ "_S/10" ]
;
:c46: = [ "_B/2" "_B/4" "_C/2" "_C/3" "_D/4" ]
;
:c47: = [ "_B/4" "_C/3" ]
;
:c48: = [ "_B/2" "_B/3" "_B/4" ]
;
:c49: = [ "_S/11" ]
;
:c50: = [ "_B/3" "_C/2" "_C/3" "_D/4" ]
;
:c51: = [ "_B/2" "_B/3" "_B/4" "_C/2" "_C/3" ]
;
:c52: = [ "_B/3" "_B/4" ]
;
:c53: = [ "_S/12" ]
;
:c54: = [ "_B/4" "_C/2" "_C/3" ]
;
:c55: = [ "_S/13" ]
;
:c56: = [ "_S/14" ]
;
:c57: = [ "_S/16" ]
;
:c58: = [ "_L00/8" ]
;
:c59: = [ "_L10/4" "_L11/4" ]
;
:c60: = [ "_L11/4" ]
;
:c61: = [ "_L10/4" ]
;
:c62: = [ "_L01/8" ]
;
:c63: = [ "_L12/4" "_L13/4" ]
;
:c64: = [ "_L13/4" ]
;
:c65: = [ "_L12/4" ]
;
:n: = [ :c0: :c1: :c2: :c3: :c4: :c5: :c6: :c7: :c8: :c9: :c10: :c11: :c12:
        :c13: :c14: :c15: :c16: :c17: :c18: :c19: :c20: :c21: :c22: :c23:
        :c24: :c25: :c26: :c27: :c28: :c29: :c30: :c31: :c32: :c33: :c34:
        :c35: :c36: :c37: :c38: :c39: :c40: :c41: :c42: :c43: :c44: :c45:
        :c46: :c47: :c48: :c49: :c50: :c51: :c52: :c53: :c54: :c55: :c56:
        :c57: :c58: :c59: :c60: :c61: :c62: :c63: :c64: :c65: ]
;
:t: = [^ :n: ]
;
START/1: C0 "_S/1"
;

START/2: C2 "_S/2"
;

START/3: C5 "_S/3"
;

START/4: C10 "_S/4"
;

START/5: C14 "_S/5"
;

START/6: C20 "_S/6"
;

START/7: C26 "_S/7"
;

START/8: C33 "_S/8"
;

START/9: C39 "_S/9"
;

START/10: C45 "_S/10"
;

START/11: C49 "_S/11"
;

START/12: C53 "_S/12"
;

START/13: C55 "_S/13"
;

START/14: C56 "_S/14"
;

START/16: C57 "_S/16"
;

C0: C1 ( "_B/1" #pn-S-2 < "_S/1" >
       | "__I1" #pn-S-12 < "_S/1" >
       | "__I2" #pn-S-20 < "_S/1" >
       )
;

C1: [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
  | [ :t: ] #pt-_S_1T < "__I1" >
  | [ :t: ] #pt-_S_9T < "__I2" >
;

C2: C3 ( "_B/2" #pn-S-2 < "_S/2" >
       | "__I3" #pn-S-25 < "_S/2" >
       | "__I4" #pn-S-27 < "_S/2" >
       | "__I5" #pn-S-28 < "_S/2" >
       | "__I6" #pn-S-33 < "_S/2" >
       | "__I7" #pn-S-34 < "_S/2" >
       | ("_A/1" "_B/1" <- #d C4 #d) #pn-S-0 < "_S/2" >
       )
;

C3: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
            | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
            )
  | [ :t: ] ( [ :t: ] #pt-_S_14T2 < "__I3" >
            | [ :t: ] #pt-_S_16T2 < "__I4" >
            | [ :t: ] #pt-_S_17T2 < "__I5" >
            )
  | [ :t: ] ( [ :t: ] #pt-_S_22T2 < "__I6" >
            | [ :t: ] #pt-_S_23T2 < "__I7" >
            )
  | [ :t: ] #pt-_A_4T #pn-A-3 < "_A/1" >
  | [ :t: ] [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
  | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C4: [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
;

C5: C6 ( "_B/3" #pn-S-2 < "_S/3" >
       | "__I8" #pn-S-13 < "_S/3" >
       | "__I9" #pn-S-15 < "_S/3" >
       | "__I10" #pn-S-22 < "_S/3" >
       | "__I11" #pn-S-24 < "_S/3" >
       | "__I12" #pn-S-26 < "_S/3" >
       | "__I13" #pn-S-36 < "_S/3" >
       | "__I14" #pn-S-41 < "_S/3" >
       | ("_A/1" "_B/2" <- #d C8 #d) #pn-S-0 < "_S/3" >
       | ("_B/1" "_C/2" <- #d C9 #d) #pn-S-3 < "_S/3" >
       )
;

C6: [ :t: ] ( [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
            | [ :t: ] [ :t: ] #pt-_S_2T3 < "__I8" >
            )
  | [ :t: ] ( [ :t: ] [ :t: ] #pt-_S_4T3 < "__I9" >
            | #pt-_A_4T [ :t: ]~ #pn-A-3 < "_A/1" >
            )
  | [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
  | [ :t: ] [ :t: ] #pt-_S_13T2 C7 "_A/1" < "__I11" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_S_11T3 < "__I10" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_S_15T3 < "__I12" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_S_25T3 < "__I13" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_S_30T3 < "__I14" >
;

C7: [ :t: ] #pt-_A_4T #pn-A-3 < "_A/1" >
;

C8: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
            | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
            )
  | [ :t: ] [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
  | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C9: [ :t: ] [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
  | [ :t: ] [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
;

C10: C11 ( "_B/4" #pn-S-2 < "_S/4" >
         | "__I15" #pn-S-16 < "_S/4" >
         | "__I16" #pn-S-17 < "_S/4" >
         | "__I17" #pn-S-18 < "_S/4" >
         | "__I18" #pn-S-19 < "_S/4" >
         | "__I19" #pn-S-23 < "_S/4" >
         | "__I20" #pn-S-29 < "_S/4" >
         | "__I21" #pn-S-30 < "_S/4" >
         | "__I22" #pn-S-31 < "_S/4" >
         | "__I23" #pn-S-32 < "_S/4" >
         | "__I24" #pn-S-37 < "_S/4" >
         | "__I25" #pn-S-38 < "_S/4" >
         | "__I26" #pn-S-39 < "_S/4" >
         | "__I27" #pn-S-40 < "_S/4" >
         | ("_A/1" "_B/3" <- #d C12 #d) #pn-S-0 < "_S/4" >
         | ("_A/3" "_B/1" <- #d C4 #d) #pn-S-0 < "_S/4" >
         | ("_B/1" "_C/3" <- #d C13 #d) #pn-S-3 < "_S/4" >
         | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-3 < "_S/4" >
         )
;

C11: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_S_7T4 < "__I17" >
                                 | [ :t: ] #pt-_S_8T4 < "__I18" >
                                 )
                       | [ :t: ] [ :t: ] #pt-_S_5T4 < "__I15" >
                       | [ :t: ] [ :t: ] #pt-_S_6T4 < "__I16" >
                       )
             | #pt-_A_4T [ :t: ]~ #pn-A-3 < "_A/1" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_A_1T3 #pn-A-0 < "_A/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] [ :t: ] #pt-_S_19T4 < "__I21" >
                       | [ :t: ] [ :t: ] #pt-_S_20T4 < "__I22" >
                       | [ :t: ] [ :t: ] #pt-_S_21T4 < "__I23" >
                       )
             | [ :t: ] [ :t: ] [ :t: ] #pt-_S_18T4 < "__I20" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_A_3T3 #pn-A-2 < "_A/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_S_12T4 < "__I19" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] #pt-_A_6T3 #pn-A-5 < "_A/3" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] ( [ :t: ] [ :t: ] #pt-_S_27T4 < "__I25" >
                     | [ :t: ] [ :t: ] #pt-_S_28T4 < "__I26" >
                     | [ :t: ] [ :t: ] #pt-_S_29T4 < "__I27" >
                     )
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_S_26T4 < "__I24" >
;

C12: [ :t: ] [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
;

C13: [ :t: ] [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                     | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                     )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
;

C14: C15 ( "_B/1" C18 ( ("_C/2" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/5" >
                      | ("_D/2" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/5" >
                      )
         | "__I28" #pn-S-14 < "_S/5" >
         | "__I29" #pn-S-21 < "_S/5" >
         | "__I30" #pn-S-24 < "_S/5" >
         | "__I31" #pn-S-35 < "_S/5" >
         | ("_A/1" "_B/4" <- #d C17 #d) #pn-S-0 < "_S/5" >
         | ("_A/3" "_B/2" <- #d C8 #d) #pn-S-0 < "_S/5" >
         | ("_A/4" "_B/1" <- #d C4 #d) #pn-S-0 < "_S/5" >
         | ("_B/2" "_C/3" <- #d C13 #d) #pn-S-3 < "_S/5" >
         | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-3 < "_S/5" >
         | ("_D/2" "_C/2" "_B/1" <- #d C9 #d C4 #d) #pn-S-10 < "_S/5" >
         )
;

C15: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_A_2T4 #pn-A-1 < "_A/4" >
                                 | #pt-_A_1T3 [ :t: ]~ #pn-A-0 < "_A/3" >
                                 )
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_A_3T3 #pn-A-2 < "_A/3" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_S_3T5 < "__I28" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
             | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_S_10T5 < "__I29" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_A_5T4 #pn-A-4 < "_A/4" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] #pt-_A_6T3 #pn-A-5 < "_A/3" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] #pt-_A_4T #pn-A-3 < "_A/1" >
   | [ :t: ] [ :t: ] #pt-_S_13T2 C16 "_A/3" < "__I30" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_S_24T5 < "__I31" >
;

C16: [ :t: ] [ :t: ] [ :t: ] #pt-_A_1T3 #pn-A-0 < "_A/3" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_A_3T3 #pn-A-2 < "_A/3" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_A_6T3 #pn-A-5 < "_A/3" >
;

C17: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C18: [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             )
   | [ :t: ] [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
   | [ :t: ] [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
;

C19: [ :t: ] [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
   | [ :t: ] [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
;

C20: C21 ( "_B/1" C23 ( ("_C/2" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/6" >
                      | ("_C/3" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/6" >
                      )
         | "_B/2" C18 ( ("_C/2" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/6" >
                      | ("_D/2" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/6" >
                      )
         | "_C/2" C24 ( "_B/1" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/6" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/6" >
                                   )
                      | ("_C/2" "_B/1" "_B/1" <- #d C4 #d C4 #d) #pn-S-9 < "_S/6" >
                      )
         | "_D/2" C25 ( ("_C/2" "_B/2" <- #d C8 #d) #pn-S-10 < "_S/6" >
                      | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-10 < "_S/6" >
                      | ("_D/2" "_C/2" <- #d C9 #d) #pn-S-11 < "_S/6" >
                      )
         | "__I32" #pn-S-24 < "_S/6" >
         | ("_A/3" "_B/3" <- #d C12 #d) #pn-S-0 < "_S/6" >
         | ("_A/4" "_B/2" <- #d C8 #d) #pn-S-0 < "_S/6" >
         | ("_B/3" "_C/3" <- #d C13 #d) #pn-S-3 < "_S/6" >
         | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-3 < "_S/6" >
         )
;

C21: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_A_2T4 #pn-A-1 < "_A/4" >
                                 | #pt-_A_1T3 [ :t: ]~ #pn-A-0 < "_A/3" >
                                 )
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_A_3T3 #pn-A-2 < "_A/3" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_A_5T4 #pn-A-4 < "_A/4" >
             )
   | [ :t: ] ( [ :t: ] #pt-_S_13T2 C22 "_A/4" < "__I32" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] #pt-_A_6T3 #pn-A-5 < "_A/3" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
;

C22: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_A_2T4 #pn-A-1 < "_A/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_A_5T4 #pn-A-4 < "_A/4" >
;

C23: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
;

C24: [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
   | [ :t: ] [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
   | [ :t: ] [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
;

C25: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
;

C26: C27 ( "_B/1" C28 ( ("_C/3" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/7" >
                      | ("_D/2" "_D/4" <- #d C29 #d) #pn-S-5 < "_S/7" >
                      | ("_D/4" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/7" >
                      | ("_E/2" "_E/2" "_E/2" <- #d C30 #d C30 #d) #pn-S-6 < "_S/7" >
                      )
         | "_B/2" C23 ( ("_C/2" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/7" >
                      | ("_C/3" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/7" >
                      )
         | "_B/3" C18 ( ("_C/2" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/7" >
                      | ("_D/2" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/7" >
                      )
         | "_C/2" C31 ( "_B/1" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/7" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/7" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/7" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/7" >
                                   )
                      | "_B/2" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/7" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/7" >
                                   )
                      | "_C/2" C32 ( ("_B/1" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/7" >
                                   | ("_B/2" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/7" >
                                   )
                      | ("_C/3" "_B/1" "_B/1" <- #d C4 #d C4 #d) #pn-S-9 < "_S/7" >
                      )
         | "_C/3" C24 ( "_B/1" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/7" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/7" >
                                   )
                      | ("_C/2" "_B/1" "_B/1" <- #d C4 #d C4 #d) #pn-S-9 < "_S/7" >
                      )
         | "_D/2" C25 ( ("_C/2" "_B/3" <- #d C12 #d) #pn-S-10 < "_S/7" >
                      | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-10 < "_S/7" >
                      | ("_D/2" "_C/3" <- #d C13 #d) #pn-S-11 < "_S/7" >
                      )
         | ("_A/3" "_B/4" <- #d C17 #d) #pn-S-0 < "_S/7" >
         | ("_A/4" "_B/3" <- #d C12 #d) #pn-S-0 < "_S/7" >
         | ("_B/4" "_C/3" <- #d C13 #d) #pn-S-3 < "_S/7" >
         | ("_D/4" "_C/2" "_B/1" <- #d C9 #d C4 #d) #pn-S-10 < "_S/7" >
         )
;

C27: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_A_2T4 #pn-A-1 < "_A/4" >
                                 | #pt-_A_1T3 [ :t: ]~ #pn-A-0 < "_A/3" >
                                 | #pt-_C_1T3 [ :t: ]~ #pn-C-0 < "_C/3" >
                                 )
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_A_3T3 #pn-A-2 < "_A/3" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_A_5T4 #pn-A-4 < "_A/4" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] #pt-_A_6T3 #pn-A-5 < "_A/3" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C28: [ :t: ] ( [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             | [ :t: ] #pt-_E_1T2 #pn-E-0 < "_E/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
             )
   | [ :t: ] [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                     | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                     )
   | [ :t: ] [ :t: ] #pt-_E_2T2 #pn-E-1 < "_E/2" >
;

C29: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
;

C30: [ :t: ] [ :t: ] #pt-_E_1T2 #pn-E-0 < "_E/2" >
   | [ :t: ] [ :t: ] #pt-_E_2T2 #pn-E-1 < "_E/2" >
;

C31: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
   | [ :t: ] [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C32: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
             )
   | [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
   | [ :t: ] [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C33: C34 ( "_B/2" C28 ( ("_C/3" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/8" >
                      | ("_D/2" "_D/4" <- #d C29 #d) #pn-S-5 < "_S/8" >
                      | ("_D/4" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/8" >
                      | ("_E/2" "_E/2" "_E/2" <- #d C30 #d C30 #d) #pn-S-6 < "_S/8" >
                      )
         | "_B/3" C23 ( ("_C/2" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/8" >
                      | ("_C/3" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/8" >
                      )
         | "_B/4" C18 ( ("_C/2" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/8" >
                      | ("_D/2" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/8" >
                      )
         | "_C/2" C35 ( "_B/1" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/8" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/8" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/8" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/8" >
                                   )
                      | "_B/2" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/8" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/8" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/8" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/8" >
                                   )
                      | "_B/3" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/8" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/8" >
                                   )
                      | "_C/2" C37 ( ("_B/1" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/8" >
                                   | ("_B/2" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/8" >
                                   | ("_B/3" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/8" >
                                   )
                      | "_C/3" C32 ( ("_B/1" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/8" >
                                   | ("_B/2" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/8" >
                                   )
                      )
         | "_C/3" C31 ( "_B/1" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/8" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/8" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/8" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/8" >
                                   )
                      | "_B/2" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/8" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/8" >
                                   )
                      | "_C/2" C32 ( ("_B/1" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/8" >
                                   | ("_B/2" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/8" >
                                   )
                      | ("_C/3" "_B/1" "_B/1" <- #d C4 #d C4 #d) #pn-S-9 < "_S/8" >
                      )
         | "_D/2" C38 ( ("_C/2" "_B/4" <- #d C17 #d) #pn-S-10 < "_S/8" >
                      | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-10 < "_S/8" >
                      | ("_D/4" "_C/2" <- #d C9 #d) #pn-S-11 < "_S/8" >
                      )
         | "_D/4" C25 ( ("_C/2" "_B/2" <- #d C8 #d) #pn-S-10 < "_S/8" >
                      | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-10 < "_S/8" >
                      | ("_D/2" "_C/2" <- #d C9 #d) #pn-S-11 < "_S/8" >
                      )
         | ("_A/4" "_B/4" <- #d C17 #d) #pn-S-0 < "_S/8" >
         )
;

C34: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_A_2T4 #pn-A-1 < "_A/4" >
                                 | #pt-_C_1T3 [ :t: ]~ #pn-C-0 < "_C/3" >
                                 )
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_A_5T4 #pn-A-4 < "_A/4" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C35: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C36: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C37: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] #pt-_B_5T #pn-B-4 < "_B/1" >
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
;

C38: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
;

C39: C40 ( "_B/3" C28 ( ("_C/3" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/9" >
                      | ("_D/2" "_D/4" <- #d C29 #d) #pn-S-5 < "_S/9" >
                      | ("_D/4" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/9" >
                      | ("_E/2" "_E/2" "_E/2" <- #d C30 #d C30 #d) #pn-S-6 < "_S/9" >
                      )
         | "_B/4" C23 ( ("_C/2" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/9" >
                      | ("_C/3" "_C/2" <- #d C9 #d) #pn-S-4 < "_S/9" >
                      )
         | "_C/2" C41 ( "_B/1" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/9" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/9" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_B/2" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/9" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/9" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_B/3" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/9" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/9" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_B/4" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_C/2" C43 ( ("_B/1" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/2" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/3" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/4" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/9" >
                                   )
                      | "_C/3" C37 ( ("_B/1" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/2" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/3" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/9" >
                                   )
                      )
         | "_C/3" C35 ( "_B/1" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/9" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/9" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_B/2" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/9" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/9" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_B/3" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/9" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/9" >
                                   )
                      | "_C/2" C37 ( ("_B/1" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/2" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/3" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/9" >
                                   )
                      | "_C/3" C32 ( ("_B/1" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/9" >
                                   | ("_B/2" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/9" >
                                   )
                      )
         | "_D/2" C44 ( ("_C/3" "_B/4" <- #d C17 #d) #pn-S-10 < "_S/9" >
                      | ("_D/4" "_C/3" <- #d C13 #d) #pn-S-11 < "_S/9" >
                      )
         | "_D/4" C25 ( ("_C/2" "_B/3" <- #d C12 #d) #pn-S-10 < "_S/9" >
                      | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-10 < "_S/9" >
                      | ("_D/2" "_C/3" <- #d C13 #d) #pn-S-11 < "_S/9" >
                      )
         | ("_B/1" "_D/4" "_D/4" <- #d C29 #d C29 #d) #pn-S-5 < "_S/9" >
         )
;

C40: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] #pt-_D_1T2 #pn-D-0 < "_D/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] ( [ :t: ] #pt-_D_3T2 #pn-D-2 < "_D/2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C41: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C42: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C43: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
             | #pt-_B_5T [ :t: ]~ #pn-B-4 < "_B/1" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C44: [ :t: ] [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                     | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                     )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
;

C45: C46 ( "_B/4" C28 ( ("_C/3" "_C/3" <- #d C13 #d) #pn-S-4 < "_S/10" >
                      | ("_D/2" "_D/4" <- #d C29 #d) #pn-S-5 < "_S/10" >
                      | ("_D/4" "_D/2" <- #d C19 #d) #pn-S-5 < "_S/10" >
                      | ("_E/2" "_E/2" "_E/2" <- #d C30 #d C30 #d) #pn-S-6 < "_S/10" >
                      )
         | "_C/2" C41 ( "_B/1" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/2" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/3" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/4" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_C/2" C48 ( ("_B/2" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/3" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/4" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/10" >
                                   )
                      | "_C/3" C43 ( ("_B/1" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/2" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/3" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/4" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/10" >
                                   )
                      )
         | "_C/3" C41 ( "_B/1" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/2" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/3" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/10" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/10" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_B/4" C24 ( ("_B/1" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/10" >
                                   | ("_C/2" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/10" >
                                   )
                      | "_C/2" C43 ( ("_B/1" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/2" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/3" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/4" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/10" >
                                   )
                      | "_C/3" C37 ( ("_B/1" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/2" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/10" >
                                   | ("_B/3" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/10" >
                                   )
                      )
         | "_D/4" C38 ( ("_C/2" "_B/4" <- #d C17 #d) #pn-S-10 < "_S/10" >
                      | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-10 < "_S/10" >
                      | ("_D/4" "_C/2" <- #d C9 #d) #pn-S-11 < "_S/10" >
                      )
         | ("_B/2" "_D/4" "_D/4" <- #d C29 #d C29 #d) #pn-S-5 < "_S/10" >
         )
;

C46: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
;

C47: [ :t: ] [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                     | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                     )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C48: [ :t: ] ( [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_B_2T2 #pn-B-1 < "_B/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C49: C50 ( "_C/2" C51 ( "_B/2" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_B/3" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/11" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_B/4" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/11" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_C/2" C52 ( ("_B/3" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/4" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/11" >
                                   )
                      | "_C/3" C48 ( ("_B/2" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/3" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/4" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/11" >
                                   )
                      )
         | "_C/3" C41 ( "_B/1" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_B/2" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/11" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_B/3" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/11" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_B/4" C31 ( ("_B/1" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/11" >
                                   | ("_B/2" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/11" >
                                   | ("_C/2" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/11" >
                                   | ("_C/3" "_B/1" <- #d C4 #d) #pn-S-8 < "_S/11" >
                                   )
                      | "_C/2" C48 ( ("_B/2" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/3" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/4" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/11" >
                                   )
                      | "_C/3" C43 ( ("_B/1" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/2" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/3" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/11" >
                                   | ("_B/4" "_B/1" <- #d C4 #d) #pn-S-9 < "_S/11" >
                                   )
                      )
         | "_D/4" C44 ( ("_C/3" "_B/4" <- #d C17 #d) #pn-S-10 < "_S/11" >
                      | ("_D/4" "_C/3" <- #d C13 #d) #pn-S-11 < "_S/11" >
                      )
         | ("_B/3" "_D/4" "_D/4" <- #d C29 #d C29 #d) #pn-S-5 < "_S/11" >
         )
;

C50: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_D_2T4 #pn-D-1 < "_D/4" >
;

C51: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
                       | #pt-_B_2T2 [ :t: ]~ #pn-B-1 < "_B/2" >
                       )
             | [ :t: ] #pt-_B_1T2 #pn-B-0 < "_B/2" >
             | [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_B_3T2 #pn-B-2 < "_B/2" >
             | [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
             )
   | [ :t: ] [ :t: ] #pt-_B_7T2 #pn-B-6 < "_B/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C52: [ :t: ] [ :t: ] [ :t: ] #pt-_B_4T3 #pn-B-3 < "_B/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C53: C54 ( "_C/2" C42 ( "_B/3" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/12" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/12" >
                                   )
                      | "_B/4" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/12" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/12" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/12" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/12" >
                                   )
                      | "_C/3" C52 ( ("_B/3" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/12" >
                                   | ("_B/4" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/12" >
                                   )
                      | ("_C/2" "_B/4" "_B/4" <- #d C17 #d C17 #d) #pn-S-9 < "_S/12" >
                      )
         | "_C/3" C51 ( "_B/2" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/12" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/12" >
                                   )
                      | "_B/3" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/12" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/12" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/12" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/12" >
                                   )
                      | "_B/4" C36 ( ("_B/2" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/12" >
                                   | ("_B/3" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/12" >
                                   | ("_C/2" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/12" >
                                   | ("_C/3" "_B/2" <- #d C8 #d) #pn-S-8 < "_S/12" >
                                   )
                      | "_C/2" C52 ( ("_B/3" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/12" >
                                   | ("_B/4" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/12" >
                                   )
                      | "_C/3" C48 ( ("_B/2" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/12" >
                                   | ("_B/3" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/12" >
                                   | ("_B/4" "_B/2" <- #d C8 #d) #pn-S-9 < "_S/12" >
                                   )
                      )
         | ("_B/4" "_D/4" "_D/4" <- #d C29 #d C29 #d) #pn-S-5 < "_S/12" >
         )
;

C54: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_C_3T3 #pn-C-2 < "_C/3" >
                       | [ :t: ] #pt-_C_4T3 #pn-C-3 < "_C/3" >
                       )
             | [ :t: ] #pt-_C_5T2 #pn-C-4 < "_C/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_C_2T2 #pn-C-1 < "_C/2" >
             | [ :t: ] [ :t: ] #pt-_C_1T3 #pn-C-0 < "_C/3" >
             )
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_6T4 #pn-B-5 < "_B/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_B_8T4 #pn-B-7 < "_B/4" >
;

C55: C23 ( "_C/2" C47 ( "_B/4" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/13" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/13" >
                                   )
                      | ("_C/3" "_B/4" "_B/4" <- #d C17 #d C17 #d) #pn-S-9 < "_S/13" >
                      )
         | "_C/3" C42 ( "_B/3" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/13" >
                                   | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/13" >
                                   )
                      | "_B/4" C42 ( ("_B/3" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/13" >
                                   | ("_B/4" "_C/2" <- #d C9 #d) #pn-S-7 < "_S/13" >
                                   | ("_C/2" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/13" >
                                   | ("_C/3" "_B/3" <- #d C12 #d) #pn-S-8 < "_S/13" >
                                   )
                      | "_C/3" C52 ( ("_B/3" "_B/4" <- #d C17 #d) #pn-S-9 < "_S/13" >
                                   | ("_B/4" "_B/3" <- #d C12 #d) #pn-S-9 < "_S/13" >
                                   )
                      | ("_C/2" "_B/4" "_B/4" <- #d C17 #d C17 #d) #pn-S-9 < "_S/13" >
                      )
         )
;

C56: C13 "_C/3" C47 ( "_B/4" C47 ( ("_B/4" "_C/3" <- #d C13 #d) #pn-S-7 < "_S/14" >
                                 | ("_C/3" "_B/4" <- #d C17 #d) #pn-S-8 < "_S/14" >
                                 )
                    | ("_C/3" "_B/4" "_B/4" <- #d C17 #d C17 #d) #pn-S-9 < "_S/14" >
                    )
;

C57: C58 ("_L00/8" "_L01/8" <- #d C62 #d) #pn-S-1 < "_S/16" >
;

C58: C59 ( ("_L10/4" "_L11/4" <- #d C60 #d) #pn-L00-0 < "_L00/8" >
         | ("_L11/4" "_L10/4" <- #d C61 #d) #pn-L00-1 < "_L00/8" >
         )
;

C59: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L10_1T4 #pn-L10-0 < "_L10/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L11_1T4 #pn-L11-0 < "_L11/4" >
;

C60: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L11_1T4 #pn-L11-0 < "_L11/4" >
;

C61: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L10_1T4 #pn-L10-0 < "_L10/4" >
;

C62: C63 ( ("_L12/4" "_L13/4" <- #d C64 #d) #pn-L01-0 < "_L01/8" >
         | ("_L13/4" "_L12/4" <- #d C65 #d) #pn-L01-1 < "_L01/8" >
         )
;

C63: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L12_1T4 #pn-L12-0 < "_L12/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L13_1T4 #pn-L13-0 < "_L13/4" >
;

C64: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L13_1T4 #pn-L13-0 < "_L13/4" >
;

C65: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_L12_1T4 #pn-L12-0 < "_L12/4" >
;

Appendix B Files {bu,td}-uni-alt-1.rg

This appendix contains the bottom-up template grammar $prefix/share/qsmm/samples/gram/bu-uni-alt-1.rg and the corresponding top-down template grammar td-uni-alt-1.rg converted from the former grammar by the rege-markup-cfg, rege-vit, and rege-bottom-up tools for using with the probabilistic adaptive bottom-up parser abu-parser.

See Examples, for the conversion commands.

File bu-uni-alt-1.rg

S: [ W1_2 W2_1 W2_11 W2_12 W2_13 W2_14 W3_1 W3_2 W3_3 W3_4
     W4_5 W4_6 W4_7 W5_1 W5_2 W5_3 ]

 | [ W2_1 W2_10 W2_11 W2_12 B1 B3 ]
   [ W2_1 W2_2 W2_3 W2_4 W2_5 W2_6 W2_7 W2_8 W2_9 W3_2 B2 B4 B7 ]

 | [ W4_5 W3_1 W2_1 B3 ]
   [ W4_5 W3_2 B5 ]
   [ W3_2 W2_1 B5 ]

 | [ W2_1 W3_1 B3 ]
   [ W2_1 W3_1 B6 ]
   [ W2_1 W3_1 B6 ]
   [ W2_1 W3_1 B6 ]
;

B1: [ W3_1 W4_1 W4_2 ]
  | [ W4_1 W4_3 ] [ W4_1 W4_3 ] 
;

B2: [ W1_1 W2_1 W4_3 W4_4 ]
  | [ W4_2 W4_4 ] [ W4_2 W4_4 ]
;

B3: [ W2_2 W2_3 ]
;

B4: [ W2_4 W2_5 ]
;

B5: [ W2_6 W2_7 ]
;

B6: [ W2_8 W2_9 ]
;

B7: [ W1_1 W3_1 ]
;

W1_1: [ "c" "d" "e" ] ;
W1_2: "a" ;
W2_1: [ "a" "f" "h" ] [ "a" "b" "e" ] ;
W2_2: [ "a" "l" ] [ "b" "i" ] ;
W2_3: "b" [ "b" "e" ] ;
W2_4: [ "a" "t" ] [ "c" "i" ] ;
W2_5: [ "c" "r" ] "c" ;
W2_6: [ "a" "l" ] [ "d" "l" ] ;
W2_7: [ "d" "r" ] [ "d" "u" ] ;
W2_8: [ "a" "v" ] [ "e" "o" ] ;
W2_9: [ "e" "v" ] "e" ;
W2_10: [ "c" "i" ] [ "f" "i" ] ;
W2_11: [ "i" "l" ] [ "i" "n" ] ;
W2_12: [ "i" "v" ] [ "i" "s" ] ;
W2_13: "o" "f" ;
W2_14: "o" "r" ;
W3_1: [ "a" "b" ] [ "b" "c" "f" "i" ] [ "c" "g" ] ;
W3_2: [ "b" "c" "e" ] [ "a" "b" "f" "h" ] [ "b" "c" "g" "j" "n" ] ;
W3_3: "t" "h" "e" ;
W3_4: "y" "o" "u" ;
W4_1: "a" "b" "c" "d" ;
W4_2: "d" "c" "b" "a" ;
W4_3: "e" "f" "g" "h" ;
W4_4: "h" "g" "f" "e" ;
W4_5: [ "d" "t" ] [ "b" "h" ] [ "b" "e" ] [ "d" "n" ] ;
W4_6: [ "c" "l" ] [ "a" "i" ] [ "t" "z" ] "y" ;
W4_7: [ "f" "l" ] [ "i" "o" ] [ "v" "x" ] [ "e" "y" ];
W5_1: "b" "l" "o" "c" "k" ;
W5_2: "f" "l" "a" "t" "s" ;
W5_3: "p" "l" "a" "c" "e" ;

File td-uni-alt-1.rg

:c0: = [ "_S/1" ]
;
:c1: = [ "_W1_2/1" ]
;
:c2: = [ "_S/2" ]
;
:c3: = [ "_W2_1/2" "_W2_11/2" "_W2_12/2" "_W2_13/2" "_W2_14/2" ]
;
:c4: = [ "_S/3" ]
;
:c5: = [ "_B3/2" "_W2_1/2" "_W2_10/2" "_W2_11/2" "_W2_12/2" "_W3_1/3"
         "_W3_2/3" "_W3_3/3" "_W3_4/3" ]
;
:c6: = [ "_W2_2/2" "_W2_3/2" "__I1" "__I2" "__I3" "__I4" "__I5" "__I6"
         "__I7" "__I8" ]
;
:c7: = [ "_B2/1" ]
;
:c8: = [ "_W1_1/1" ]
;
:c9: = [ "_S/4" ]
;
:c10: = [ "_B1/3" "_B3/2" "_W2_1/2" "_W2_10/2" "_W2_11/2" "_W2_12/2"
          "_W4_5/4" "_W4_6/4" "_W4_7/4" ]
;
:c11: = [ "_W2_2/2" "_W2_3/2" "_W3_1/3" "__I1" "__I2" "__I3" "__I4" "__I9"
          "__I10" "__I11" ]
;
:c12: = [ "_B2/2" "_B4/2" "_W2_1/2" "_W2_2/2" "_W2_3/2" "_W2_4/2" "_W2_5/2"
          "_W2_6/2" "_W2_7/2" "_W2_8/2" "_W2_9/2" ]
;
:c13: = [ "_W2_1/2" "_W2_4/2" "_W2_5/2" "__I1" "__I12" "__I13" "__I14"
          "__I15" "__I16" "__I17" "__I18" "__I19" ]
;
:c14: = [ "_S/5" ]
;
:c15: = [ "_B1/3" "_B1/4" "_B3/2" "_W2_1/2" "_W2_10/2" "_W2_11/2"
          "_W2_12/2" "_W5_1/5" "_W5_2/5" "_W5_3/5" ]
;
:c16: = [ "_W2_2/2" "_W2_3/2" "_W3_1/3" "_W4_1/4" "_W4_2/4" "__I1" "__I2"
          "__I3" "__I4" "__I20" "__I21" "__I22" ]
;
:c17: = [ "_B2/1" "_B7/1" ]
;
:c18: = [ "_B7/3" "_W3_2/3" ]
;
:c19: = [ "_W3_1/3" "__I6" ]
;
:c20: = [ "_S/6" ]
;
:c21: = [ "_B1/3" "_B1/4" "_B3/2" "_W2_1/2" "_W2_10/2" "_W2_11/2"
          "_W2_12/2" ]
;
:c22: = [ "_W2_2/2" "_W2_3/2" "_W3_1/3" "_W4_1/4" "_W4_2/4" "__I1" "__I2"
          "__I3" "__I4" ]
;
:c23: = [ "_B2/4" "_B5/2" ]
;
:c24: = [ "_W2_6/2" "_W2_7/2" "_W4_3/4" "_W4_4/4" ]
;
:c25: = [ "_B5/2" "_W2_1/2" ]
;
:c26: = [ "_W2_6/2" "_W2_7/2" "__I1" ]
;
:c27: = [ "_B2/4" ]
;
:c28: = [ "_W4_3/4" "_W4_4/4" ]
;
:c29: = [ "_S/7" ]
;
:c30: = [ "_B1/3" "_B1/4" "_B3/2" "_W2_1/2" "_W3_1/3" ]
;
:c31: = [ "_W2_2/2" "_W2_3/2" "_W3_1/3" "_W4_1/4" "_W4_2/4" "__I1" "__I5" ]
;
:c32: = [ "_B5/2" "_W3_2/3" ]
;
:c33: = [ "_W2_6/2" "_W2_7/2" "__I6" ]
;
:c34: = [ "_W3_2/3" ]
;
:c35: = [ "_B5/2" ]
;
:c36: = [ "_W2_6/2" "_W2_7/2" ]
;
:c37: = [ "_S/8" ]
;
:c38: = [ "_B1/4" "_B3/2" "_W2_1/2" "_W3_1/3" "_W4_5/4" ]
;
:c39: = [ "_W2_2/2" "_W2_3/2" "_W4_1/4" "_W4_2/4" "__I1" "__I5" "__I9" ]
;
:c40: = [ "_B6/2" "_W2_1/2" "_W3_2/3" "_W4_5/4" ]
;
:c41: = [ "_W2_8/2" "_W2_9/2" "__I1" "__I6" "__I9" ]
;
:c42: = [ "_B6/2" "_W2_1/2" ]
;
:c43: = [ "_W2_8/2" "_W2_9/2" "__I1" ]
;
:c44: = [ "_S/9" ]
;
:c45: = [ "_B1/8" "_B3/2" "_W2_1/2" "_W3_1/3" "_W4_5/4" ]
;
:c46: = [ "_W2_2/2" "_W2_3/2" "_W4_1/4" "_W4_3/4" "__I1" "__I5" "__I9" ]
;
:c47: = [ "_W4_1/4" "_W4_3/4" ]
;
:c48: = [ "_B6/2" "_W2_1/2" "_W3_1/3" "_W4_5/4" ]
;
:c49: = [ "_W2_8/2" "_W2_9/2" "__I1" "__I5" "__I9" ]
;
:c50: = [ "_B6/2" "_W2_1/2" "_W3_1/3" ]
;
:c51: = [ "_W2_8/2" "_W2_9/2" "__I1" "__I5" ]
;
:c52: = [ "_W3_1/3" ]
;
:c53: = [ "_S/10" ]
;
:c54: = [ "_B1/8" "_B3/2" "_W2_1/2" "_W2_10/2" "_W2_11/2" "_W2_12/2"
          "_W3_1/3" "_W4_5/4" ]
;
:c55: = [ "_W2_2/2" "_W2_3/2" "_W4_1/4" "_W4_3/4" "__I1" "__I2" "__I3"
          "__I4" "__I5" "__I9" ]
;
:c56: = [ "_B2/8" "_B6/2" "_W2_1/2" "_W3_1/3" ]
;
:c57: = [ "_W2_8/2" "_W2_9/2" "_W4_2/4" "_W4_4/4" "__I1" "__I5" ]
;
:c58: = [ "_W4_2/4" "_W4_4/4" ]
;
:c59: = [ "_B2/8" ]
;
:c60: = [ "_W3_2/3" "_W4_5/4" ]
;
:c61: = [ "_S/11" ]
;
:c62: = [ "_B1/3" "_B1/8" "_B3/2" "_W2_1/2" "_W3_1/3" "_W4_5/4" ]
;
:c63: = [ "_W2_2/2" "_W2_3/2" "_W3_1/3" "_W4_1/4" "_W4_3/4" "__I1" "__I5"
          "__I9" ]
;
:c64: = [ "_W4_5/4" ]
;
:c65: = [ "_S/12" ]
;
:c66: = [ "_B1/4" "_B1/8" "_W3_1/3" ]
;
:c67: = [ "_W4_1/4" "_W4_2/4" "_W4_3/4" "__I5" ]
;
:c68: = [ "_W4_1/4" "_W4_3/4" "__I23" ]
;
:c69: = [ "_S/16" ]
;
:c70: = [ "_B1/8" ]
;
:n: = [ :c0: :c1: :c2: :c3: :c4: :c5: :c6: :c7: :c8: :c9: :c10: :c11: :c12:
        :c13: :c14: :c15: :c16: :c17: :c18: :c19: :c20: :c21: :c22: :c23:
        :c24: :c25: :c26: :c27: :c28: :c29: :c30: :c31: :c32: :c33: :c34:
        :c35: :c36: :c37: :c38: :c39: :c40: :c41: :c42: :c43: :c44: :c45:
        :c46: :c47: :c48: :c49: :c50: :c51: :c52: :c53: :c54: :c55: :c56:
        :c57: :c58: :c59: :c60: :c61: :c62: :c63: :c64: :c65: :c66: :c67:
        :c68: :c69: :c70: ]
;
:t: = [^ :n: ]
;
START/1: C0 "_S/1"
;

START/2: C2 "_S/2"
;

START/3: C4 "_S/3"
;

START/4: C9 "_S/4"
;

START/5: C14 "_S/5"
;

START/6: C20 "_S/6"
;

START/7: C29 "_S/7"
;

START/8: C37 "_S/8"
;

START/9: C44 "_S/9"
;

START/10: C53 "_S/10"
;

START/11: C61 "_S/11"
;

START/12: C65 "_S/12"
;

START/16: C69 "_S/16"
;

C0: C1 "_W1_2/1" #pn-S-0 < "_S/1" >
;

C1: [ :t: ] #pt-_W1_2_1T #pn-W1_2-0 < "_W1_2/1" >
;

C2: C3 ( "_W2_1/2" #pn-S-0 < "_S/2" >
       | "_W2_11/2" #pn-S-0 < "_S/2" >
       | "_W2_12/2" #pn-S-0 < "_S/2" >
       | "_W2_13/2" #pn-S-0 < "_S/2" >
       | "_W2_14/2" #pn-S-0 < "_S/2" >
       )
;

C3: [ :t: ] ( [ :t: ] ( #pt-_W2_11_1T2 [ :t: ]~ #pn-W2_11-0 < "_W2_11/2" >
                      | #pt-_W2_12_1T2 [ :t: ]~ #pn-W2_12-0 < "_W2_12/2" >
                      )
            | [ :t: ] #pt-_W2_11_1T2 #pn-W2_11-0 < "_W2_11/2" >
            | [ :t: ] #pt-_W2_12_1T2 #pn-W2_12-0 < "_W2_12/2" >
            )
  | [ :t: ] ( [ :t: ] #pt-_W2_13_1T2 #pn-W2_13-0 < "_W2_13/2" >
            | [ :t: ] #pt-_W2_14_1T2 #pn-W2_14-0 < "_W2_14/2" >
            )
  | [ :t: ] [ :t: ] #pt-_W2_1_1T2 #pn-W2_1-0 < "_W2_1/2" >
  | [ :t: ] [ :t: ] #pt-_W2_11_1T2 #pn-W2_11-0 < "_W2_11/2" >
  | [ :t: ] [ :t: ] #pt-_W2_12_1T2 #pn-W2_12-0 < "_W2_12/2" >
;

C4: C5 ( "_W3_1/3" #pn-S-0 < "_S/3" >
       | "_W3_2/3" #pn-S-0 < "_S/3" >
       | "_W3_3/3" #pn-S-0 < "_S/3" >
       | "_W3_4/3" #pn-S-0 < "_S/3" >
       | ("_B3/2" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/3" >
       | ("_W2_1/2" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/3" >
       | ("_W2_10/2" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/3" >
       | ("_W2_11/2" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/3" >
       | ("_W2_12/2" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/3" >
       )
;

C5: C6 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
       | "_W2_3/2" #pn-B3-0 < "_B3/2" >
       | "__I1" #pn-W2_1-0 < "_W2_1/2" >
       | "__I2" #pn-W2_10-0 < "_W2_10/2" >
       | "__I3" #pn-W2_11-0 < "_W2_11/2" >
       | "__I4" #pn-W2_12-0 < "_W2_12/2" >
       | "__I5" #pn-W3_1-0 < "_W3_1/3" >
       | "__I6" #pn-W3_2-0 < "_W3_2/3" >
       | "__I7" #pn-W3_3-0 < "_W3_3/3" >
       | "__I8" #pn-W3_4-0 < "_W3_4/3" >
       )
;

C6: [ :t: ] ( [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                )
                      | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                )
                      | [ :t: ] #pt-_W3_2_1T3 < "__I6" >
                      )
            | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                )
                      | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                )
                      | [ :t: ] #pt-_W3_2_1T3 < "__I6" >
                      | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                      )
            | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
            | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
            | [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
            )
  | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                      | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                      | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                      )
            | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                      | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                      )
            | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
            | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
            )
  | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_2_1T3 < "__I6" >
                      | #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                      )
            | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
            | [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
            )
  | [ :t: ] ( [ :t: ] ( #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                      | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                      )
            | [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
            | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
            )
  | [ :t: ] ( [ :t: ] ( #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                      | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                      | #pt-_W2_12_1T2 [ :t: ]~ < "__I4" >
                      )
            | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
            | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
            | [ :t: ] #pt-_W2_12_1T2 < "__I4" >
            )
  | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
  | [ :t: ] [ :t: ] #pt-_W2_12_1T2 < "__I4" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_3_1T3 < "__I7" >
  | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_4_1T3 < "__I8" >
;

C7: C8 "_W1_1/1" #pn-B2-0 < "_B2/1" >
;

C8: [ :t: ] #pt-_W1_1_1T #pn-W1_1-0 < "_W1_1/1" >
;

C9: C10 ( "_B3/2" C12 ( "_B2/2" #pn-S-1 < "_S/4" >
                      | "_B4/2" #pn-S-1 < "_S/4" >
                      | "_W2_1/2" #pn-S-1 < "_S/4" >
                      | "_W2_2/2" #pn-S-1 < "_S/4" >
                      | "_W2_3/2" #pn-S-1 < "_S/4" >
                      | "_W2_4/2" #pn-S-1 < "_S/4" >
                      | "_W2_5/2" #pn-S-1 < "_S/4" >
                      | "_W2_6/2" #pn-S-1 < "_S/4" >
                      | "_W2_7/2" #pn-S-1 < "_S/4" >
                      | "_W2_8/2" #pn-S-1 < "_S/4" >
                      | "_W2_9/2" #pn-S-1 < "_S/4" >
                      )
        | "_W2_1/2" C12 ( "_B2/2" #pn-S-1 < "_S/4" >
                        | "_B4/2" #pn-S-1 < "_S/4" >
                        | "_W2_1/2" #pn-S-1 < "_S/4" >
                        | "_W2_2/2" #pn-S-1 < "_S/4" >
                        | "_W2_3/2" #pn-S-1 < "_S/4" >
                        | "_W2_4/2" #pn-S-1 < "_S/4" >
                        | "_W2_5/2" #pn-S-1 < "_S/4" >
                        | "_W2_6/2" #pn-S-1 < "_S/4" >
                        | "_W2_7/2" #pn-S-1 < "_S/4" >
                        | "_W2_8/2" #pn-S-1 < "_S/4" >
                        | "_W2_9/2" #pn-S-1 < "_S/4" >
                        )
        | "_W2_10/2" C12 ( "_B2/2" #pn-S-1 < "_S/4" >
                         | "_B4/2" #pn-S-1 < "_S/4" >
                         | "_W2_1/2" #pn-S-1 < "_S/4" >
                         | "_W2_2/2" #pn-S-1 < "_S/4" >
                         | "_W2_3/2" #pn-S-1 < "_S/4" >
                         | "_W2_4/2" #pn-S-1 < "_S/4" >
                         | "_W2_5/2" #pn-S-1 < "_S/4" >
                         | "_W2_6/2" #pn-S-1 < "_S/4" >
                         | "_W2_7/2" #pn-S-1 < "_S/4" >
                         | "_W2_8/2" #pn-S-1 < "_S/4" >
                         | "_W2_9/2" #pn-S-1 < "_S/4" >
                         )
        | "_W2_11/2" C12 ( "_B2/2" #pn-S-1 < "_S/4" >
                         | "_B4/2" #pn-S-1 < "_S/4" >
                         | "_W2_1/2" #pn-S-1 < "_S/4" >
                         | "_W2_2/2" #pn-S-1 < "_S/4" >
                         | "_W2_3/2" #pn-S-1 < "_S/4" >
                         | "_W2_4/2" #pn-S-1 < "_S/4" >
                         | "_W2_5/2" #pn-S-1 < "_S/4" >
                         | "_W2_6/2" #pn-S-1 < "_S/4" >
                         | "_W2_7/2" #pn-S-1 < "_S/4" >
                         | "_W2_8/2" #pn-S-1 < "_S/4" >
                         | "_W2_9/2" #pn-S-1 < "_S/4" >
                         )
        | "_W2_12/2" C12 ( "_B2/2" #pn-S-1 < "_S/4" >
                         | "_B4/2" #pn-S-1 < "_S/4" >
                         | "_W2_1/2" #pn-S-1 < "_S/4" >
                         | "_W2_2/2" #pn-S-1 < "_S/4" >
                         | "_W2_3/2" #pn-S-1 < "_S/4" >
                         | "_W2_4/2" #pn-S-1 < "_S/4" >
                         | "_W2_5/2" #pn-S-1 < "_S/4" >
                         | "_W2_6/2" #pn-S-1 < "_S/4" >
                         | "_W2_7/2" #pn-S-1 < "_S/4" >
                         | "_W2_8/2" #pn-S-1 < "_S/4" >
                         | "_W2_9/2" #pn-S-1 < "_S/4" >
                         )
        | "_W4_5/4" #pn-S-0 < "_S/4" >
        | "_W4_6/4" #pn-S-0 < "_S/4" >
        | "_W4_7/4" #pn-S-0 < "_S/4" >
        | ("_B1/3" "_B2/1" <- #d C7 #d) #pn-S-1 < "_S/4" >
        )
;

C10: C11 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W3_1/3" #pn-B1-0 < "_B1/3" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I2" #pn-W2_10-0 < "_W2_10/2" >
         | "__I3" #pn-W2_11-0 < "_W2_11/2" >
         | "__I4" #pn-W2_12-0 < "_W2_12/2" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         | "__I10" #pn-W4_6-0 < "_W4_6/4" >
         | "__I11" #pn-W4_7-0 < "_W4_7/4" >
         )
;

C11: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] [ :t: ] #pt-_W4_6_1T4 < "__I10" >
                       | [ :t: ] [ :t: ] #pt-_W4_7_1T4 < "__I11" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       )
             | [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_6_1T4 < "__I10" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_7_1T4 < "__I11" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] [ :t: ] #pt-_W4_6_1T4 < "__I10" >
                       | #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                       )
             | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_6_1T4 < "__I10" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       | #pt-_W2_12_1T2 [ :t: ]~ < "__I4" >
                       )
             | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             | [ :t: ] #pt-_W2_12_1T2 < "__I4" >
             )
   | [ :t: ] ( [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_7_1T4 < "__I11" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_12_1T2 < "__I4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C12: C13 ( "_W2_1/2" #pn-B2-0 < "_B2/2" >
         | "_W2_4/2" #pn-B4-0 < "_B4/2" >
         | "_W2_5/2" #pn-B4-0 < "_B4/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I12" #pn-W2_2-0 < "_W2_2/2" >
         | "__I13" #pn-W2_3-0 < "_W2_3/2" >
         | "__I14" #pn-W2_4-0 < "_W2_4/2" >
         | "__I15" #pn-W2_5-0 < "_W2_5/2" >
         | "__I16" #pn-W2_6-0 < "_W2_6/2" >
         | "__I17" #pn-W2_7-0 < "_W2_7/2" >
         | "__I18" #pn-W2_8-0 < "_W2_8/2" >
         | "__I19" #pn-W2_9-0 < "_W2_9/2" >
         )
;

C13: [ :t: ] ( [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       )
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       )
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       | #pt-_W2_2_1T2 [ :t: ]~ < "__I12" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                       | #pt-_W2_8_1T2 [ :t: ]~ < "__I18" >
                       )
             | [ :t: ] ( #pt-_W2_2_1T2 [ :t: ]~ < "__I12" >
                       | #pt-_W2_4_1T2 [ :t: ]~ < "__I14" >
                       | #pt-_W2_4_1T2 [ :t: ]~ #pn-W2_4-0 < "_W2_4/2" >
                       )
             | [ :t: ] ( #pt-_W2_4_1T2 [ :t: ]~ < "__I14" >
                       | #pt-_W2_4_1T2 [ :t: ]~ #pn-W2_4-0 < "_W2_4/2" >
                       )
             | [ :t: ] #pt-_W2_6_1T2 < "__I16" >
             | [ :t: ] #pt-_W2_8_1T2 < "__I18" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_4_1T2 [ :t: ]~ < "__I14" >
                       | #pt-_W2_4_1T2 [ :t: ]~ #pn-W2_4-0 < "_W2_4/2" >
                       )
             | [ :t: ] ( #pt-_W2_4_1T2 [ :t: ]~ < "__I14" >
                       | #pt-_W2_4_1T2 [ :t: ]~ #pn-W2_4-0 < "_W2_4/2" >
                       )
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_5_1T2 [ :t: ]~ < "__I15" >
                       | #pt-_W2_5_1T2 [ :t: ]~ #pn-W2_5-0 < "_W2_5/2" >
                       )
             | [ :t: ] #pt-_W2_7_1T2 < "__I17" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ < "__I18" >
                       | #pt-_W2_9_1T2 [ :t: ]~ < "__I19" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 < "__I18" >
             )
   | [ :t: ] ( [ :t: ] #pt-_W2_2_1T2 < "__I12" >
             | [ :t: ] #pt-_W2_6_1T2 < "__I16" >
             )
   | [ :t: ] [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                     | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                     )
   | [ :t: ] [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                     | #pt-_W2_1_1T2 [ :t: ]~ #pn-W2_1-0 < "_W2_1/2" >
                     )
   | [ :t: ] [ :t: ] ( #pt-_W2_4_1T2 [ :t: ]~ < "__I14" >
                     | #pt-_W2_4_1T2 [ :t: ]~ #pn-W2_4-0 < "_W2_4/2" >
                     )
   | [ :t: ] [ :t: ] ( #pt-_W2_5_1T2 [ :t: ]~ < "__I15" >
                     | #pt-_W2_5_1T2 [ :t: ]~ #pn-W2_5-0 < "_W2_5/2" >
                     )
   | [ :t: ] [ :t: ] #pt-_W2_3_1T2 < "__I13" >
   | [ :t: ] [ :t: ] #pt-_W2_7_1T2 < "__I17" >
   | [ :t: ] [ :t: ] #pt-_W2_9_1T2 < "__I19" >
;

C14: C15 ( "_B1/3" C12 ( "_B2/2" #pn-S-1 < "_S/5" >
                       | "_B4/2" #pn-S-1 < "_S/5" >
                       | "_W2_1/2" #pn-S-1 < "_S/5" >
                       | "_W2_2/2" #pn-S-1 < "_S/5" >
                       | "_W2_3/2" #pn-S-1 < "_S/5" >
                       | "_W2_4/2" #pn-S-1 < "_S/5" >
                       | "_W2_5/2" #pn-S-1 < "_S/5" >
                       | "_W2_6/2" #pn-S-1 < "_S/5" >
                       | "_W2_7/2" #pn-S-1 < "_S/5" >
                       | "_W2_8/2" #pn-S-1 < "_S/5" >
                       | "_W2_9/2" #pn-S-1 < "_S/5" >
                       )
         | "_B1/4" C17 ( "_B2/1" #pn-S-1 < "_S/5" >
                       | "_B7/1" #pn-S-1 < "_S/5" >
                       )
         | "_B3/2" C18 ( "_B7/3" #pn-S-1 < "_S/5" >
                       | "_W3_2/3" #pn-S-1 < "_S/5" >
                       )
         | "_W2_1/2" C18 ( "_B7/3" #pn-S-1 < "_S/5" >
                         | "_W3_2/3" #pn-S-1 < "_S/5" >
                         )
         | "_W2_10/2" C18 ( "_B7/3" #pn-S-1 < "_S/5" >
                          | "_W3_2/3" #pn-S-1 < "_S/5" >
                          )
         | "_W2_11/2" C18 ( "_B7/3" #pn-S-1 < "_S/5" >
                          | "_W3_2/3" #pn-S-1 < "_S/5" >
                          )
         | "_W2_12/2" C18 ( "_B7/3" #pn-S-1 < "_S/5" >
                          | "_W3_2/3" #pn-S-1 < "_S/5" >
                          )
         | "_W5_1/5" #pn-S-0 < "_S/5" >
         | "_W5_2/5" #pn-S-0 < "_S/5" >
         | "_W5_3/5" #pn-S-0 < "_S/5" >
         )
;

C15: C16 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W3_1/3" #pn-B1-0 < "_B1/3" >
         | "_W4_1/4" #pn-B1-0 < "_B1/4" >
         | "_W4_2/4" #pn-B1-0 < "_B1/4" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I2" #pn-W2_10-0 < "_W2_10/2" >
         | "__I3" #pn-W2_11-0 < "_W2_11/2" >
         | "__I4" #pn-W2_12-0 < "_W2_12/2" >
         | "__I20" #pn-W5_1-0 < "_W5_1/5" >
         | "__I21" #pn-W5_2-0 < "_W5_2/5" >
         | "__I22" #pn-W5_3-0 < "_W5_3/5" >
         )
;

C16: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W5_1_1T5 < "__I20" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       )
             | [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       | #pt-_W2_12_1T2 [ :t: ]~ < "__I4" >
                       )
             | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             | [ :t: ] #pt-_W2_12_1T2 < "__I4" >
             )
   | [ :t: ] ( [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W5_2_1T5 < "__I21" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_10_1T2 < "__I2" >
   | [ :t: ] [ :t: ] #pt-_W2_12_1T2 < "__I4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W5_3_1T5 < "__I22" >
;

C17: C8 "_W1_1/1" ( [ :t: ]~ #pn-B2-0 < "_B2/1" >
                  | [ :t: ]~ #pn-B7-0 < "_B7/1" >
                  )
;

C18: C19 ( "_W3_1/3" #pn-B7-0 < "_B7/3" >
         | "__I6" #pn-W3_2-0 < "_W3_2/3" >
         )
;

C19: [ :t: ] ( [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                 )
                       | [ :t: ] #pt-_W3_2_1T3 < "__I6" >
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 | #pt-_W3_2_1T3 [ :t: ]~ < "__I6" >
                                 )
                       | [ :t: ] #pt-_W3_2_1T3 < "__I6" >
                       )
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             | [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
             )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
;

C20: C21 ( "_B1/3" C18 ( "_B7/3" #pn-S-1 < "_S/6" >
                       | "_W3_2/3" #pn-S-1 < "_S/6" >
                       )
         | "_B1/4" C12 ( "_B2/2" #pn-S-1 < "_S/6" >
                       | "_B4/2" #pn-S-1 < "_S/6" >
                       | "_W2_1/2" #pn-S-1 < "_S/6" >
                       | "_W2_2/2" #pn-S-1 < "_S/6" >
                       | "_W2_3/2" #pn-S-1 < "_S/6" >
                       | "_W2_4/2" #pn-S-1 < "_S/6" >
                       | "_W2_5/2" #pn-S-1 < "_S/6" >
                       | "_W2_6/2" #pn-S-1 < "_S/6" >
                       | "_W2_7/2" #pn-S-1 < "_S/6" >
                       | "_W2_8/2" #pn-S-1 < "_S/6" >
                       | "_W2_9/2" #pn-S-1 < "_S/6" >
                       )
         | "_B3/2" C23 ( "_B2/4" #pn-S-1 < "_S/6" >
                       | "_B5/2" C25 ( "_B5/2" #pn-S-2 < "_S/6" >
                                     | "_W2_1/2" #pn-S-2 < "_S/6" >
                                     )
                       )
         | "_W2_1/2" C23 ( "_B2/4" #pn-S-1 < "_S/6" >
                         | "_B5/2" C25 ( "_B5/2" #pn-S-2 < "_S/6" >
                                       | "_W2_1/2" #pn-S-2 < "_S/6" >
                                       )
                         )
         | ("_W2_10/2" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/6" >
         | ("_W2_11/2" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/6" >
         | ("_W2_12/2" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/6" >
         )
;

C21: C22 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W3_1/3" #pn-B1-0 < "_B1/3" >
         | "_W4_1/4" #pn-B1-0 < "_B1/4" >
         | "_W4_2/4" #pn-B1-0 < "_B1/4" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I2" #pn-W2_10-0 < "_W2_10/2" >
         | "__I3" #pn-W2_11-0 < "_W2_11/2" >
         | "__I4" #pn-W2_12-0 < "_W2_12/2" >
         )
;

C22: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       )
             | [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       | #pt-_W2_12_1T2 [ :t: ]~ < "__I4" >
                       )
             | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             | [ :t: ] #pt-_W2_12_1T2 < "__I4" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_10_1T2 < "__I2" >
   | [ :t: ] [ :t: ] #pt-_W2_12_1T2 < "__I4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
;

C23: C24 ( "_W2_6/2" #pn-B5-0 < "_B5/2" >
         | "_W2_7/2" #pn-B5-0 < "_B5/2" >
         | "_W4_3/4" #pn-B2-0 < "_B2/4" >
         | "_W4_4/4" #pn-B2-0 < "_B2/4" >
         )
;

C24: [ :t: ] [ :t: ] #pt-_W2_6_1T2 #pn-W2_6-0 < "_W2_6/2" >
   | [ :t: ] [ :t: ] #pt-_W2_7_1T2 #pn-W2_7-0 < "_W2_7/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_4_1T4 #pn-W4_4-0 < "_W4_4/4" >
;

C25: C26 ( "_W2_6/2" #pn-B5-0 < "_B5/2" >
         | "_W2_7/2" #pn-B5-0 < "_B5/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         )
;

C26: [ :t: ] ( [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_6_1T2 #pn-W2_6-0 < "_W2_6/2" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_6_1T2 #pn-W2_6-0 < "_W2_6/2" >
   | [ :t: ] [ :t: ] #pt-_W2_7_1T2 #pn-W2_7-0 < "_W2_7/2" >
;

C27: C28 ( "_W4_3/4" #pn-B2-0 < "_B2/4" >
         | "_W4_4/4" #pn-B2-0 < "_B2/4" >
         )
;

C28: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_4_1T4 #pn-W4_4-0 < "_W4_4/4" >
;

C29: C30 ( "_B1/4" C18 ( "_B7/3" #pn-S-1 < "_S/7" >
                       | "_W3_2/3" #pn-S-1 < "_S/7" >
                       )
         | "_B3/2" C32 ( "_W3_2/3" C25 ( "_B5/2" #pn-S-2 < "_S/7" >
                                       | "_W2_1/2" #pn-S-2 < "_S/7" >
                                       )
                       | ("_B5/2" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/7" >
                       )
         | "_W2_1/2" C32 ( "_W3_2/3" C25 ( "_B5/2" #pn-S-2 < "_S/7" >
                                         | "_W2_1/2" #pn-S-2 < "_S/7" >
                                         )
                         | ("_B5/2" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/7" >
                         )
         | ("_B1/3" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/7" >
         | ("_W3_1/3" "_B5/2" <- #d C35 #d) C25 ( "_B5/2" #pn-S-2 < "_S/7" >
                                                | "_W2_1/2" #pn-S-2 < "_S/7" >
                                                )
         )
;

C30: C31 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W3_1/3" #pn-B1-0 < "_B1/3" >
         | "_W4_1/4" #pn-B1-0 < "_B1/4" >
         | "_W4_2/4" #pn-B1-0 < "_B1/4" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         )
;

C31: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
;

C32: C33 ( "_W2_6/2" #pn-B5-0 < "_B5/2" >
         | "_W2_7/2" #pn-B5-0 < "_B5/2" >
         | "__I6" #pn-W3_2-0 < "_W3_2/3" >
         )
;

C33: [ :t: ] [ :t: ] #pt-_W2_6_1T2 #pn-W2_6-0 < "_W2_6/2" >
   | [ :t: ] [ :t: ] #pt-_W2_7_1T2 #pn-W2_7-0 < "_W2_7/2" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
;

C34: [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 #pn-W3_2-0 < "_W3_2/3" >
;

C35: C36 ( "_W2_6/2" #pn-B5-0 < "_B5/2" >
         | "_W2_7/2" #pn-B5-0 < "_B5/2" >
         )
;

C36: [ :t: ] [ :t: ] #pt-_W2_6_1T2 #pn-W2_6-0 < "_W2_6/2" >
   | [ :t: ] [ :t: ] #pt-_W2_7_1T2 #pn-W2_7-0 < "_W2_7/2" >
;

C37: C38 ( "_B3/2" C40 ( "_B6/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                   | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                   )
                                     | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                     )
                                     )
                       | "_W2_1/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                     )
                                       | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                       )
                                       )
                       | "_W4_5/4" C25 ( "_B5/2" #pn-S-2 < "_S/8" >
                                       | "_W2_1/2" #pn-S-2 < "_S/8" >
                                       )
                       | ("_W3_2/3" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/8" >
                       )
         | "_W2_1/2" C40 ( "_B6/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                     )
                                       | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                       )
                                       )
                         | "_W2_1/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                       )
                                         | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/8" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/8" >
                                                         )
                                         )
                         | "_W4_5/4" C25 ( "_B5/2" #pn-S-2 < "_S/8" >
                                         | "_W2_1/2" #pn-S-2 < "_S/8" >
                                         )
                         | ("_W3_2/3" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/8" >
                         )
         | "_W3_1/3" C32 ( "_W3_2/3" C25 ( "_B5/2" #pn-S-2 < "_S/8" >
                                         | "_W2_1/2" #pn-S-2 < "_S/8" >
                                         )
                         | ("_B5/2" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/8" >
                         )
         | ("_B1/4" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/8" >
         | ("_W4_5/4" "_B5/2" <- #d C35 #d) C25 ( "_B5/2" #pn-S-2 < "_S/8" >
                                                | "_W2_1/2" #pn-S-2 < "_S/8" >
                                                )
         )
;

C38: C39 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W4_1/4" #pn-B1-0 < "_B1/4" >
         | "_W4_2/4" #pn-B1-0 < "_B1/4" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C39: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C40: C41 ( "_W2_8/2" #pn-B6-0 < "_B6/2" >
         | "_W2_9/2" #pn-B6-0 < "_B6/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I6" #pn-W3_2-0 < "_W3_2/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C41: [ :t: ] ( [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       | #pt-_W2_9_1T2 [ :t: ]~ #pn-W2_9-0 < "_W2_9/2" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_W2_9_1T2 #pn-W2_9-0 < "_W2_9/2" >
             | [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 < "__I6" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C42: C43 ( "_W2_8/2" #pn-B6-0 < "_B6/2" >
         | "_W2_9/2" #pn-B6-0 < "_B6/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         )
;

C43: [ :t: ] ( [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       | #pt-_W2_9_1T2 [ :t: ]~ #pn-W2_9-0 < "_W2_9/2" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_9_1T2 #pn-W2_9-0 < "_W2_9/2" >
;

C44: C45 ( "_B1/8" C17 ( "_B2/1" #pn-S-1 < "_S/9" >
                       | "_B7/1" #pn-S-1 < "_S/9" >
                       )
         | "_B3/2" C48 ( "_B6/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                     )
                                     | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3 < "_S/9" >
                                     | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3 < "_S/9" >
                                     )
                       | "_W2_1/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                       | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3 < "_S/9" >
                                       | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/9" >
                                       )
                       | "_W3_1/3" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                     )
                                       | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                       )
                       | ("_W4_5/4" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/9" >
                       )
         | "_W2_1/2" C48 ( "_B6/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                       | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3 < "_S/9" >
                                       | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/9" >
                                       )
                         | "_W2_1/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                         )
                                         | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/9" >
                                         | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/9" >
                                         )
                         | "_W3_1/3" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                         | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                         )
                                         )
                         | ("_W4_5/4" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/9" >
                         )
         | "_W3_1/3" C40 ( "_B6/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                     | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                     )
                                       | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                       )
                         | "_W2_1/2" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                       )
                                         | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/9" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/9" >
                                                         )
                                         )
                         | "_W4_5/4" C25 ( "_B5/2" #pn-S-2 < "_S/9" >
                                         | "_W2_1/2" #pn-S-2 < "_S/9" >
                                         )
                         | ("_W3_2/3" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/9" >
                         )
         | "_W4_5/4" C32 ( "_W3_2/3" C25 ( "_B5/2" #pn-S-2 < "_S/9" >
                                         | "_W2_1/2" #pn-S-2 < "_S/9" >
                                         )
                         | ("_B5/2" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/9" >
                         )
         )
;

C45: C46 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W4_1/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "_W4_3/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C46: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C47: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
;

C48: C49 ( "_W2_8/2" #pn-B6-0 < "_B6/2" >
         | "_W2_9/2" #pn-B6-0 < "_B6/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C49: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       | #pt-_W2_9_1T2 [ :t: ]~ #pn-W2_9-0 < "_W2_9/2" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_9_1T2 #pn-W2_9-0 < "_W2_9/2" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C50: C51 ( "_W2_8/2" #pn-B6-0 < "_B6/2" >
         | "_W2_9/2" #pn-B6-0 < "_B6/2" >
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         )
;

C51: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       | #pt-_W2_9_1T2 [ :t: ]~ #pn-W2_9-0 < "_W2_9/2" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_9_1T2 #pn-W2_9-0 < "_W2_9/2" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
;

C52: [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 #pn-W3_1-0 < "_W3_1/3" >
;

C53: C54 ( "_B1/8" C12 ( "_B2/2" #pn-S-1 < "_S/10" >
                       | "_B4/2" #pn-S-1 < "_S/10" >
                       | "_W2_1/2" #pn-S-1 < "_S/10" >
                       | "_W2_2/2" #pn-S-1 < "_S/10" >
                       | "_W2_3/2" #pn-S-1 < "_S/10" >
                       | "_W2_4/2" #pn-S-1 < "_S/10" >
                       | "_W2_5/2" #pn-S-1 < "_S/10" >
                       | "_W2_6/2" #pn-S-1 < "_S/10" >
                       | "_W2_7/2" #pn-S-1 < "_S/10" >
                       | "_W2_8/2" #pn-S-1 < "_S/10" >
                       | "_W2_9/2" #pn-S-1 < "_S/10" >
                       )
         | "_B3/2" C56 ( "_B2/8" #pn-S-1 < "_S/10" >
                       | "_W3_1/3" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                       )
                                       | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/10" >
                                       | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/10" >
                                       )
                       | ("_B6/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                         < "_S/10" >
                       | ("_W2_1/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                         < "_S/10" >
                       )
         | "_W2_1/2" C56 ( "_B2/8" #pn-S-1 < "_S/10" >
                         | "_W3_1/3" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                         )
                                         | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/10" >
                                         | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/10" >
                                         )
                         | ("_B6/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                           < "_S/10" >
                         | ("_W2_1/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                           < "_S/10" >
                         )
         | "_W3_1/3" C48 ( "_B6/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                       )
                                       | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/10" >
                                       | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                         < "_S/10" >
                                       )
                         | "_W2_1/2" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                         )
                                         | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/10" >
                                         | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/10" >
                                         )
                         | "_W3_1/3" C42 ( "_B6/2" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                       | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                       )
                                         | "_W2_1/2" C42 ( "_B6/2" #pn-S-3 < "_S/10" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/10" >
                                                         )
                                         )
                         | ("_W4_5/4" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/10" >
                         )
         | "_W4_5/4" C60 ( "_W4_5/4" C25 ( "_B5/2" #pn-S-2 < "_S/10" >
                                         | "_W2_1/2" #pn-S-2 < "_S/10" >
                                         )
                         | ("_W3_2/3" "_W3_2/3" <- #d C34 #d) #pn-S-2 < "_S/10" >
                         )
         | ("_W2_10/2" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/10" >
         | ("_W2_11/2" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/10" >
         | ("_W2_12/2" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/10" >
         )
;

C54: C55 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W4_1/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "_W4_3/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I2" #pn-W2_10-0 < "_W2_10/2" >
         | "__I3" #pn-W2_11-0 < "_W2_11/2" >
         | "__I4" #pn-W2_12-0 < "_W2_12/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C55: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       )
             | [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_10_1T2 [ :t: ]~ < "__I2" >
                       | #pt-_W2_11_1T2 [ :t: ]~ < "__I3" >
                       | #pt-_W2_12_1T2 [ :t: ]~ < "__I4" >
                       )
             | [ :t: ] #pt-_W2_10_1T2 < "__I2" >
             | [ :t: ] #pt-_W2_11_1T2 < "__I3" >
             | [ :t: ] #pt-_W2_12_1T2 < "__I4" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_10_1T2 < "__I2" >
   | [ :t: ] [ :t: ] #pt-_W2_12_1T2 < "__I4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C56: C57 ( "_W2_8/2" #pn-B6-0 < "_B6/2" >
         | "_W2_9/2" #pn-B6-0 < "_B6/2" >
         | "_W4_2/4" C58 ( "_W4_2/4" #pn-B2-1 < "_B2/8" >
                         | "_W4_4/4" #pn-B2-1 < "_B2/8" >
                         )
         | "_W4_4/4" C58 ( "_W4_2/4" #pn-B2-1 < "_B2/8" >
                         | "_W4_4/4" #pn-B2-1 < "_B2/8" >
                         )
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         )
;

C57: [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       )
             | [ :t: ] ( #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] ( [ :t: ] ( #pt-_W2_8_1T2 [ :t: ]~ #pn-W2_8-0 < "_W2_8/2" >
                       | #pt-_W2_9_1T2 [ :t: ]~ #pn-W2_9-0 < "_W2_9/2" >
                       )
             | [ :t: ] #pt-_W2_8_1T2 #pn-W2_8-0 < "_W2_8/2" >
             )
   | [ :t: ] ( [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] [ :t: ] #pt-_W4_4_1T4 #pn-W4_4-0 < "_W4_4/4" >
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_9_1T2 #pn-W2_9-0 < "_W2_9/2" >
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
;

C58: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_4_1T4 #pn-W4_4-0 < "_W4_4/4" >
;

C59: C58 ( "_W4_2/4" C58 ( "_W4_2/4" #pn-B2-1 < "_B2/8" >
                         | "_W4_4/4" #pn-B2-1 < "_B2/8" >
                         )
         | "_W4_4/4" C58 ( "_W4_2/4" #pn-B2-1 < "_B2/8" >
                         | "_W4_4/4" #pn-B2-1 < "_B2/8" >
                         )
         )
;

C60: [ :t: ] [ :t: ] [ :t: ] #pt-_W3_2_1T3 #pn-W3_2-0 < "_W3_2/3" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 #pn-W4_5-0 < "_W4_5/4" >
;

C61: C62 ( "_B1/8" C18 ( "_B7/3" #pn-S-1 < "_S/11" >
                       | "_W3_2/3" #pn-S-1 < "_S/11" >
                       )
         | "_W3_1/3" C50 ( "_W3_1/3" C50 ( "_W3_1/3" C42 ( "_B6/2" #pn-S-3 < "_S/11" >
                                                         | "_W2_1/2" #pn-S-3 < "_S/11" >
                                                         )
                                         | ("_B6/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/11" >
                                         | ("_W2_1/2" "_W3_1/3" <- #d C52 #d) #pn-S-3
                                           < "_S/11" >
                                         )
                         | ("_B6/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                           < "_S/11" >
                         | ("_W2_1/2" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d) #pn-S-3
                           < "_S/11" >
                         )
         | ("_B1/3" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/11" >
         | ("_B3/2" "_W3_1/3" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d C52 #d) #pn-S-3
           < "_S/11" >
         | ("_W2_1/2" "_W3_1/3" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d C52 #d) #pn-S-3
           < "_S/11" >
         | ("_W4_5/4" "_W4_5/4" "_W3_2/3" <- #d C64 #d C34 #d) #pn-S-2 < "_S/11" >
         )
;

C62: C63 ( "_W2_2/2" #pn-B3-0 < "_B3/2" >
         | "_W2_3/2" #pn-B3-0 < "_B3/2" >
         | "_W3_1/3" #pn-B1-0 < "_B1/3" >
         | "_W4_1/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "_W4_3/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "__I1" #pn-W2_1-0 < "_W2_1/2" >
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         | "__I9" #pn-W4_5-0 < "_W4_5/4" >
         )
;

C63: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_1_1T2 [ :t: ]~ < "__I1" >
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_2_1T2 [ :t: ]~ #pn-W2_2-0 < "_W2_2/2" >
                       )
             | [ :t: ] #pt-_W2_1_1T2 < "__I1" >
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             )
   | [ :t: ] ( [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       )
             | [ :t: ] ( [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                                 )
                       | #pt-_W2_3_1T2 [ :t: ]~ #pn-W2_3-0 < "_W2_3/2" >
                       )
             | [ :t: ] #pt-_W2_3_1T2 #pn-W2_3-0 < "_W2_3/2" >
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             | [ :t: ] [ :t: ] ( #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                               | #pt-_W3_1_1T3 [ :t: ]~ #pn-W3_1-0 < "_W3_1/3" >
                               )
             )
   | [ :t: ] [ :t: ] #pt-_W2_1_1T2 < "__I1" >
   | [ :t: ] [ :t: ] #pt-_W2_2_1T2 #pn-W2_2-0 < "_W2_2/2" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 < "__I9" >
;

C64: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_5_1T4 #pn-W4_5-0 < "_W4_5/4" >
;

C65: C66 ( ("_B1/4" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/12" >
         | ("_B1/8" "_B2/4" <- #d C27 #d) #pn-S-1 < "_S/12" >
         | ("_W3_1/3" "_W3_1/3" "_W3_1/3" "_W3_1/3" <- #d C52 #d C52 #d C52 #d) #pn-S-3
           < "_S/12" >
         )
;

C66: C67 ( "_W4_1/4" C68 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         | "__I23" #pn-B1-0 < "_B1/4" >
                         )
         | "_W4_2/4" #pn-B1-0 < "_B1/4" >
         | "_W4_3/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "__I5" #pn-W3_1-0 < "_W3_1/3" >
         )
;

C67: [ :t: ] ( [ :t: ] ( [ :t: ] ( [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
                                 | #pt-_W3_1_1T3 [ :t: ]~ < "__I5" >
                                 )
                       | [ :t: ] #pt-_W3_1_1T3 < "__I5" >
                       )
             | [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
             )
   | [ :t: ] [ :t: ] [ :t: ] #pt-_W3_1_1T3 < "__I5" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_2_1T4 #pn-W4_2-0 < "_W4_2/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
;

C68: [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_1_1T4 #pn-W4_1-0 < "_W4_1/4" >
   | [ :t: ] [ :t: ] [ :t: ] [ :t: ] #pt-_W4_3_1T4 #pn-W4_3-0 < "_W4_3/4" >
   | [ :t: ]~ < "__I23" >
;

C69: C70 ("_B1/8" "_B2/8" <- #d C59 #d) #pn-S-1 < "_S/16" >
;

C70: C47 ( "_W4_1/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         | "_W4_3/4" C47 ( "_W4_1/4" #pn-B1-1 < "_B1/8" >
                         | "_W4_3/4" #pn-B1-1 < "_B1/8" >
                         )
         )
;

GNU General Public License

Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. http://fsf.org/

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.

Preamble

The GNU General Public License is a free, copyleft license for software and other kinds of works.

The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program—to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.

To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.

For the developers’ and authors’ protection, the GPL clearly explains that there is no warranty for this free software. For both users’ and authors’ sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.

Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users’ freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.

Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.

The precise terms and conditions for copying, distribution and modification follow.

TERMS AND CONDITIONS

  1. Definitions.

    “This License” refers to version 3 of the GNU General Public License.

    “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.

    “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.

    To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.

    A “covered work” means either the unmodified Program or a work based on the Program.

    To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.

    To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.

    An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.

  2. Source Code.

    The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.

    A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.

    The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.

    The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work’s System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.

    The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.

    The Corresponding Source for a work in source code form is that same work.

  3. Basic Permissions.

    All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.

    You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.

    Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.

  4. Protecting Users’ Legal Rights From Anti-Circumvention Law.

    No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.

    When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work’s users, your or third parties’ legal rights to forbid circumvention of technological measures.

  5. Conveying Verbatim Copies.

    You may convey verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.

    You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.

  6. Conveying Modified Source Versions.

    You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:

    1. The work must carry prominent notices stating that you modified it, and giving a relevant date.
    2. The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
    3. You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
    4. If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.

    A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation’s users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.

  7. Conveying Non-Source Forms.

    You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:

    1. Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
    2. Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
    3. Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
    4. Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
    5. Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.

    A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.

    A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.

    “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.

    If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).

    The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.

    Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.

  8. Additional Terms.

    “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.

    When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.

    Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:

    1. Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
    2. Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
    3. Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
    4. Limiting the use for publicity purposes of names of licensors or authors of the material; or
    5. Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
    6. Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.

    All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.

    If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.

    Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.

  9. Termination.

    You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).

    However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

    Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

    Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.

  10. Acceptance Not Required for Having Copies.

    You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.

  11. Automatic Licensing of Downstream Recipients.

    Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.

    An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party’s predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.

    You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.

  12. Patents.

    A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor’s “contributor version”.

    A contributor’s “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.

    Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor’s essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.

    In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.

    If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient’s use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.

    If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.

    A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.

    Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.

  13. No Surrender of Others’ Freedom.

    If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.

  14. Use with the GNU Affero General Public License.

    Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.

  15. Revised Versions of this License.

    The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.

    If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Program.

    Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.

  16. Disclaimer of Warranty.

    THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  17. Limitation of Liability.

    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

  18. Interpretation of Sections 15 and 16.

    If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.

one line to give the program's name and a brief idea of what it does.
Copyright (C) year name of author

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses/.

Also add information on how to contact you by electronic and paper mail.

If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:

program Copyright (C) year name of author
This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’.
This is free software, and you are welcome to redistribute it
under certain conditions; type ‘show c’ for details.

The hypothetical commands ‘show w’ and ‘show c’ should show the appropriate parts of the General Public License. Of course, your program’s commands might be different; for a GUI interface, you would use an “about box”.

You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see http://www.gnu.org/licenses/.

The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read http://www.gnu.org/philosophy/why-not-lgpl.html.


GNU Free Documentation License

Version 1.3, 3 November 2008
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
http://fsf.org/

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
  1. PREAMBLE

    The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

    This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

    We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

  2. APPLICABILITY AND DEFINITIONS

    This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

    A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

    A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

    The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

    The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

    A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

    Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

    The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

    The “publisher” means any person or entity that distributes copies of the Document to the public.

    A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

    The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

  3. VERBATIM COPYING

    You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

    You may also lend copies, under the same conditions stated above, and you may publicly display copies.

  4. COPYING IN QUANTITY

    If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

    If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

    If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

    It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

  5. MODIFICATIONS

    You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

    1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
    2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
    3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
    4. Preserve all the copyright notices of the Document.
    5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
    6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
    7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
    8. Include an unaltered copy of this License.
    9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
    10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
    11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
    12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
    13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
    14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
    15. Preserve any Warranty Disclaimers.

    If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

    You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

    You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

    The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

  6. COMBINING DOCUMENTS

    You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

    The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

    In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”

  7. COLLECTIONS OF DOCUMENTS

    You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

    You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

  8. AGGREGATION WITH INDEPENDENT WORKS

    A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

    If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

  9. TRANSLATION

    Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

    If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

  10. TERMINATION

    You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

    However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

    Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

    Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

  11. FUTURE REVISIONS OF THIS LICENSE

    The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

    Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

  12. RELICENSING

    “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

    “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

    “Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

    An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

    The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

  Copyright (C)  year  your name.
  Permission is granted to copy, distribute and/or modify this document
  under the terms of the GNU Free Documentation License, Version 1.3
  or any later version published by the Free Software Foundation;
  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
  Texts.  A copy of the license is included in the section entitled ``GNU
  Free Documentation License''.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:

    with the Invariant Sections being list their titles, with
    the Front-Cover Texts being list, and with the Back-Cover Texts
    being list.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.


Function and Macro Index

Index EntrySection

Q
qsmm_actor_calc_action_probEmitting an Output Signal
qsmm_actor_choice_sig_prob_releaseEmitting an Output Signal
qsmm_actor_createCreating an Actor
qsmm_actor_destroyCreating an Actor
qsmm_actor_enum_ngrams_v2Revising Action Choice States
qsmm_actor_permut_add_v2Preloading a Probability Profile
qsmm_actor_profile_add_v2Preloading a Probability Profile
qsmm_actor_reg_ngram_inReceiving Input Signals
qsmm_actor_reg_sig_outEmitting an Output Signal
qsmm_actor_remove_ngramRevising Action Choice States
qsmm_actor_spur_deltaIncrementing Spur
qsmm_actor_time_delta_v2Incrementing Time
QSMM_ASM_ARRAY_OUTLoading a Parsed Program into a Node
QSMM_ASM_DETERM_ACTIONLoading a Parsed Program into a Node
QSMM_ASM_DETERM_GOTOLoading a Parsed Program into a Node
QSMM_ASM_TEMPLATELoading a Parsed Program into a Node
QSMM_ASM_VAR_AUXLoading a Parsed Program into a Node
QSMM_ASM_VAR_OUTLoading a Parsed Program into a Node
qsmm_createCreating a Handle
qsmm_destroyCreating a Handle
qsmm_engine_createCreating the Model Instance
qsmm_engine_destroyCreating the Model Instance
qsmm_enum_entEnumerating Entities
qsmm_enum_var_probControlled Variables
qsmm_enum_var_prob_outOutput Variables
qsmm_err_strError Handling
QSMM_EVT_ACTIVATEInstruction Meta-Class Event Handling
QSMM_EVT_ENGINE_DONEInstruction Meta-Class Event Handling
QSMM_EVT_ENGINE_DONEInstruction Class Set Event Handling
QSMM_EVT_ENGINE_INITInstruction Meta-Class Event Handling
QSMM_EVT_ENGINE_INITInstruction Class Set Event Handling
QSMM_EVT_ENT_DONEInstruction Meta-Class Event Handling
QSMM_EVT_ENT_DONEInstruction Class Set Event Handling
QSMM_EVT_ENT_INITInstruction Meta-Class Event Handling
QSMM_EVT_ENT_INITInstruction Class Set Event Handling
QSMM_EVT_INSTR_CLASS_DONEInstruction Meta-Class Event Handling
QSMM_EVT_INSTR_CLASS_INITInstruction Meta-Class Event Handling
QSMM_EVT_NODE_ENTERInstruction Class Set Event Handling
QSMM_EVT_NODE_LEAVEInstruction Class Set Event Handling
qsmm_except_dumpError Handling for a Multinode Model
qsmm_find_instr_class_in_set_f_v2Registering Instruction Classes
qsmm_find_instr_class_in_set_fv_v2Registering Instruction Classes
qsmm_find_instr_class_seq_in_setInstruction Class Sequences
QSMM_FMT_PRI_SIGBasic Datatypes and Macros
QSMM_FMT_PRI_SSIGBasic Datatypes and Macros
QSMM_FMT_SCN_SIGBasic Datatypes and Macros
qsmm_get_actor_auto_spur_typeAutomatic Spur
qsmm_get_actor_choice_sig_probEmitting an Output Signal
qsmm_get_actor_choice_sig_prob_vecEmitting an Output Signal
qsmm_get_actor_compatCreating an Actor
qsmm_get_actor_discrete_cycle_period_lastReceiving Input Signals
qsmm_get_actor_discrete_cycle_period_meanReceiving Input Signals
qsmm_get_actor_discrete_timeIncrementing Time
qsmm_get_actor_ktemperatureActor Temperature
qsmm_get_actor_large_modelCreating an Actor
qsmm_get_actor_large_osct_nodePreloading a Probability Profile
qsmm_get_actor_ngram_profileAssigning a Preloaded Probability Profile
qsmm_get_actor_ngram_szCreating an Actor
qsmm_get_actor_nsig_ctrlNumber of Output Signals
qsmm_get_actor_nsig_inCreating an Actor
qsmm_get_actor_nsig_outNumber of Output Signals
qsmm_get_actor_nspurCreating an Actor
qsmm_get_actor_ntimeCreating an Actor
qsmm_get_actor_prob_actionEmitting an Output Signal
qsmm_get_actor_profile_pool_szPreloading a Probability Profile
qsmm_get_actor_randomSwitching Adaptive or Random Behavior of an Actor
qsmm_get_actor_range_sigCreating an Actor
qsmm_get_actor_relprob_helperHelper Relative Probability Functions
qsmm_get_actor_relprob_typeRelative Probability Function Types
qsmm_get_actor_rngSwitching Adaptive or Random Behavior of an Actor
qsmm_get_actor_sig_actionEmitting an Output Signal
qsmm_get_actor_sig_ngramReceiving Input Signals
qsmm_get_actor_sig_weightSetting a Weight for an Output Signal
qsmm_get_actor_spurIncrementing Spur
qsmm_get_actor_spur_perceptionSpur Perception
qsmm_get_actor_spur_timeIncrementing Time
qsmm_get_actor_spur_weightSpur Weight
qsmm_get_actor_storageCreating an Actor
qsmm_get_actor_timeIncrementing Time
qsmm_get_actpairCreating the Model Instance
qsmm_get_actpair_actorCreating the Model Instance
qsmm_get_continueTerminating Model Execution
qsmm_get_default_dump_instr_descPrinting an Assembler Program
qsmm_get_default_dump_prg_descPrinting an Assembler Program
qsmm_get_engine_descCreating a Handle
qsmm_get_ent_type_by_nameEnumerating Entities
qsmm_get_err_handlerError Handling for a Multinode Model
qsmm_get_instr_class_meta_nameRegistering Instruction Classes
qsmm_get_instr_class_nameRegistering Instruction Classes
qsmm_get_instr_class_noutcome_v2Registering Instruction Classes
qsmm_get_instr_class_param_binRegistering Instruction Classes
qsmm_get_instr_class_param_strRegistering Instruction Classes
qsmm_get_instr_class_seqInstruction Class Sequences
qsmm_get_instr_class_set_handlerRegistering the Instruction Class Set
qsmm_get_instr_class_set_sz_v2Registering Instruction Classes
qsmm_get_instr_class_weightSetting Instruction Classes Weights
qsmm_get_instr_class_weight_by_name_fSetting Instruction Classes Weights
qsmm_get_instr_labelInspecting an Assembler Program
qsmm_get_instr_meta_class_handlerRegistering the Instruction Meta-Class Function
qsmm_get_instr_nestedInspecting an Assembler Program
qsmm_get_instr_nlabelInspecting an Assembler Program
qsmm_get_instr_nnestedInspecting an Assembler Program
qsmm_get_instr_typeInspecting an Assembler Program
qsmm_get_iter_keyOperations on Iterators
qsmm_get_iter_valOperations on Iterators
qsmm_get_la_sigSetting Look-Ahead Signals
qsmm_get_map_key_szCreating Maps and Iterators
qsmm_get_map_val_szCreating Maps and Iterators
qsmm_get_mehcall_instr_class_setInstruction Class Identifiers
qsmm_get_mehcall_instr_meta_classInstruction Class Identifiers
qsmm_get_mehcall_instr_param_binAccessing Binary Instruction Parameters
qsmm_get_mehcall_instr_param_strSetting Text Instruction Parameters
qsmm_get_mehcall_modelEvent Handler Call Parameters
qsmm_get_mehcall_noutcomeSetting the Number of Instruction Outcomes
qsmm_get_mehcall_outcomeHandling Instruction Invocation
qsmm_get_mehcall_prob_actionHandling Instruction Invocation
qsmm_get_mehcall_prob_gotoHandling Instruction Invocation
qsmm_get_mehcall_returnReturning Control from a Node
qsmm_get_mehcall_stack_frameWorking with the Node Call Stack
qsmm_get_mehcall_stack_instr_classWorking with the Node Call Stack
qsmm_get_mehcall_stack_nodeWorking with the Node Call Stack
qsmm_get_mehcall_stack_stateWorking with the Node Call Stack
qsmm_get_mehcall_stack_szWorking with the Node Call Stack
qsmm_get_msg_typeCreating Messages
qsmm_get_msglist_msgAdding Messages to a Message List
qsmm_get_msglist_szAdding Messages to a Message List
qsmm_get_msglist_sz_typeAdding Messages to a Message List
qsmm_get_ngram_env_la_szCreating a Handle
qsmm_get_nnodeCreating Nodes
qsmm_get_node_array_prob_cycleOutput Arrays
qsmm_get_node_array_prob_matOutput Arrays
qsmm_get_node_array_prob_outOutput Arrays
qsmm_get_node_class_nameCreating Nodes
qsmm_get_node_fqCalling a Node
qsmm_get_node_nstate_v2Creating Nodes
qsmm_get_node_ptrAssociating Parameters with a Model
qsmm_get_node_recursCalling a Node
qsmm_get_node_state_by_nameState Names in stt Instructions
qsmm_get_node_state_nameState Names in stt Instructions
qsmm_get_node_var_probControlled Variables
qsmm_get_node_var_prob_cycleOutput Variables
qsmm_get_node_var_prob_matOutput Variables
qsmm_get_node_var_prob_outOutput Variables
qsmm_get_nsig_ngram_env_laCreating a Handle
qsmm_get_nstate_max_v2Registering the Instruction Class Set
qsmm_get_prg_instrInspecting an Assembler Program
qsmm_get_prg_nameInspecting an Assembler Program
qsmm_get_prg_nestedInspecting an Assembler Program
qsmm_get_prg_ninstrInspecting an Assembler Program
qsmm_get_prg_nnestedInspecting an Assembler Program
qsmm_get_prg_nstate_v2Loading a Parsed Program into a Node
qsmm_get_prg_nvarVariables in an Assembler Program
qsmm_get_prg_var_nameVariables in an Assembler Program
qsmm_get_ptrAssociating Parameters with a Model
qsmm_get_rngSwitching Adaptive or Random Behavior of a Multinode Model
qsmm_get_rng_defaultCustom Random Number Generators
qsmm_get_side_err_handlerError Handling for the Side API
qsmm_get_side_nameRegistering Interaction Sides
qsmm_get_side_trace_flagsTracing the Exchange of Data Packets
qsmm_get_side_trace_streamTracing the Exchange of Data Packets
qsmm_get_stack_frame_szWorking with the Node Call Stack
qsmm_get_stack_sz_maxCreating a Handle
qsmm_get_storage_cycle_nextEnumerating Action Choice States and Cycle Types
qsmm_get_storage_cycle_next_redirSpecifying Redirection Functions
qsmm_get_storage_cycle_statsRetrieving Storing and Removing Statistics
qsmm_get_storage_cycle_stats_redirSpecifying Redirection Functions
qsmm_get_storage_cycle_update_hookSpecifying Redirection Functions
qsmm_get_storage_msglistGetting the Reason of a Storage Failure
qsmm_get_storage_nspvalStorage Handle
qsmm_get_storage_state_statsRetrieving Storing and Removing Statistics
qsmm_get_storage_state_stats_redirSpecifying Redirection Functions
qsmm_get_trace_flagsTracing Model Execution
qsmm_get_trace_streamTracing Model Execution
qsmm_get_use_instr_class_weightsCreating a Handle
qsmm_get_vec_elm_by_pos_dOrdinary and Sparse Vectors
qsmm_get_vec_nposOrdinary and Sparse Vectors
qsmm_get_vec_pos_by_idx_v2Ordinary and Sparse Vectors
QSMM_HAS_INSTR_CLASSAccessing Binary Instruction Parameters
QSMM_HEADERS_VERSIONGetting Library Version
QSMM_INSTR_CLASS_SETInstruction Class Set Function Declaration
QSMM_INSTR_META_CLASSInstruction Meta-Class Function Declaration
qsmm_instr_strPrinting an Assembler Program
qsmm_is_iter_at_endOperations on Iterators
qsmm_is_map_emptyOperations on Maps
qsmm_iter_assignOperations on Iterators
qsmm_iter_destroyCreating Maps and Iterators
qsmm_iter_nextOperations on Iterators
qsmm_iter_prevOperations on Iterators
qsmm_iter_test_eqOperations on Iterators
qsmm_map_assignOperations on Maps
qsmm_map_clearOperations on Maps
qsmm_map_createCreating Maps and Iterators
qsmm_map_create_szCreating Maps and Iterators
qsmm_map_destroyCreating Maps and Iterators
qsmm_map_eraseOperations on Maps
qsmm_map_findOperations on Maps
qsmm_map_insertOperations on Maps
qsmm_map_iter_beginOperations on Maps
qsmm_map_iter_createCreating Maps and Iterators
qsmm_map_iter_endOperations on Maps
qsmm_map_iter_rbeginOperations on Maps
qsmm_map_iter_rendOperations on Maps
qsmm_map_key_compar_funcCreating Maps and Iterators
qsmm_map_key_compar_paramCreating Maps and Iterators
qsmm_map_lower_boundOperations on Maps
qsmm_map_multi_createCreating Maps and Iterators
qsmm_map_multi_create_szCreating Maps and Iterators
qsmm_map_multi_iter_createCreating Maps and Iterators
qsmm_map_sizeOperations on Maps
qsmm_map_upper_boundOperations on Maps
qsmm_mat_action_dump_v2Dumping the Action Emission Matrix
qsmm_mat_goto_dump_v2Dumping the State Transition Matrix
qsmm_msg_append_fCreating Messages
qsmm_msg_append_fvCreating Messages
qsmm_msg_cloneCreating Messages
qsmm_msg_create_fCreating Messages
qsmm_msg_create_fvCreating Messages
qsmm_msg_destroyCreating Messages
qsmm_msg_strPrinting Messages
qsmm_msglist_add_msgAdding Messages to a Message List
qsmm_msglist_clearAdding Messages to a Message List
qsmm_msglist_createCreating a Message List
qsmm_msglist_destroyCreating a Message List
qsmm_msglist_dumpPrinting Messages
qsmm_msglist_extendAdding Messages to a Message List
qsmm_node_asmLoading a Parsed Program into a Node
qsmm_node_call_defaultCalling a Node
QSMM_NODE_CLONE_STATE_NAMESCloning the Probability Profile
QSMM_NODE_CLONE_TEMPLATECloning the Probability Profile
QSMM_NODE_CLONE_VARSCloning the Probability Profile
QSMM_NODE_CREATECreating Nodes
qsmm_node_create_v2Creating Nodes
qsmm_node_destroyCreating Nodes
qsmm_node_disasmDisassembling a Node
qsmm_node_profile_cloneCloning the Probability Profile
qsmm_node_unloadUnloading the Probability Profile
qsmm_node_var_out_forgetOutput Variables
qsmm_node_var_realizeControlled Variables
QSMM_PARSE_ASM_COMPOUNDParsing an Assembler Program
QSMM_PARSE_ASM_PREPROCESSParsing an Assembler Program
qsmm_parse_asm_source_bufParsing an Assembler Program
qsmm_parse_asm_source_fileParsing an Assembler Program
qsmm_parse_asm_source_streamParsing an Assembler Program
QSMM_PARSE_ASM_STRIP_COMMENTSParsing an Assembler Program
QSMM_PARSE_ASM_WARN_UNUSED_LABELSParsing an Assembler Program
qsmm_preprocess_asm_source_bufGetting Preprocessed Output
qsmm_preprocess_asm_source_fileGetting Preprocessed Output
qsmm_preprocess_asm_source_streamGetting Preprocessed Output
qsmm_prg_add_nestedBasic Datatypes for Assembler Programs
qsmm_prg_createBasic Datatypes for Assembler Programs
qsmm_prg_destroyBasic Datatypes for Assembler Programs
qsmm_prg_dumpPrinting an Assembler Program
QSMM_REG_INSTR_CLASSRegistering Instruction Classes
QSMM_REG_INSTR_CLASS_PARAMRegistering Instruction Classes
qsmm_reg_instr_class_seqInstruction Class Sequences
qsmm_reg_instr_class_setRegistering the Instruction Class Set
QSMM_REG_INSTR_CLASS_SET_PARAMRegistering the Instruction Class Set
qsmm_reg_instr_class_v2Registering Instruction Classes
qsmm_reg_instr_meta_classRegistering the Instruction Meta-Class Function
QSMM_REG_INSTR_META_CLASS_PARAMRegistering the Instruction Meta-Class Function
qsmm_reg_var_probControlled Variables
QSMM_REG_VAR_PROBControlled Variables
QSMM_RNG_CMD_CREATECustom Random Number Generators
QSMM_RNG_CMD_DESTROYCustom Random Number Generators
QSMM_RNG_CMD_GENERATECustom Random Number Generators
QSMM_RNG_CMD_SEEDCustom Random Number Generators
qsmm_rng_createCreating a Random Number Generator
qsmm_rng_create_customCreating a Random Number Generator
qsmm_rng_destroyCreating a Random Number Generator
qsmm_rng_seedGenerating Random Numbers
qsmm_rng_uniformGenerating Random Numbers
qsmm_rng_uniform_intGenerating Random Numbers
qsmm_rng_uniform_posGenerating Random Numbers
qsmm_set_actor_auto_spur_typeAutomatic Spur
qsmm_set_actor_discrete_timeIncrementing Time
qsmm_set_actor_ktemperatureActor Temperature
qsmm_set_actor_ngram_profileAssigning a Preloaded Probability Profile
qsmm_set_actor_nsig_ctrlNumber of Output Signals
qsmm_set_actor_nsig_outNumber of Output Signals
qsmm_set_actor_randomSwitching Adaptive or Random Behavior of an Actor
qsmm_set_actor_relprob_helperHelper Relative Probability Functions
qsmm_set_actor_relprob_typeRelative Probability Function Types
qsmm_set_actor_sig_weightSetting a Weight for an Output Signal
qsmm_set_actor_spur_perceptionSpur Perception
qsmm_set_actor_spur_timeIncrementing Time
qsmm_set_actor_spur_weightSpur Weight
qsmm_set_continueTerminating Model Execution
qsmm_set_err_handlerError Handling for a Multinode Model
qsmm_set_instr_class_weightSetting Instruction Classes Weights
qsmm_set_instr_class_weight_by_name_fSetting Instruction Classes Weights
qsmm_set_iter_valOperations on Iterators
qsmm_set_la_sigSetting Look-Ahead Signals
qsmm_set_mehcall_instr_param_fSetting Text Instruction Parameters
qsmm_set_mehcall_instr_param_fvSetting Text Instruction Parameters
qsmm_set_mehcall_noutcomeSetting the Number of Instruction Outcomes
qsmm_set_mehcall_outcomeHandling Instruction Invocation
qsmm_set_mehcall_returnReturning Control from a Node
qsmm_set_msg_linenoCreating Messages
qsmm_set_node_nstateCreating Nodes
qsmm_set_node_profile_sourceMemory Efficient Cloning the Probability Profile
qsmm_set_node_ptrAssociating Parameters with a Model
qsmm_set_node_var_probControlled Variables
qsmm_set_nstate_maxRegistering the Instruction Class Set
qsmm_set_ptrAssociating Parameters with a Model
qsmm_set_randomSwitching Adaptive or Random Behavior of a Multinode Model
qsmm_set_rng_defaultCustom Random Number Generators
qsmm_set_side_err_handlerError Handling for the Side API
qsmm_set_side_trace_flagsTracing the Exchange of Data Packets
qsmm_set_side_trace_streamTracing the Exchange of Data Packets
qsmm_set_stack_frame_szWorking with the Node Call Stack
qsmm_set_storage_cycle_next_redirSpecifying Redirection Functions
qsmm_set_storage_cycle_statsRetrieving Storing and Removing Statistics
qsmm_set_storage_cycle_stats_redirSpecifying Redirection Functions
qsmm_set_storage_cycle_update_hookSpecifying Redirection Functions
qsmm_set_storage_state_statsRetrieving Storing and Removing Statistics
qsmm_set_storage_state_stats_redirSpecifying Redirection Functions
qsmm_set_trace_flagsTracing Model Execution
qsmm_set_trace_streamTracing Model Execution
qsmm_side_createRegistering Interaction Sides
qsmm_side_destroyRegistering Interaction Sides
qsmm_side_recvExchanging Data Packets Between Sides
QSMM_SIDE_RECVExchanging Data Packets Between Sides
qsmm_side_sendExchanging Data Packets Between Sides
QSMM_SIDE_SENDExchanging Data Packets Between Sides
QSMM_SIDE_TRACE_APITracing the Exchange of Data Packets
qsmm_side_trace_fTracing the Exchange of Data Packets
qsmm_side_trace_fvTracing the Exchange of Data Packets
QSMM_SIDE_TRACE_MSGTracing the Exchange of Data Packets
QSMM_SIG_INVALIDBasic Datatypes and Macros
QSMM_SIG_MAXBasic Datatypes and Macros
qsmm_storage_enum_states_v2Enumerating Action Choice States and Cycle Types
qsmm_storage_remove_stateRetrieving Storing and Removing Statistics
QSMM_TERMINATETerminating Model Execution
QSMM_TRACE_APITracing Model Execution
QSMM_TRACE_CTRLTracing Model Execution
QSMM_TRACE_EVTTracing Model Execution
qsmm_trace_fTracing Model Execution
qsmm_trace_fvTracing Model Execution
qsmm_vec_cloneOrdinary and Sparse Vectors
qsmm_vec_destroyOrdinary and Sparse Vectors
qsmm_versionGetting Library Version


Type Index

Index EntrySection

Q
qsmm_actor_desc_sCreating an Actor
qsmm_actor_large_desc_sCreating an Actor
qsmm_actor_tCreating an Actor
qsmm_actpair_tCreating the Model Instance
qsmm_compar_func_tCreating Maps and Iterators
qsmm_cspval_sStructures for Accessing Storage
qsmm_cycle_sStructures for Accessing Storage
qsmm_desc_sCreating a Handle
qsmm_disasm_desc_sDisassembling a Node
qsmm_dump_instr_desc_sPrinting an Assembler Program
qsmm_dump_mat_action_desc_sDumping the Action Emission Matrix
qsmm_dump_mat_goto_desc_sDumping the State Transition Matrix
qsmm_dump_msg_desc_sPrinting Messages
qsmm_dump_prg_desc_sPrinting an Assembler Program
qsmm_engine_desc_sCreating a Handle
qsmm_engine_eCreating a Handle
qsmm_enum_ent_callback_func_tEnumerating Entities
qsmm_enum_ngram_callback_func_tRevising Action Choice States
qsmm_enum_state_callback_func_tEnumerating Action Choice States and Cycle Types
qsmm_err_handler_func_tError Handling for a Multinode Model
qsmm_except_evthndlr_sError Handling for a Multinode Model
qsmm_except_exist_sError Handling for a Multinode Model
qsmm_except_noeqclas_sError Handling for a Multinode Model
qsmm_except_notfound_sError Handling for a Multinode Model
qsmm_except_outcome_sError Handling for a Multinode Model
qsmm_except_profsrcp_sError Handling for a Multinode Model
qsmm_except_profsrcu_sError Handling for a Multinode Model
qsmm_except_psumgt1_sError Handling for a Multinode Model
qsmm_except_sError Handling for a Multinode Model
qsmm_except_type_sError Handling for a Multinode Model
qsmm_except_uError Handling for a Multinode Model
qsmm_get_cycle_next_func_tSpecifying Redirection Functions
qsmm_get_cycle_stats_func_tSpecifying Redirection Functions
qsmm_get_state_stats_func_tSpecifying Redirection Functions
qsmm_gref_eEntity References
qsmm_gref_sEntity References
qsmm_gref_uEntity References
qsmm_handle_eObject Handles
qsmm_handle_lref_sEntity References
qsmm_handle_lref2_sEntity References
qsmm_handle_sObject Handles
qsmm_handle_uObject Handles
qsmm_instr_class_sEntity References
qsmm_instr_class_seq_sEntity References
qsmm_instr_class_set_func_tInstruction Class Set Function Declaration
qsmm_instr_eInspecting an Assembler Program
qsmm_instr_meta_class_func_tInstruction Meta-Class Function Declaration
qsmm_instr_tBasic Datatypes for Assembler Programs
qsmm_iter_tCreating Maps and Iterators
qsmm_lref_eEntity References
qsmm_lref_sEntity References
qsmm_lref_uEntity References
qsmm_map_tCreating Maps and Iterators
qsmm_mat_eOutput Variables
qsmm_mehcall_sEvent Handler Call Parameters
qsmm_mehcall_tEvent Handler Call Parameters
qsmm_msg_eCreating Messages
qsmm_msg_tCreating Messages
qsmm_msglist_tCreating a Message List
qsmm_pair_sig_sCreating an Actor
qsmm_prg_tBasic Datatypes for Assembler Programs
qsmm_prob_eEmitting an Output Signal
qsmm_proxy_func_tCustom Random Number Generators
qsmm_relprob_eRelative Probability Function Types
qsmm_relprob_user1_func_tHelper Relative Probability Functions
qsmm_relprob_user2_func_tHelper Relative Probability Functions
qsmm_rng_cmd_seed_in_sCustom Random Number Generators
qsmm_rng_tCreating a Random Number Generator
qsmm_side_tRegistering Interaction Sides
qsmm_sig_tBasic Datatypes and Macros
qsmm_spur_perception_eSpur Perception
qsmm_ssig_tBasic Datatypes and Macros
qsmm_sspval_sStructures for Accessing Storage
qsmm_state_sStructures for Accessing Storage
qsmm_storage_tStorage Handle
qsmm_tCreating a Handle
qsmm_update_cycle_stats_func_tSpecifying Redirection Functions
qsmm_vec_tOrdinary and Sparse Vectors


Concept Index

Jump to:   ?   *  
A   B   C   D   E   F   G   H   I   K   L   M   N   O   P   Q   R   S   T   U   V   W  
Index EntrySection

?
?, quantifierAlternatives
?, quantifierParser Assembler Program Structure
?, quantifierrege-markup-cfg

*
*, quantifierLoops
*, quantifierMarking a Left-Hand Side
*, quantifierMarking a Right-Hand Side
*, quantifierParser Assembler Program Structure

A
accumulated cycle-summed valueStructures for Accessing Storage
action choice stateEvent History
action choice state, conditionStructures for Accessing Storage
action emission matrixNode Parameters
action emission matrixDumping the Action Emission Matrix
actorBuilding Blocks for Intelligent Machines
actorAdaptive Probabilistic Mapping
actor pairCreating the Model Instance
actor, creatingCreating an Actor
actor, destroyingCreating an Actor
actor, handleCreating an Actor
actor, largeSmall and Large Actors
actor, n-gram bufferReceiving Input Signals
actor, smallSmall and Large Actors
actor, temperatureActor Temperature
adaptive behavior modeSwitching Adaptive or Random Behavior of an Actor
adaptive behavior modeSwitching Adaptive or Random Behavior of a Multinode Model
adaptive parser, bottom-upabu-parser
adaptive parser, top-downatd-parser
adaptive probabilistic mappingBuilding Blocks for Intelligent Machines
adaptive probabilistic mappingAdaptive Probabilistic Mapping
aggregate statisticsOutput Variables
aggregate statisticsOutput Arrays
alternatives, in a grammarAlternatives
array, output probabilitieschoice Instruction Block
array, output probabilitiesOutput Arrays
array, signal rangesCreating an Actor
array, signal rangesCreating an Actor
array, signal rangesRevising Action Choice States
array, signal rangesEnumerating Action Choice States and Cycle Types
array, signal rangesCreating a Handle
assembler instructionDefining Instruction Meta-Classes
assembler instructionAssembler Programs
assembler instructionAssembler Instructions
assembler instruction, comment forComments
assembler instruction, fetchingInspecting an Assembler Program
assembler instruction, handleBasic Datatypes for Assembler Programs
assembler instruction, label, dataPlain Program
assembler instruction, label, locationPlain Program
assembler instruction, mixed-typeAssembler Instructions
assembler instruction, parametersInstruction Class Identifiers
assembler instruction, parameters, binaryAccessing Binary Instruction Parameters
assembler instruction, parameters, binaryRegistering Instruction Classes
assembler instruction, parameters, binaryRegistering Instruction Classes
assembler instruction, parameters, textSetting Text Instruction Parameters
assembler instruction, parameters, textRegistering Instruction Classes
assembler instruction, parser, bottom-upAssembler Instruction Set for Bottom-Up Parser
assembler instruction, parser, top-downAssembler Instruction Set for Top-Down Parser
assembler instruction, printingPrinting an Assembler Program
assembler instruction, splittingPlain Program
assembler instruction, typeInspecting an Assembler Program
assembler instruction, userAssembler Instructions
assembler instruction, userUser Instructions
assembler programAssembler Program Syntax
assembler program, commentsComments
assembler program, compoundCompound Program
assembler program, creating emptyBasic Datatypes for Assembler Programs
assembler program, destroyingBasic Datatypes for Assembler Programs
assembler program, handleBasic Datatypes for Assembler Programs
assembler program, loadingLoading a Parsed Program into a Node
assembler program, parsingParsing an Assembler Program
assembler program, plainPlain Program
assembler program, plainRecommended Assembler Program Structure
assembler program, preprocessingUsing the Assembler Preprocessor
assembling a nodeAssembling a Node
automatic spurAutomatic Spur
automaton stateBuilding Blocks for Intelligent Machines
automaton stateEvent History
automaton stateAutomatic Spur
auxiliary probability variableAuxiliary Variables

B
behavior modeSwitching Adaptive or Random Behavior of an Actor
behavior modeSwitching Adaptive or Random Behavior of a Multinode Model
binary instruction parametersInstruction Class Identifiers
binary instruction parametersAccessing Binary Instruction Parameters
binary instruction parametersRegistering Instruction Classes
binary instruction parametersRegistering Instruction Classes
bottom-up parserabu-parser
bottom-up parser assembler instructionsAssembler Instruction Set for Bottom-Up Parser
bottom-up template grammarBottom-Up Template Grammar
built-in instructionAssembler Instructions

C
callback function, enumerationRevising Action Choice States
callback function, enumerationEnumerating Action Choice States and Cycle Types
callback function, enumerationEnumerating Entities
calling a nodeCalling a Node
canonical instruction parametersSetting Text Instruction Parameters
choice complexityAnimate Machines
class, instructionPrinciple of Operation
class, instructionInstruction Class Identifiers
class, instructionRegistering Instruction Classes
class, instructionInstruction Class Sequences
cloning a nonterminal symbolCloning Nonterminal Symbols
cloning a nonterminal symbol class, deepSymbol Class Expressions
cloning a nonterminal symbol, deepCloning Nonterminal Symbols
cloning a probability profileCloning the Probability Profile
cloning a probability profile, deferredMemory Efficient Cloning the Probability Profile
comment for an assembler instructionComments
comments in a template grammarTop-Down Template Grammar
comments in an assembler programComments
complexity, choiceAnimate Machines
compound assembler programCompound Program
compound nonterminal symbolNonterminal Symbols
compound nonterminal symbolCompound Nonterminal Symbols
condition for an action choice stateStructures for Accessing Storage
consciousness, a rudiment ofAnimate Machines
context-free grammar, factoredQSMM Components
context-free grammar, factoredBottom-Up Template Grammar
context-free grammar, factoredrege-vit
context-free grammar, initialCommand-Line Options of Top-Down Parser
context-free grammar, initialCommand-Line Options of Bottom-Up Parser
context-free grammar, initialrege-markup-cfg
context-free grammar, initialrege-asm
context, nonterminal symbolCompound Nonterminal Symbols
continuous cycle periodReceiving Input Signals
continuous timeIncrementing Time
control, possessing by a nodeMultinode Model
control, returning from a nodeReturning Control from a Node
control, transferring to a nodeCalling a Node
controlled probability variableControlled Variables
creating a mapCreating Maps and Iterators
creating a messageCreating Messages
creating a message listCreating a Message List
creating a modelCreating a Handle
creating a model instanceCreating the Model Instance
creating a nodeCreating Nodes
creating a random number generatorCreating a Random Number Generator
creating an actorCreating an Actor
creating an empty assembler programBasic Datatypes for Assembler Programs
creating an iteratorCreating Maps and Iterators
cycleOutput Signal Selection
cycle directionReceiving Input Signals
cycle periodReceiving Input Signals
cycle periodReceiving Input Signals
cycle periodRelative Probability Function Types
cycle start timeReceiving Input Signals
cycle typeOutput Signal Selection
cycle typeReceiving Input Signals
cycle typeSpur Perception
cycle type statisticsStructures for Accessing Storage
cycle type statistics updates, interceptingSpecifying Redirection Functions
cycle-summed valueStatistics Storage
cycle-summed value, accumulatedStructures for Accessing Storage
cycle-summed value, initialStructures for Accessing Storage

D
data labelPlain Program
data labeljprob Instruction
data labelchoice Instruction Block
data labelchoice Instruction Block
data labelVariables in an Assembler Program
data labelOutput Arrays
default output signal choice treeNumber of Output Signals
default output signal choice treePreloading a Probability Profile
default output signal choice treeAssigning a Preloaded Probability Profile
default output signal choice treeAssigning a Preloaded Probability Profile
default probability profileRegistering the Instruction Class Set
default probability profileNode Parameters
default probability profileNode Parameters
default probability profileCreating Nodes
deferred cloning a probability profileMemory Efficient Cloning the Probability Profile
deferring a terminal symbolReverse Order Sequences
deferring a terminal symbolDeferring a Terminal Symbol
deferring a terminal symbolpushd Instruction
derived PCFGabu-parser
derived PCFGCommand-Line Options of Bottom-Up Parser
destroying a mapCreating Maps and Iterators
destroying a messageCreating Messages
destroying a message listCreating a Message List
destroying a modelCreating a Handle
destroying a model instanceCreating the Model Instance
destroying a nodeCreating Nodes
destroying a random number generatorCreating a Random Number Generator
destroying a vectorOrdinary and Sparse Vectors
destroying an actorCreating an Actor
destroying an assembler programBasic Datatypes for Assembler Programs
destroying an iteratorCreating Maps and Iterators
direction, cycleReceiving Input Signals
disassembling a nodeDisassembling a Node
discrete cycle periodReceiving Input Signals
discrete cycle period, meanRelative Probability Function Types
discrete timeIncrementing Time

E
empty terminal symbol classTerminal Symbol Classes
end-of-production markerTop-Down Template Grammar Specifiers
end-of-production markernprod Instruction
end-of-production markertprod Instruction
end-of-stream markerTerminal Symbols
engine actorCreating the Model Instance
engine typeCreating a Handle
engine, environment state identificationPrinciple of Operation
engine, instruction emittingPrinciple of Operation
entity identifier, globalEntity References
entity identifier, localEntity References
entity reference, globalEntity References
entity reference, localEntity References
entity typeEntity References
enumeration callback functionRevising Action Choice States
enumeration callback functionEnumerating Action Choice States and Cycle Types
enumeration callback functionEnumerating Entities
environment state identification enginePrinciple of Operation
error handler functionError Handling for a Multinode Model
error handler functionError Handling for the Side API
event handler, instruction class setInstruction Class Set Function Declaration
event handler, instruction class setRegistering the Instruction Class Set
event handler, instruction class setInstruction Class Set Function Layout
event handler, instruction meta-classInstruction Meta-Class Function Declaration
event handler, instruction meta-classRegistering the Instruction Meta-Class Function
event handler, instruction meta-classInstruction Meta-Class Function Layout
event historyEvent History
event type, instruction class setInstruction Class Set Event Handling
event type, instruction meta-classInstruction Meta-Class Event Handling
excitatory (positive) spurAutomatic Spur
exclusive terminal symbol classTerminal Symbol Classes
execution, modelCreating the Model Instance
execution, modelTerminating Model Execution
execution, nodeMultinode Model
execution, nodeCalling a Node
expression, symbol classSymbol Class Expressions

F
factored context-free grammarQSMM Components
factored context-free grammarBottom-Up Template Grammar
factored context-free grammarrege-vit
factored PCFGQSMM Components
factored PCFGBottom-Up Template Grammar
function, enumeration callbackRevising Action Choice States
function, enumeration callbackEnumerating Action Choice States and Cycle Types
function, enumeration callbackEnumerating Entities
function, error handlerError Handling for a Multinode Model
function, error handlerError Handling for the Side API
function, event handler, instruction class setInstruction Class Set Function Declaration
function, event handler, instruction class setRegistering the Instruction Class Set
function, event handler, instruction meta-classInstruction Meta-Class Function Declaration
function, event handler, instruction meta-classRegistering the Instruction Meta-Class Function
function, key comparisonCreating Maps and Iterators
function, proxyCustom Random Number Generators
function, relative probabilityCustomizing the Relative Probability Function
function, relative probability, helperHelper Relative Probability Functions
function, statistics update interceptionSpecifying Redirection Functions
function, storage redirectionSpecifying Redirection Functions

G
global entity identifierEntity References
global entity referenceEntity References
grammar, context-free, factoredQSMM Components
grammar, context-free, factoredBottom-Up Template Grammar
grammar, context-free, factoredrege-vit
grammar, context-free, initialCommand-Line Options of Top-Down Parser
grammar, context-free, initialCommand-Line Options of Bottom-Up Parser
grammar, context-free, initialrege-markup-cfg
grammar, context-free, initialrege-asm
grammar, template, bottom-upBottom-Up Template Grammar
grammar, template, top-downTop-Down Template Grammar

H
handleObject Handles
handle, actorCreating an Actor
handle, actor pairCreating the Model Instance
handle, assembler instructionBasic Datatypes for Assembler Programs
handle, assembler programBasic Datatypes for Assembler Programs
handle, iteratorCreating Maps and Iterators
handle, mapCreating Maps and Iterators
handle, messageCreating Messages
handle, message listCreating a Message List
handle, modelCreating a Handle
handle, model event handler callEvent Handler Call Parameters
handle, random number generatorCreating a Random Number Generator
handle, sideRegistering Interaction Sides
handle, storageStorage Handle
handle, vectorOrdinary and Sparse Vectors
helper relative probability functionHelper Relative Probability Functions

I
inclusive nonterminal symbol classNonterminal Symbol Classes
inclusive terminal symbol classTerminal Symbol Classes
incrementing spurIncrementing Spur
incrementing timeIncrementing Time
inhibitory (negative) spurAutomatic Spur
initial context-free grammarCommand-Line Options of Top-Down Parser
initial context-free grammarCommand-Line Options of Bottom-Up Parser
initial context-free grammarrege-markup-cfg
initial context-free grammarrege-asm
initial cycle-summed valueStructures for Accessing Storage
input signalAdaptive Probabilistic Mapping
input signalReceiving Input Signals
instance, instructionPrinciple of Operation
instance, modelCreating the Model Instance
instruction class nameInstruction Class Identifiers
instruction class nameRegistering Instruction Classes
instruction class sequencePrinciple of Operation
instruction class sequenceInstruction Class Sequences
instruction class setPrinciple of Operation
instruction class setDefining Instruction Class Sets
instruction class set event handlerInstruction Class Set Function Declaration
instruction class set event handlerRegistering the Instruction Class Set
instruction class set event handlerInstruction Class Set Function Layout
instruction class set nameInstruction Class Identifiers
instruction class set nameInstruction Class Set Function Declaration
instruction class set nameRegistering the Instruction Class Set
instruction class weightSetting Instruction Classes Weights
instruction class, individualPrinciple of Operation
instruction class, individualInstruction Class Identifiers
instruction class, individualRegistering Instruction Classes
instruction emitting enginePrinciple of Operation
instruction meta-classPrinciple of Operation
instruction meta-classDefining Instruction Meta-Classes
instruction meta-class event handlerInstruction Meta-Class Function Declaration
instruction meta-class event handlerRegistering the Instruction Meta-Class Function
instruction meta-class event handlerInstruction Meta-Class Function Layout
instruction meta-class namePrinciple of Operation
instruction meta-class nameInstruction Meta-Class Function Declaration
instruction meta-class nameRegistering the Instruction Meta-Class Function
instruction meta-class nameInstruction Class Identifiers
instruction meta-class nameRegistering Instruction Classes
instruction, assemblerDefining Instruction Meta-Classes
instruction, assemblerAssembler Programs
instruction, assemblerAssembler Instructions
instruction, comment forComments
instruction, fetchingInspecting an Assembler Program
instruction, handleBasic Datatypes for Assembler Programs
instruction, instancePrinciple of Operation
instruction, invocationHandling Instruction Invocation
instruction, label, dataPlain Program
instruction, label, locationPlain Program
instruction, mixed-typeAssembler Instructions
instruction, outcomePrinciple of Operation
instruction, outcomeSetting the Number of Instruction Outcomes
instruction, outcomeHandling Instruction Invocation
instruction, parameters, binaryInstruction Class Identifiers
instruction, parameters, binaryAccessing Binary Instruction Parameters
instruction, parameters, binaryRegistering Instruction Classes
instruction, parameters, binaryRegistering Instruction Classes
instruction, parameters, canonicalSetting Text Instruction Parameters
instruction, parameters, textInstruction Class Identifiers
instruction, parameters, textSetting Text Instruction Parameters
instruction, parameters, textRegistering Instruction Classes
instruction, printingPrinting an Assembler Program
instruction, splittingPlain Program
instruction, typeInspecting an Assembler Program
instruction, userAssembler Instructions
instruction, userUser Instructions
intelligenceWhat Is Intelligence?
interaction sideRegistering Interaction Sides
intercepting cycle type statistics updatesSpecifying Redirection Functions
invocation, instructionHandling Instruction Invocation
iterator handleCreating Maps and Iterators
iterator, creatingCreating Maps and Iterators
iterator, destroyingCreating Maps and Iterators

K
key comparison functionCreating Maps and Iterators

L
label, dataPlain Program
label, datajprob Instruction
label, datachoice Instruction Block
label, datachoice Instruction Block
label, dataVariables in an Assembler Program
label, dataOutput Arrays
label, locationPlain Program
large actorSmall and Large Actors
learned PCFGCommand-Line Options of Top-Down Parser
learningMultinode Model
learning, reinforcementSpur-Driven Behavior
length, nonterminal symbolNonterminal Symbols
length, nonterminal symbolCompound Nonterminal Symbols
loading a probability profile into a nodeLoading a Parsed Program into a Node
loading an assembler program into a nodeLoading a Parsed Program into a Node
local entity identifierEntity References
local entity referenceEntity References
location labelPlain Program
look-ahead signalSetting Look-Ahead Signals
look-ahead signallookup Instruction
look-ahead terminal symbolAlternatives
look-ahead terminal symbolLoops
look-ahead terminal symbolpeek Instruction
look-ahead terminal symbolParser Assembler Program Structure
loop, in a grammarLoops
loop, in a grammarParser Assembler Program Structure

M
map handleCreating Maps and Iterators
map, creatingCreating Maps and Iterators
map, destroyingCreating Maps and Iterators
mapping, probabilisticBuilding Blocks for Intelligent Machines
mapping, probabilistic, adaptiveBuilding Blocks for Intelligent Machines
mapping, probabilistic, adaptiveAdaptive Probabilistic Mapping
marker, end-of-productionTop-Down Template Grammar Specifiers
marker, end-of-productionnprod Instruction
marker, end-of-productiontprod Instruction
marker, end-of-streamTerminal Symbols
marker, production sideBottom-Up Template Grammar Specifiers
markup, source PCFGBottom-Up Template Grammar Specifiers
markup, source PCFGrege-markup-cfg
matrix, action emissionNode Parameters
matrix, action emissionDumping the Action Emission Matrix
matrix, state transitionNode Parameters
matrix, state transitionDumping the State Transition Matrix
mean discrete cycle periodRelative Probability Function Types
mean nominal number of output signalsNumber of Output Signals
message list, creatingCreating a Message List
message list, destroyingCreating a Message List
message list, handleCreating a Message List
message, creatingCreating Messages
message, destroyingCreating Messages
message, handleCreating Messages
meta-class, instructionPrinciple of Operation
meta-class, instructionDefining Instruction Meta-Classes
mixed-type instructionAssembler Instructions
mode, behaviorSwitching Adaptive or Random Behavior of an Actor
mode, behaviorSwitching Adaptive or Random Behavior of a Multinode Model
model event handler call handleEvent Handler Call Parameters
model executionCreating the Model Instance
model executionTerminating Model Execution
model handleCreating a Handle
model instance, creatingCreating the Model Instance
model instance, destroyingCreating the Model Instance
model, creatingCreating a Handle
model, destroyingCreating a Handle
model, stateIntroduction
multinode modelBuilding Blocks for Intelligent Machines
multinode modelMultinode Model

N
n-gram buffer, actorReceiving Input Signals
n-gram, action choice stateEvent History
name, instruction classInstruction Class Identifiers
name, instruction classRegistering Instruction Classes
name, instruction class setInstruction Class Identifiers
name, instruction class setInstruction Class Set Function Declaration
name, instruction class setRegistering the Instruction Class Set
name, instruction meta-classPrinciple of Operation
name, instruction meta-classInstruction Meta-Class Function Declaration
name, instruction meta-classRegistering the Instruction Meta-Class Function
name, instruction meta-classInstruction Class Identifiers
name, instruction meta-classRegistering Instruction Classes
name, statestt Instruction
name, stateState Names in stt Instructions
named terminal symbol segmentTerminal Symbols
named terminal symbol segmentNamed Terminal Symbol Segments
named terminal symbol segmentrege-markup-cfg
nodeBuilding Blocks for Intelligent Machines
nodeMultinode Model
node class, instruction class setDefining Instruction Class Sets
node, assemblingAssembling a Node
node, callingCalling a Node
node, creatingCreating Nodes
node, destroyingCreating Nodes
node, disassemblingDisassembling a Node
node, executionMultinode Model
node, executionCalling a Node
node, loading a probability profile intoLoading a Parsed Program into a Node
node, parametersNode Parameters
node, parametersNode Parameters
node, possessing controlMultinode Model
node, returning control fromReturning Control from a Node
node, transferring control toCalling a Node
node, unloading a probability profile fromUnloading the Probability Profile
nominal number of output signalsNumber of Output Signals
nonterminal symbol class, deep cloningSymbol Class Expressions
nonterminal symbol class, expressionSymbol Class Expressions
nonterminal symbol class, inclusiveNonterminal Symbol Classes
nonterminal symbol, cloningCloning Nonterminal Symbols
nonterminal symbol, cloning, deepCloning Nonterminal Symbols
nonterminal symbol, compoundNonterminal Symbols
nonterminal symbol, compoundCompound Nonterminal Symbols
nonterminal symbol, contextCompound Nonterminal Symbols
nonterminal symbol, lengthNonterminal Symbols
nonterminal symbol, lengthCompound Nonterminal Symbols
nonterminal symbol, simpleNonterminal Symbols
nonterminal symbol, startTop-Down Template Grammar
nonterminal symbol, startNonterminal Symbols
nonterminal symbol, stemCompound Nonterminal Symbols
nonterminal symbol, virtualReverse Order Sequences
nonterminal symbol, virtualEnding a Terminal Production
nonterminal symbol, virtualRestrictions for Bottom-Up Parsing
normalization, probabilities listPreloading a Probability Profile
number of output signals, nominalNumber of Output Signals

O
outcome, instructionPrinciple of Operation
outcome, instructionSetting the Number of Instruction Outcomes
outcome, instructionHandling Instruction Invocation
output probabilities arraychoice Instruction Block
output probabilities arrayOutput Arrays
output probability variableOutput Variables
output signalAdaptive Probabilistic Mapping
output signalEmitting an Output Signal
output signalEmitting an Output Signal
output signal choice treeSmall and Large Actors
output signal choice tree, arityCreating an Actor
output signal choice tree, arityosct
output signal choice tree, defaultNumber of Output Signals
output signal choice tree, defaultPreloading a Probability Profile
output signal choice tree, defaultAssigning a Preloaded Probability Profile
output signal choice tree, defaultAssigning a Preloaded Probability Profile
output signal permutationPreloading a Probability Profile
output signal permutationPreloading a Probability Profile
output signal weightSpecifying Output Signal Weights
output terminal symbolOutput Terminal Symbols
output terminal symbolwr Instruction

P
parameters, assembler instructionInstruction Class Identifiers
parameters, assembler instructionAccessing Binary Instruction Parameters
parameters, assembler instructionSetting Text Instruction Parameters
parameters, assembler instructionRegistering Instruction Classes
parameters, assembler instructionRegistering Instruction Classes
parameters, assembler instructionRegistering Instruction Classes
parameters, nodeNode Parameters
parameters, nodeNode Parameters
parse tree, printingCommand-Line Options of Top-Down Parser
parse tree, printingCommand-Line Options of Bottom-Up Parser
parse tree, printingCommand-Line Options of Bottom-Up Parser
parser, bottom-upabu-parser
parser, bottom-up, assembler instructionsAssembler Instruction Set for Bottom-Up Parser
parser, top-downatd-parser
parser, top-down, assembler instructionsAssembler Instruction Set for Top-Down Parser
parsing an assembler programParsing an Assembler Program
PCFG, derivedabu-parser
PCFG, derivedCommand-Line Options of Bottom-Up Parser
PCFG, factoredQSMM Components
PCFG, factoredBottom-Up Template Grammar
PCFG, formatPCFG Format
PCFG, learnedCommand-Line Options of Top-Down Parser
PCFG, sourceBottom-Up Template Grammar
PCFG, sourceCommand-Line Options of Bottom-Up Parser
PCFG, sourcerege-markup-cfg
PCFG, source, markupBottom-Up Template Grammar Specifiers
perceived stateBuilding Blocks for Intelligent Machines
perception, spurSpur Perception
period, cycleReceiving Input Signals
period, cycleReceiving Input Signals
period, cycleRelative Probability Function Types
permutation, output signalsPreloading a Probability Profile
permutation, output signalsPreloading a Probability Profile
plain assembler programPlain Program
plain assembler programRecommended Assembler Program Structure
pool, output signal permutationsPreloading a Probability Profile
pool, output signal permutationsPreloading a Probability Profile
pool, probabilities lists in normal formPreloading a Probability Profile
possessing control by a nodeMultinode Model
prefix for virtual terminal symbolsEnding a Terminal Production
prefix for virtual terminal symbolsRestrictions for Bottom-Up Parsing
prefix for virtual terminal symbolsCommand-Line Options of Bottom-Up Parser
preprocessing an assembler programUsing the Assembler Preprocessor
printing an assembler instructionPrinting an Assembler Program
probabilistic mappingBuilding Blocks for Intelligent Machines
probabilistic mapping, adaptiveBuilding Blocks for Intelligent Machines
probabilities array, outputchoice Instruction Block
probabilities array, outputOutput Arrays
probabilities list normalizationPreloading a Probability Profile
probability profile, cloningCloning the Probability Profile
probability profile, cloning, deferredMemory Efficient Cloning the Probability Profile
probability profile, defaultRegistering the Instruction Class Set
probability profile, defaultNode Parameters
probability profile, defaultNode Parameters
probability profile, defaultCreating Nodes
probability profile, loading into a nodeLoading a Parsed Program into a Node
probability profile, preloadedSpecifying Output Signal Weights
probability profile, preloadedPreloading a Probability Profile
probability profile, unloading from a nodeUnloading the Probability Profile
probability variableUsing Probability Variables
probability variable, auxiliaryAuxiliary Variables
probability variable, controlledControlled Variables
probability variable, definingjprob Instruction
probability variable, definingchoice Instruction Block
probability variable, definingVariables in an Assembler Program
probability variable, outputOutput Variables
program, assemblerAssembler Program Syntax
proxy functionCustom Random Number Generators
pseudo-random number generatorRandom Number Generators
put-back terminal symbolPut-Back Terminal Symbols
put-back terminal symbolscn Instruction

Q
quantifier, ?Alternatives
quantifier, ?Parser Assembler Program Structure
quantifier, ?rege-markup-cfg
quantifier, *Loops
quantifier, *Marking a Left-Hand Side
quantifier, *Marking a Right-Hand Side
quantifier, *Parser Assembler Program Structure

R
random behavior modeSwitching Adaptive or Random Behavior of an Actor
random behavior modeSwitching Adaptive or Random Behavior of a Multinode Model
random number generator, creatingCreating a Random Number Generator
random number generator, destroyingCreating a Random Number Generator
random number generator, handleCreating a Random Number Generator
redirection function, initial conditionSpecifying Redirection Functions
redirection function, initial statisticsSpecifying Redirection Functions
redirection function, next cycle typeSpecifying Redirection Functions
redirection function, statistics updateSpecifying Redirection Functions
registering an interaction sideRegistering Interaction Sides
reinforcement learningSpur-Driven Behavior
relative probability functionCustomizing the Relative Probability Function
relative probability function, helperHelper Relative Probability Functions
returning control from a nodeReturning Control from a Node
reverse order sequenceReverse Order Sequences
run, modelCreating the Model Instance

S
sequence, in a grammarSequences and Groupings
sequence, in a grammarReverse Order Sequences
sequence, instruction classPrinciple of Operation
sequence, instruction classInstruction Class Sequences
sequence, reverse orderReverse Order Sequences
Side APIExchanging Data Packets in a Multithreaded Program
side handleRegistering Interaction Sides
signalBasic Datatypes and Macros
signal ranges arrayCreating an Actor
signal ranges arrayCreating an Actor
signal ranges arrayRevising Action Choice States
signal ranges arrayEnumerating Action Choice States and Cycle Types
signal ranges arrayCreating a Handle
signal, inputAdaptive Probabilistic Mapping
signal, inputReceiving Input Signals
signal, look-aheadSetting Look-Ahead Signals
signal, look-aheadlookup Instruction
signal, outputAdaptive Probabilistic Mapping
signal, outputEmitting an Output Signal
signal, outputEmitting an Output Signal
signal, output, permutationPreloading a Probability Profile
signal, output, permutationPreloading a Probability Profile
signal, output, weightSpecifying Output Signal Weights
small actorSmall and Large Actors
source PCFGBottom-Up Template Grammar
source PCFGCommand-Line Options of Bottom-Up Parser
source PCFGrege-markup-cfg
source PCFG, markupBottom-Up Template Grammar Specifiers
source PCFG, markuprege-markup-cfg
source terminal symbolEnding a Terminal Production
splitting an assembler instructionPlain Program
spurSpur-Driven Behavior
spur, automaticAutomatic Spur
spur, excitatory (positive)Automatic Spur
spur, increment velocityOutput Signal Selection
spur, increment velocityIncrementing Time
spur, increment velocityRelative Probability Function Types
spur, increment velocitySpur Perception
spur, incrementingIncrementing Spur
spur, inhibitory (negative)Automatic Spur
spur, perceptionSpur Perception
spur, schemeIncrementing Spur
spur, typeSpur-Driven Behavior
spur, weightSpur Weight
stack frame, systemWorking with the Node Call Stack
stack frame, userWorking with the Node Call Stack
start nonterminal symbolTop-Down Template Grammar
start nonterminal symbolNonterminal Symbols
stateBuilding Blocks for Intelligent Machines
state modelIntroduction
state sub-modelBuilding Blocks for Intelligent Machines
state transition matrixNode Parameters
state transition matrixDumping the State Transition Matrix
state, automatonBuilding Blocks for Intelligent Machines
state, automatonEvent History
state, automatonAutomatic Spur
state, in an assembler programstt Instruction
state, in an assembler programState Beginning and Instruction Selection
state, in an assembler programPossible State Beginning Reasons
state, namestt Instruction
state, nameState Names in stt Instructions
statistics for a cycle typeStructures for Accessing Storage
statistics update interception functionSpecifying Redirection Functions
statistics, aggregateOutput Variables
statistics, aggregateOutput Arrays
stem, nonterminal symbolCompound Nonterminal Symbols
STL map templateThe Implementation of Functionality of STL map Template
storage handleStorage Handle
storage redirectionStatistics Storage
storage redirection, functionSpecifying Redirection Functions
sub-model, stateBuilding Blocks for Intelligent Machines
system stack frameWorking with the Node Call Stack

T
temperature, actorActor Temperature
template grammar, bottom-upBottom-Up Template Grammar
template grammar, commentsTop-Down Template Grammar
template grammar, top-downTop-Down Template Grammar
terminal symbol class, emptyTerminal Symbol Classes
terminal symbol class, exclusiveTerminal Symbol Classes
terminal symbol class, expressionSymbol Class Expressions
terminal symbol class, inclusiveTerminal Symbol Classes
terminal symbol, deferringReverse Order Sequences
terminal symbol, deferringDeferring a Terminal Symbol
terminal symbol, deferringpushd Instruction
terminal symbol, inputInput Terminal Symbols
terminal symbol, inputrd Instruction
terminal symbol, look-aheadAlternatives
terminal symbol, look-aheadLoops
terminal symbol, look-aheadpeek Instruction
terminal symbol, look-aheadParser Assembler Program Structure
terminal symbol, named segmentTerminal Symbols
terminal symbol, named segmentNamed Terminal Symbol Segments
terminal symbol, named segmentrege-markup-cfg
terminal symbol, outputOutput Terminal Symbols
terminal symbol, outputwr Instruction
terminal symbol, placeholderTerminal Symbols
terminal symbol, put-backPut-Back Terminal Symbols
terminal symbol, put-backscn Instruction
terminal symbol, sourceEnding a Terminal Production
terminal symbol, virtualReverse Order Sequences
terminal symbol, virtualEnding a Terminal Production
terminal symbol, virtualRestrictions for Bottom-Up Parsing
terminal symbol, virtualCommand-Line Options of Bottom-Up Parser
terminating model executionTerminating Model Execution
text instruction parametersInstruction Class Identifiers
text instruction parametersSetting Text Instruction Parameters
text instruction parametersRegistering Instruction Classes
text instruction parameters, canonicalSetting Text Instruction Parameters
time, continuousIncrementing Time
time, cycle startReceiving Input Signals
time, discreteIncrementing Time
time, incrementingIncrementing Time
time, typeIncrementing Time
top-down parseratd-parser
top-down parser assembler instructionsAssembler Instruction Set for Top-Down Parser
top-down template grammarTop-Down Template Grammar
trace logTracing Model Execution
trace logTracing the Exchange of Data Packets
transferring control to a nodeCalling a Node
type, cycleOutput Signal Selection
type, cycleReceiving Input Signals
type, cycleSpur Perception
type, entityEntity References
type, instructionInspecting an Assembler Program
type, spurSpur-Driven Behavior
type, timeIncrementing Time

U
uniform probability profileRegistering the Instruction Class Set
uniform probability profileNode Parameters
uniform probability profileNode Parameters
uniform probability profileCreating Nodes
unloading a probability profile from a nodeUnloading the Probability Profile
unregistering an interaction sideRegistering Interaction Sides
user instructionAssembler Instructions
user instructionUser Instructions
user stack frameWorking with the Node Call Stack

V
variable, auxiliaryAuxiliary Variables
variable, controlledControlled Variables
variable, outputOutput Variables
vector handleOrdinary and Sparse Vectors
vector, destroyingOrdinary and Sparse Vectors
velocity, spur incrementOutput Signal Selection
velocity, spur incrementIncrementing Time
velocity, spur incrementRelative Probability Function Types
velocity, spur incrementSpur Perception
virtual nonterminal symbolReverse Order Sequences
virtual nonterminal symbolEnding a Terminal Production
virtual nonterminal symbolRestrictions for Bottom-Up Parsing
virtual terminal symbolReverse Order Sequences
virtual terminal symbolEnding a Terminal Production
virtual terminal symbolRestrictions for Bottom-Up Parsing
virtual terminal symbolCommand-Line Options of Bottom-Up Parser

W
weight, instruction classSetting Instruction Classes Weights
weight, output signalSpecifying Output Signal Weights
weight, spur typeSpur Weight


Footnotes

(1)

As the author of this manual read a translation of that book, its original text in English might use a word other than burin.

(2)

A profile probability does not fall into the category “statistics.” The structure qsmm_cycle_s holds a profile probability along with statistics on a cycle type.

(3)

Here and below, “the invocation/execution of an instruction class” means “the invocation/execution of an instruction belonging to an instruction class.”