About

EASEL is a modeling language, able to represent compartmental and other scientific models in a concise, human- and machine-readable way. It builds off Galois's experience with the AMIDOL IR, and is intended to supplant it in the long term. It, like the AMIDOL IR, is meant to represent stochastic Petri nets with a form of inhibitor arcs.

What follows is an explanation of this language's format and features by example, the example being an adapted, subset version of the CHIME epidemiological model from UPenn.

models

A model is a named entity (CHIME in the example), followed by a set of declarations of state and other variables, followed by a set of declarations of events that may depend on or modify these variables, modulo some rules.

models are constructed blockwise in a whitespace-sensitive way that should be familiar to users of YAML and other similar languages.

parameter-Declared Variables

parameter contact_rate = 0.05
parameter contact_multiplier = 1 - contact_rate

Variables declared with parameter are meant to function as the "inputs" to a model. They are optionally bound to expressions in a model's specification, as is the case with both above parameters. These bindings represent parameter defaults. If a default is not provided, it is incumbent on the user to provide a parameter value when requesting the simulation of a model. See donu for more on simulation requests. Though CHIME does not include any, a parameter declaration without a default is formed in this way:

parameter A

While a user is required to provide values for parameters without defaults, they are also allowed to override the defaults specified for any other parameter(s) they choose, when simulating. This has implications for the interplay between contact_rate and contact_multiplier: as the model sits, the default for contact_rate is 0.05 and the default for contact_multiplier is 0.95. If a user manually overrides contact_rate but does not manually override contact_multiplier, their parameterization will nonetheless affect the value of contact_multiplier, as it depends on contact_rate.

Note: parameter variables may not depend on any of the model's state - that is, they must be constant throughout a model's simulation. If you want to create a variable that can depend on state, see let.

let-Declared Variables

  let s_Initial = 999.0
  ...
  let beta =
    cond:
      gamma              if time <= policy_days0
      gamma + 0.1486983  if time <= policy_days1
      gamma + 0.0717734  otherwise

Variables declared with let are bound to expressions - these may be constants, in the case of s_Initial, or more complex, state-dependent expressions, in the case of beta. As they can depend on state variables, unlike parameters, lets may change their value throughout a model's simulation. Unlike state variables, lets cannot be directly modified in an event's effect section.

state-Declared Variables

  state Susceptible = s_Initial
  state Infected    = i_Initial
  state Recovered   = r_Initial

Variables declared with state differ internally from let-declared variables in that they may be modified in an event's effect block. These variables may be used to represent what the model is actually modeling - that is, they may be the output of an execution/simulation of a model (though they needn't be).

events

  event Infect:
  ...

An event consists of an enabling predicate (a when block), a rate (how likely this event is to "fire"), and an effect, which describes what happens when the event fires (an "output predicate", in some previous Galois literature).

when

    when:
      Susceptible > 0.0 and Infected > 0.0

An expression defined on let variables and state variables, evaluating to a Boolean, which determines whether or not an event is able to fire. An event must have a true when and be chosen stochastically based on its rate in order to fire.

rate

    rate:
      beta * contact_multiplier * Susceptible * Infected / total_pop

An expression defined on let variables and state variables, evaluating to a real, which represents the frequency with which an event fires. In simulation, events would be chosen stochastically based on this value - a rate of 0.8 means at any given time step an event would have an 80% chance of firing.

effect

    effect:
      Susceptible -= 1.0
      Infected    = Infected + 1.0

What happens when the model fires. This is a series of assignments, executed in order, that may change the value of some or all of the state variables in the model.

Example

model CHIME_GTRI_IR:
  let  s_Initial = 999.0
  let  i_Initial = 10.0
  let  r_Initial = 0.0

  state Susceptible = s_Initial
  state Infected    = i_Initial
  state Recovered   = r_Initial

  let gamma = 1.0 / 14.0
  let policy_days0 = 37.0
  let policy_days1 = 77.0
  parameter contact_rate = 0.05
  parameter contact_multiplier = 1 - contact_rate

  let total_pop = Susceptible + Infected + Recovered
  let beta =
    cond:
      gamma              if time <= policy_days0
      gamma + 0.1486983  if time <= policy_days1
      gamma + 0.0717734  otherwise

  # or
  # let beta =
  #   if time <= policy_days0
  #     then gamma
  #   else if time <= policy_days1
  #     then gamma + 0.1486983
  #   else
  #     gamma + 0.0717734

  event Infect:
    when:
      Susceptible > 0.0 and Infected > 0.0

    rate: 
      beta * contact_multiplier * Susceptible * Infected / total_pop

    effect:
      Susceptible = Susceptible - 1.0
      Infected    = Infected + 1.0

  event Cure:
    when:
      Infected > 0.0

    rate:
      gamma * Infected

    effect:
      Infected  = Infected - 1.0
      Recovered = Recovered + 1.0

          

