5. Evaluating Decision Models
As described in section 4, Decision Models can be evaluated. That is, when the input elements—the Actions and the Externals—are set to specific values, the corresponding values of the Outcomes can be determined by evaluating the equations in the chain of dependencies from the inputs to the Outcomes. The API call to evaluate (or execute) a Decision Model is:
POST /evaluate/{id}
where id is the ID of the Decision Model to be evaluated. The details of the request body are described in the section entitled Using the evaluate API call, below.
Execution Processors in World Modeler Server
In World Modeler Server a Decision Models is evaluated by a Processor. When the World Modeler API receives a request to evaluate a given Decision Model for the first time, it creates a Processor instance that is then associated with the Decision Model for the lifetime of Processor; each Processor only processes a single Decision Model. If the Decision Model is changed while it is attached to a Processor, the Processor is discarded and a new Processor instance is created and attached to the updated Decision Model.
As with all other objects in World Modeler, a Processor is identified by its ID, a GUID that will not change for the life of the Processor instance. While the mapping between the Processor and the Decision Model to which it is attached is immutable (that is, a single processor will always evaluate one and only one Decision Model), multiple processors can be attached to a single Decision Models in some circumstances. So the relationship between Decision Models and Processors is one-to-many.
The reason Processors are immutably attached to their associated Decision Model is that when it is initialized, the Processor compiles the Decision Model into a binary representation which is then stored within the Processor, and executed when the Decision Model is to be evaluated. While the initialization process is computationally expensive, once the Decision Model has been loaded, parsed and compiled, execution of the compiled code is highly efficient. Therefore, the lifecycle of a Processor begins with initializing the Processor at the time is created, and then saving the initialized processor, including its copy of the compiled Decision Model, in a cache so it is available for future execution requests without having to re-run the initialization process. The life-cyle of a Processor from creation to evaluating its decision model is shown below.
The Processor ID
The World Modeler Server API’s evaluate operation is the way a Processor is invoked to execute a Decision Model. An important concept that is critical to using the Processor caching mechanism described above is the ProcessorID. When a Processor is created and initialized, it is given a ProcessorID which, like all IDs in the World Modeler API, is a UUID string. Use of the ProcessorID at different times of the Processor and Decision Model lifecycle is described in the table below.
Lifecycle Event | Processor Actions |
First time the evaluate operation is called for a Decision Model |
The ProcessorID is set to null. This triggers the initialization process shown in the above diagram, which is necessary to create and configure the Processor the first time it is used, but only the first time. When a call to evaluate completes for which a null ProcessorID was passed in the request body, the body of the response will contain the ProcessorID that was assigned to the new processor. The new ProcessorID makes the initialized Processor retrievable from the cache. It is important the clients of the API retain the processorID value so that the cached Processor can be used in future calls to evaluate. |
Subsequent calls to evaluate for the same Decision Model | In subsequent calls to evaluate, the processorID returned by the initial call should be set in the requerst body. When the processorID is not null, instead of a new Processor being created and initialized, the existing one with the specified processorID will be retrieved from the cache and used to evaluate the Decision Model with arguments as specified in the request body (see below). |
- Each cached Processor retains the state of the model after completion of the most recent call to evaluate. Therefore model values do not need to be re-initialized after each call to evaluate. Each call to evaluate only needs to specify the changes to be made to the model’s inputs since the previous call.
- At any stage, calling evaluate with processorID = null will invalidate the current Processor and cause a new Processor instance to be created and initialized.
- Re-initializing the Processor will restore the model to its default state and previously calculated values will be reset.
Will a cached Processor always be available in the future?
No. There are two reasons an existing cached processor may "disappear":
- The cache timeout expires. This set in the instance configuration of the World Modeler Server but is typically set to several hours or longer.
- The Decision Model associated with the cached Processor is changed. In this situation, all cached Processors associated with the model will automatically be discarded.
Handling status code 410 (Gone)
If the ID of a Processor that was once available in the cache, but is no longer available, is used in a call to evaluate, the status code 410 (Gone) is returned. The reason the Processor has been removed from the cache is also returned in the message field of the RESTResponse object in the response body (see Returned data and the RESTResponse object in section 2). If a 410 status code is returned as the response to an evaluate request, a new request should be sent to the API to invoke the evaluate operation with processID = null and the normal procedure followed after that. Note that the cached state of the model after the most recent call to evaluate will have been lost and the new processor instance will initialize all model elements to their default or initial values.
Using the evaluate API call
The body of the request to invoke the evaluate operation must contain a JSON object, formatted as shown below
URL: https://host.domain/evaluate/{id}
Method: POST
Body:
{
"processorID": "string", // or null,
"returnElements": ["string","string",...],
"arguments": {
"argName1":argValue1,
"argName2":argValue2,
// ... etc.
},
"saveAs": "name", // or null,
"summary": "short summary string", //or null,
"documentation": "longer documentation string", // or null,
"documentationMIMEType": "MIME type of the documentation string", // or null,
"userData": "string" // or null
}
URL Arguments
id | The ID of the Decision Model to be evaluated. |
Request body JSON
processorID | The ID of a processor which has been created by a previous call to evaluate and is still valid. If this is the first time evaluate is being called, processorID should be null, or an empty string and the new processor ID will be returned in the response if the call succeeded. See the section entitled The Processor ID, above. Note that the processorID specified must be associated with the Decision Model whose ID is specified in the id URL argument. | ||||||
returnElements |
An array of strings, each of which is the
a. ID, b. FullyQualifiedName, or c. Name of a Decision Model Element in the Decision Model whose ID is specified in the id URL argument. Note that the search for matching elements is performed in the order specified above. The purpose of this is to allow the caller to limit the data that is returned when the processor evaluates the model to only those elements that the caller is interested in. This improves efficiency and reduces network traffic when large models are evaluated. The following values may be specified
|
||||||
arguments |
A JSON object containing name = value pairs, where each name identifies an element in the Decision Model and instructs the processor to set the specified element to the specified value before evaluating the model. Each model element name may be specified either by its Fully Qualified Name or its Name. The value must satisfy the following:
|
||||||
saveAs | If the inputs and results of the evaluation are to be saved, then this argument specifies the name used to refer to the saved evaluation. If this argument is null, then the evaluation will not be saved. | ||||||
summary |
May be null.
If the saveAs argument is not null, then this argument allows a short summary string to be included in the record of the saved evaluation. If saveAs is null, then this argument is ignored. |
||||||
documentation |
May be null.
If the saveAs argument is not null, then this argument allows a longer documentation string to be included in the record of the saved evaluation. The MIME type of the string must be specified in the documentationMIMEType argument. |
||||||
documentationMIMEType | If both the saveAs argument and the documentation argument are not null, then this argument must be set to the string identifying the MIME type of text in the documentation argument. If either saveAs or documentation are null, then this argument is ignored. | ||||||
userData | An optional, user-defined text string that can be passed with the call. If defined, the string will be returned in the response to this call. This can be used for responses to requests, for example to sort the sequence of returned responses so it matches the order in which the requests were made. |
Response body
Upon success, the body of the response will contain a RESTResponse JSON object whose value field contains the result of the evaluation, similar to that shown below.
{ "status": "Success",
"value": {
"argument": {
"value": {},
"type": "DIObject"
},
"result": {
"value": {
"MarketSize": {
"type": "DINumber",
"value": 1000000
},
"UnitsSold": {
"type": "DINumber",
"value": 264239.1233933647
},
"UnitCost": {
"type": "DIString",
"value": "{}"
},
"Revenue": {
"type": "DINumber",
"value": 1200000
},
"Profit": {
"type": "DINumber",
"value": 1200000
},
"DemandCurve": {
"type": "DINumber",
"value": 0.2642391233933647
},
"Price": {
"type": "DINumber",
"value": 10
},
"ProductionRun": {
"type": "DINumber",
"value": 120000
}
},
"type": "DIObject"
},
"properties": {
"userData": "string"
},
"processorID": "f8fdbdd9-d93d-490d-a222-5502fce57d1a",
"decisionModelID": "6027bcb9-553d-4625-bdbf-01307132e2de"
},
"message": null,
"requestTime": "0001-01-01T00:00:00",
"duration": "00:00:00",
"url": "https://hostname.domain/evaluate/6027bcb9-553d-4625-bdbf-01307132e2de"
}
Managing saved Evaluations
TBD