Donu Documentation

About Donu

Donu is the webservice that is able to run simulations and various kinds of analysis on models for the ASKE-E program.

Calling Convention

All operations are implemented at path / and are indifferent to HTTP verb (GET, POST, etc.)

Response Convention

All responses return a two-element dict.

On success, the members are "status", which will map to the literal string "success", and "result", which will map to a dict containing whatever is specified below in a command's Response section.

On error, the members are "status", which will map to the literal string "error", and "error", which will map to a string description of the error.

The provided examples reflect this schema.

Types

datasource

A datasource is either an object with the single field model with :

FieldTypeDescription
modelstringFilename to use as a data source

Example:

{ "model": "model.gromet" }

Or a string containing the data itself:

"model SIR:\n  let beta = 0.4\n  let gamma = 0.04\n  let s_initial = 997..."

model-def

A model def is a datasource along with a model type. Valid model types are easel, diff-eqs, core, gromet-pnc, and gromet-prt.

Example:

{
  "source": { "model": "sir.easel" },
  "type": "easel"
}

Operations

list-models - List the available models

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "list-models"

Example:

{ "command": "list-models"}

Response:

FieldTypeDescription
modelslistlist of "model-def++" objects - guaranteed to have the same members as a model-def object, but will also include "name" and "description" members for ESL models

Example:

{
  "status": "success",
  "result": {
    "models": [
      {
        "source": { "model": "sir.easel" },
        "type": "easel",
        "name": "SIR",
        "description": "No description."
      }
    ]
  }
}

query-models - Query models based on metadata

Request:

FieldTypeDescription
commandstringThe literal "query-models"
textstringText to search for. Accepts wildcards * and ?. Searches through model source name, model level metadata (both, as returned by list-models) as well as parameter and measure metadata values for a match.

Example:

{
  "command": "query-models",
  "text": "*hospital*"
}

Response:

Description
list of "model-def++" objects of the same form as returned by list-models

Example:

{
  "status": "success",
  "result": [
    {
      "source": {
          "model": "seird_hosp.easel"
      },
      "name": "SEIRS_Hospitalization_Death",
      "description": "No description.",
      "type": "easel"
    },
    {
      "source": {
          "model": "seird_hosp.easel"
      },
      "type": "gromet-prt"
    }
  ]
}

simulate - simulate a model

Request:

FieldTypeDescriptionStipulations
commandstringThe literal "simulate"
sim-typestring(optional) Simulation engine - one of "aj", "discrete", "gsl", "automates"Defaults to a model specific simulation type
definitionmodel-defDefinition of the model
startnumberStart time of the simulation
endnumberEnd time of the simulation
stepnumberSimulation time step size
seedinteger(optional) Seed for random number generation/event selectionOnly valid when sim-type is discrete
domain-parameterstring(optional) Independent variable over which start/step/end variesNot yet supported, and only valid when simulating function networks
parametersdict(optional) Parameter values/initial conditions for the simulationWhen sim-type is aj, parameters specified neither here nor in the model will default to 0
outputslistRestrict model output to these valuesLeave empty to output all variables

Example:

{
  "command": "simulate",
  "sim-type": "gsl",
  "definition": {
    "type": "easel",
    "source": { "model": "sir.easel" }
  },
  "start": 0,
  "end": 120.0,
  "step": 30.0,
  "parameters": {
    "beta": 0.9
  }
}

Response:

Description
A list of simulation results

Simulation result schema:

FieldTypeDescription
timeslist of numberseries of times used in simulation
valuesresult series objectvalues of state variables

Each object in values is structured such that each key is the name of a model variable V and each value is a list l such that V has the value l[x] at time times[x].

Example:

{
  "status": "success",
  "result": [
    {
      "values": {
        "I": [
          3,
          396.20766691080604,
          119.33588838987737,
          35.943279530151585,
          10.825907756942332
        ],
        "S": [
          997,
          0.0012550867795002216,
          2.4726152151230926e-06,
          3.7868257221162325e-07,
          2.151977671793774e-07
        ],
        "R": [
          0,
          603.7910780024147,
          880.6641091375077,
          964.0567200911661,
          989.1740920278602
        ]
      },
      "times": [
        0,
        30,
        60,
        90,
        120
      ]
    }
  ]
}

get-model-schematic - get schematic description of a model

This call gets a high level schematic description of a model as a graph. Not all models support this visualization.

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "get-model-schematic"
definitionmodel-defDefinition of the model

Example:

{
  "command": "get-model-schematic",
  "definition": {
    "type": "easel",
    "source": { "model": "sir.easel" }
  }
}

Response:

FieldTypeDescription
nodeslist of nodeA node has a name and a type
edgeslist of edgeAn edge is a "tuple" mapping one node to another
{
  "status": "success",
  "result": {
    "nodes": [
      {
        "name": "Infect",
        "type": "event"
      },
      {
        "name": "S",
        "type": "state"
      },
      {
        "name": "I",
        "type": "state"
      },
      {
        "name": "Remove",
        "type": "event"
      },
      {
        "name": "R",
        "type": "state"
      }
    ],
    "edges": [
      [
        {
          "name": "Infect",
          "type": "event"
        },
        {
          "name": "I",
          "type": "state"
        }
      ],
      [
        {
          "name": "S",
          "type": "state"
        },
        {
          "name": "Infect",
          "type": "event"
        }
      ],
      [
        {
          "name": "I",
          "type": "state"
        },
        {
          "name": "Remove",
          "type": "event"
        }
      ],
      [
        {
          "name": "Remove",
          "type": "event"
        },
        {
          "name": "R",
          "type": "state"
        }
      ]
    ]
  }
}

get-model-source - get source code for a model

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "get-model-source"
definitionmodel-defDefinition of the model
{
  "command": "get-model-source",
  "definition": {
    "type": "easel",
    "source": { "model": "sir.easel" }
  }
}

Response:

The result, if successful, is a model-def object with the source inline.

{
  "status": "success",
  "result": {
    "source": "model SIR:\n  let beta = 0.4\n  let gamma = 0.04\n\n  let s_initial = 997\n  let i_initial = 3\n  let r_initial = 0\n\n  state S = s_initial\n  state I = i_initial\n  state R = r_initial\n\n  let total_population = S + I + R\n\n  event Infect:\n    when:\n      S > 0 and I > 0\n    rate: \n      beta * S * I / total_population\n    effect:\n      S -= 1\n      I += 1\n      \n  event Remove:\n    when:\n      I > 0\n    rate: \n      gamma * I\n    effect:\n      I -= 1\n      R += 1\n      \n      ",
    "type": "easel"
  }
}

convert-model - convert a model from one form to another

May fail if the conversion is not supported.

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "convert-model"
definitionmodel-defDefinition of the model
dest-typestringModel type to convert to - same fields model-def's type field
{
  "command": "convert-model",
  "definition": {
    "type": "easel",
    "source": { "model": "sir.easel" }
  },
  "dest-type":"diff-eqs"
}

Response:

The result, if successful, is a model-def object with the new model inline.

{
  "status": "success",
  "result": {
    "source": "let beta = 0.4\nlet gamma = 0.04\nlet i_initial = 3.0\nlet r_initial = 0.0\nlet s_initial = 997.0\nlet total_population = S + I + R\nI(0) = 3.0\nR(0) = 0.0\nS(0) = 997.0\nd/dt I = (if 0.0 < S and 0.0 < I then 0.4 * S * I / (S + R + I) else 0.0) + (if 0.0 < I then -0.04 * I else 0.0)\nd/dt R = if 0.0 < I then 0.04 * I else 0.0\nd/dt S = if 0.0 < S and 0.0 < I then -0.4 * S * I / (S + R + I) else 0.0",
    "type": "diff-eqs"
  }
}

describe-model-interface - describe parameters of a model

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "describe-model-interface"
definitionmodel-defDefinition of the model
{
  "command": "describe-model-interface",
  "definition": {
    "type": "easel",
    "source": {
      "model": "sir.easel"
    }
  }
}

Response

FieldTypeDescription
measureslist of state variablesSomething the can be measured
parameterslist of parameterSomething that can be tweaked

Both measures and parameters are lists of objects, where each object has uid, value_type and metadata fields. In addition, parameters may have a default field.

The metadata is an object with variable fields, but some of interest are description, name, and group. In particular, group may be used as a hint to group related parameters.

Response:

{
  "status": "success",
  "result": {
    "measures": [
      {
        "metadata": {
          "name": "I"
        },
        "value_type": "Real",
        "uid": "I"
      },
      {
        "metadata": {
          "name": "R"
        },
        "value_type": "Real",
        "uid": "R"
      },
      {
        "metadata": {
          "name": "S"
        },
        "value_type": "Real",
        "uid": "S"
      },
      {
        "metadata": {
          "name": "total_population"
        },
        "value_type": "Real",
        "uid": "total_population"
      }
    ],
    "parameters": [
      {
        "metadata": {
          "name": "beta"
        },
        "value_type": "Real",
        "uid": "beta"
      },
      {
        "metadata": {
          "name": "gamma"
        },
        "value_type": "Real",
        "uid": "gamma"
      },
      {
        "metadata": {
          "name": "i_initial"
        },
        "value_type": "Real",
        "uid": "i_initial"
      },
      {
        "metadata": {
          "name": "r_initial"
        },
        "value_type": "Real",
        "uid": "r_initial"
      },
      {
        "metadata": {
          "name": "s_initial"
        },
        "value_type": "Real",
        "uid": "s_initial"
      },
      {
        "metadata": {
          "name": "beta"
        },
        "value_type": "Real",
        "default": 0.4,
        "uid": "beta"
      },
      {
        "metadata": {
          "name": "gamma"
        },
        "value_type": "Real",
        "default": 0.04,
        "uid": "gamma"
      },
      {
        "metadata": {
          "name": "i_initial"
        },
        "value_type": "Real",
        "default": 3,
        "uid": "i_initial"
      },
      {
        "metadata": {
          "name": "r_initial"
        },
        "value_type": "Real",
        "default": 0,
        "uid": "r_initial"
      },
      {
        "metadata": {
          "name": "s_initial"
        },
        "value_type": "Real",
        "default": 997,
        "uid": "s_initial"
      }
    ]
  }
}

upload-model - Upload a new model

This command may fail if you attempt to overwrite an existing model, or if the model you attempt to upload is not syntactically valid.

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "upload-model"
namestringThe (base)name of the model in storage
typestringModel type - same options as model-def's type field
definitionstringThe model itself, inlined as a string

Example:

command = {
    "command": "upload-model",
    "name": "sir.easel",
    "type": "easel",
    "definition": "model SIR:\n  let beta = 0.4\n  let gamma = 0.04\n\n  let s_initial = 997\n  let i_initial = 3\n  let r_initial = 0\n\n  state S = s_initial\n  state I = i_initial\n  state R = r_initial\n\n  let total_population = S + I + R\n\n  event Infect:\n    when:\n      S > 0 and I > 0\n    rate: \n      beta * S * I / total_population\n    effect:\n      S -= 1\n      I += 1\n      \n  event Remove:\n    when:\n      I > 0\n    rate: \n      gamma * I\n    effect:\n      I -= 1\n      R += 1\n      \n      "
}

Response:

The result, if successful, is a model-def object with the new file in the source field.

Example:

{
  "status": "success",
  "result": {
    "source": { "model": "sir.easel" },
    "type": "easel"
  }
}

list-datasets List available datasets

Request:

FieldTypeDescription
commandstringCommand - for this operation it will be the string "list-datasets"

Example:

{
  "command": "list-datasets"
}

Response:

Description
A list of dataset descriptions.
{
  "status": "success",
  "result": [
    {
      "source": {
        "model": "example.json"
      },
      "name": "Example Data",
      "description": "Example data drawn from SIR model"
    },
    {
      "source": {
        "model": "sir_noise.json"
      },
      "name": "SIR Infected with Noise",
      "description": "Infected values from SIR model with added noise"
    },
    {
      "source": {
        "model": "sir_sample.json"
      },
      "name": "Sample SIR Data",
      "description": "Sample data generated from a SIR model"
    }
  ]
}

get-dataset Get a dataset

FieldTypeDescription
commandstringCommand - for this operation it will be the string "get-dataset"
sourcedatasourceDatasource for model (e.g. from list-datasets)

Request:

Example:

{
  "command": "get-dataset",
  "source": {"model": "example.json"}
}

Response:

Dataset schema:

FieldTypeDescription
namestringDisplay name of this dataset
descriptionstringHuman readable description for this data set
columnsarray of columnList of columns (see column schema)

Column schema:

FieldTypeDescription
namestringName of this column
descriptionstringHuman readable description for this column
valuesarray of numbersData values

Example:

{
  "status": "success",
  "result": {
    "name": "Example Data",
    "description": "Example data drawn from SIR model",
    "columns": [
      {
        "values": [
          3,
          570.9758710681087,
          177.8779579737781,
          53.66360145338841,
          16.175249034797183
        ],
        "name": "I",
        "description": "Infected Population"
      },
      {
        "values": [
          0,
          412.987493166334,
          821.8532404022537,
          946.2589265257153,
          983.7715119765173
        ],
        "name": "R",
        "description": "Recovered Population"
      },
      {
        "values": [
          997,
          16.036635765557786,
          0.2688016239687889,
          0.07747202089688701,
          0.05323898868597068
        ],
        "name": "S",
        "description": "Susceptible Population"
      },
      {
        "values": [
          0,
          30,
          60,
          90,
          120
        ],
        "name": "time",
        "description": "Time (in days)"
      }
    ]
  }
}

fit-measure Estimate model parameters

Request

FieldTypeDescription
commandstringCommand - for this operation it will be the string "fit-measure"
definitionmodel-defDatasource for model (e.g. from list-datasets)
parameterslist of stringParameters to try to find values for
datadataseriesData series to fit against (see below)

Data series:

FieldTypeDescription
valuesobjectKeys are model variable names, values are lists of points
timeslist of numbersCorresponding times for the data points

Each value of the values object should be an array of the same length as times.

Example:

{
  "command": "fit-measures",
  "definition": {
    "type": "easel",
    "source": { "model": "sir-meta.easel" }
  },
  "parameters": ["beta", "gamma"],
  "data": {
    "values": {
      "I": [
        3, 74.78758342604473, 623.3137065799646, 761.227660031603, 641.3487163757723, 526.5677251792523,
        431.297586129131, 353.1478923294002, 289.1402682575921, 236.73013719570082, 193.81898629689385,
        158.6858700205345, 129.92114428227376, 106.37050988809484, 87.08884901094167, 71.30234380846396,
        58.37743746622634, 47.7954138770176, 39.131582481945436, 32.03823518720198, 26.23069221742839,
        21.47587722450436, 17.582963280246798, 14.395714419465202, 11.786215392681438
      ]
    },
    "times": [
      0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120
    ]
  }
}

Response

The result field contains a object whose keys are parameter names and whose values are the estimated parameter values

Example:

{
  "status": "success",
  "result": {
    "gamma": 4.0000000000252035e-2,
    "beta": 0.6999999999997466
  }
}

Compare models

Compare two models, if possible.

(At the moment, "if possible" means that we've already performed a comparison of these two models and stored the result - live comparison isn't currently supported.)

Request

FieldTypeDescription
commandstringCommand - for this operation it will be the string "compare-models"
sourcemodel-defSource of the model acting as the comparison "source"
targetmodel-defSource of the model acting as the comparison "target"

Example:

{
    "command": "compare-models",
    "source": {
        "type": "gromet-pnc",
        "source": {"model": "SimpleSIR_metadata_gromet_PetriNetClassic.json"}
    },
    "target": {
        "type": "gromet-pnc",
        "source": {"model": "chime+.json"}
    }
}

Response

The result field contains a list of variable-to-variable mappings, with keys being variables in the source model and values being variables in the target model. The list is in no particular order.

Example:

{
    "status": "success",
    "result": [
        {
            "J:I": "J:I_U",
            "J:S": "J:S",
            "J:R": "J:R",
            "J:gamma": "J:rec_u",
            "J:beta": "J:inf_uu"
        },
        {
            "J:I": "J:I_V",
            "J:S": "J:V",
            "J:R": "J:R",
            "J:gamma": "J:rec_v",
            "J:beta": "J:inf_vv"
        }
    ]
}

compute-error Error Measurement

Request:

{
  "command": "compute-error",
  "interp-model": "linear",
  "error-model": "L2",
  "measures": [
    {
      "uid": "J:I",
      "predicted": {
        "times": [1,2,3,4,5,6],
        "values": [1,2,3,4,5,6]
      },
      "observed": {
        "times": [1,2,3,4,5,6],
        "values": [1,1,2,2,3,3]
      }
    },
    {
      "uid": "J:J",
      "predicted": {
        "times": [1,2,3,4,5,6],
        "values": [1,2,3,4,5,6]
      },
      "observed": {
        "times": [1,3,5],
        "values": [1,2,3]
      }
    },
    {
      "uid": "J:K",
      "predicted": {
        "times": [1,2,3,4,5,6],
        "values": [1,2,3,4,5,6]
      },
      "observed": {
        "times": [1.5,3.5,5.5],
        "values": [1,2,3]
      }
    }
  ]
}

Response:

{
  "status": "success",
  "result": {
    "measures": [
      {
        "error_ind": [ 0, 1, 1, 2, 2, 3 ],
        "uid": "J:I",
        "error_total": 19
      },
      {
        "error_ind": [ 0, 1, 2 ],
        "uid": "J:J",
        "error_total": 5
      },
      {
        "error_ind": [ 0.5, 1.5, 2.5 ],
        "uid": "J:K",
        "error_total": 8.75
      }
    ],
    "error_total": 32.75
  }
}

PrTNet Gromet Specification

PrTNet Gromet is a JSON based representation of stochastic Petri nets. Abstractly, a stochastic Petri net is a collection of state variables, and a collection of transitions, which specify how the state variables may change. Each state variable has an initial condition, and the format also supports parameterized Petri nets, used to describe a family of related Petri nets.

The specification uses the following concepts:

  • junctions are used to represent the states of the Petri Net

  • boxes are used to group conceptually related entities; in particular the entire model is a box containg the junctions for the state variables, and boxes for the transitions

  • ports are used to mark inputs or outputs of boxes; data only flows in and out of boxes through ports

  • wires are used to specify how data flows around the system; wires may connect two ports, or a port and a junction:

    • a wire that flows into a junction indicates setting the value of a state variable
    • a wire flowing out of a junction indicates getting the value of a state variable

Top Level Object

A PrTNet Gromet is JSON object with the following form:

PRTNET :=
  { "syntax"    = "Gromet"
  , "type"      = "PrTNet"
  , "name"      = STRING
  , "metadata"  = null          // XXX: Format to be determined
  , "uid"       = STRING
  , "root"      = BOX_ID        // The top-level box for the model
  , "ports"     = [ PORT ]
  , "wires"     = [ WIRE ]
  , "junctions" = [ JUNCTION ]
  , "boxes"     = [ BOX ]
  }

Unique Identifiers

The specifications uses various forms of unique identifiers, which are all strings, but we give them explicit names to indicate what entities they identify.

BOX_ID      := STRING
PORT_ID     := STRING
WIRE_ID     := STRING
JUNCTION_ID := STRING

Note that these identifiers are unique for a given PrTNet object, but are not globally unique.

Value Types

Most entities also contain a field indicating its type, which may be one of the following:

VALUE_TYPE :=
    "Real"                // The type of real numbers
  | "Bool"                // The type of booleans

Junctions

Junctions are used to represent the states of the Petri Net. They will only appear in the top-level box for the model. Each junction will have the following connections:

  • A wire from each event box that may modify the state to the junction
  • A wire from an expression box to the junction, specifying the initial state of the variable
  • A wire from the junction to each event box that needs to use the value of the variable.
JUNCTION :=
  { "syntax"     = "Junction"
  , "uid"        = JUNCTION_ID
  , "type"       = "State"
  , "value_type" = VALUE_TYPE
  }

Wires

Wires are used to specify how data flows around the model.

WIRE :=
  { "syntax"      = "Wire"
  , "uid"         = WIRE_ID
  , "type"        = "Directed"
  , "value_type"  = VALUE_TYPE
  , "metadata"    = null                     // XXX
  , "src"         = PORT_ID | JUNCTION_ID
  , "tgt"         = PORT_ID | JUNCTION_ID
  }

Ports

Ports are used to specify inputs and outputs of a box. Input ports are of type "Input" while output ports are of type "Output". An exception to this is that the ports for the outermost model box are of type "Parameter".

PORT :=
  { "syntax"     = "Port"
  , "type"       = "Parameter" | "Input" | "Output"
  , "name"       = STRING
  , "metadata"   = null        // Format to be determined
  , "value_type" = VALUE_TYPE
  , "uid"        = PORT_ID
  , "box"        = BOX_ID      // Owner of the port
  }

Boxes

Boxes are a generic components used to group related entities. There are two flavors of boxes:

  • relation boxes are used for grouping, and may contain other boxes
  • expression boxes contain a tree describing a mathematical expression
BOX := REL_BOX | EXPR_BOX

Relation Boxes

Relation boxes have the following format:

REL_BOX :=
  { "syntax"    = "Relation"
  , "type"      = "PrTNet" | "Event" | "Enable" | "Rate" | "Effect"
  , "uid"       = BOX_ID
  , "name"      = STRING
  , "wires"     = [ WIRE_ID ]      // Wires contained in this box
  , "boxes"     = [ BOX_ID ]       // Nested boxes
  , "ports"     = [ PORT_ID ]      // Ports for the box
  , "junctions" = [ JUNCTION_ID ]  // Nested junctions
  }

Relation boxes are nested as follows:

  • The only box of type "PrTNet" is the outermost box containing the whole model

  • The "PrTNet" box may contain only "Event" boxes and expression boxes; The expression boxes at this level are used for the inital values of the state variables, as well as to name expressions that may be used in multiple places in the model

  • An "Event" box is going to have exactly 3 nested boxes:

    • One of type "Enable"
    • One of type "Rate"
    • One of type "Effect"
  • A "Enable" box contains a single expression box, describing the enabling condition for the given event

  • A "Rate" box contains a single expression box, describing the rate at which this event may occur

  • A "Effect" box contains a collection of expression boxes, one for each variable that may be affected by the event.

Only "Event" and "Effect" boxes have output ports, which are used to show how state variables are affected by events.

Expression Boxes

Expression boxes contain a mathematical expression. Some have an output port, which is used to indicate where the expression is used. Others (e.g. in "Enable" and in "Rate") do not have an output port as the expession is only part of the specification.

EXPR_BOX :=
  { "syntax"    = "Expression"
  , "uid"       = BOX_ID
  , "name"      = STRING
  , "tree"      = EXPR             // Exp
  , "ports"     = [ PORT_ID ]      // Ports for the box
  , "wires"     = [ ]
  , "boxes"     = [ ]
  , "junctions" = [ ]
  }

Mathematical expressions are encoded as follows:

EXPR := LIT_EXPR      // A literal
      | PORT_ID       // Link to a port
      | CALL_EXPR     // Use of an operator

LIT_EXPR :=
  { "syntax"    = "Literal"
  , "type"      = VALUE_TYPE
  , "value"     = { "syntax" = "Val"
                  , "val"    = STRING          // Value for the literal
                  }
  , "metadata"  = null            // Format to be determined
  }

CALL_EXPR :=
  { "syntax"  = "Expr"
  , "call"    = OPERATOR
  , "args"    = [ EXPR ]
  }

OPERATOR :=
  { "syntax" = "RefOp"
  , "name"   = "not" | "exp" | "log"
             | "+" | "-" | "*" | "/"
             | "lt" | "leq" | "=="
             | "and" | "or"
             | "if"
  }

Example

The following picture is a visualization of a PrTNet document. The ports at the top part of box are input ports, while the ports at the bottom are output ports.

Example

Milestones

M1B

Galois

Initial integration plan

Uncharted

Initial integration plan

M2B

Galois

Initial Report of AMIDOL as a Service with ASKE ecosystem

Uncharted

Uncharted initial release of codebase

M3B

Galois

Galois initial code release

Uncharted

Uncharted has updated their code repository