/*******************************************************
Xpress Executor Example Model
=============================
file blendxe.js
```````````````
Demonstrates executing the 'blend3c' model using Xpress Executor
with the supplied input data & displaying the results. This example is written
in JavaScript and intended to be run using node.js.
Local prerequisites:
node.js
npm
Instructions
1) Configure your Xpress Executor component with the blend3c example model
2) Fill in the DMP_* variables with the details of your Xpress Executor component
3) Open a command prompt and type: npm install
4) When that completes, type: node blendxe.js
(c) 2017 Fair Isaac Corporation
author: J. Farmer, Jul. 2017
*******************************************************/
// The REST endpoint of the Xpress Executor DMP component
// ! Obtain this by clicking "View Links" for the Xpress Executor component on the DMP UI
var DMP_XE_REST_ENDPOINT="";
// The client ID of solution containing the Xpress Executor DMP component
// Obtain this through the DMP UI
var DMP_SOLUTION_CLIENT_ID="";
// The secret of the solution containing the Xpress Executor DMP component
// Obtain this through the DMP UI
var DMP_SOLUTION_SECRET="";
// The root DMP manager URL. This will be different depending on which instance of DMP you are using.
var DMP_MANAGER_URL="https://manager-svc.prd-platform.ficoanalyticcloud.com";
// The input file for the remote model
var INPUTFILE="../data/blend.csv";
// Third-party dependency: prequest
// for promise-based HTTP requests
var prequest = require('prequest');
// Third-party dependency: delay
// for promise-based delays
var delay = require('delay');
// Third-party dependency: csv-parse
// for parsing CSV data
// The example model blend3c.mos reads & outputs CSV; this is a feature of this example rather than a requirement
// of Xpress Executor.
var parse = require('csv-parse/lib/sync');
// Standard node.js filesystem module
var fs = require('fs');
// Standard node.js URL handling module
var url = require('url');
// Request an authentication token from DMP
console.log("Requesting authorization token from DMP");
var authorizationToken;
prequest({
method: 'POST',
url: DMP_MANAGER_URL+"/registration/rest/client/token",
body: {
clientId: DMP_SOLUTION_CLIENT_ID,
secret: DMP_SOLUTION_SECRET
}
}).then(function(body) {
// This token can be re-used in subsequent requests, but should be refreshed every half hour
authorizationToken = body;
// Start the execution of the model in our Xpress Executor service
console.log("Initiating model execution");
return prequest({
method: 'POST',
url: DMP_XE_REST_ENDPOINT,
headers: {
"Authorization": 'Bearer '+authorizationToken
},
body: {
// parameters defined in 'parameters' section at the top of blend3c.mos
parameters: {
INPUTFILE: "input",
RESULTFILE: "result"
},
// Use inputText for passing input data as a string, inputBase64 for encoded binary input data
inputText: fs.readFileSync(INPUTFILE,"utf8")
}
});
}).then(function(executionStatus) {
// executionStatus is a standard structure that contains various meta-data about an execution in
// the Xpress Executor service. It also contains relative paths to various REST resources
// relating to this execution - e.g. input, result, status, run log...
// Model will be executing asynchronously; repeatedly wait 1/4 second then re-fetch status until it
// is complete
console.log("Waiting for completion of execution");
function waitForCompletion() {
if (executionStatus.status!=='NOT_COMPLETED' && executionStatus.status!=='NOT_LOADED') {
// Execution has finishd!
return Promise.resolve(executionStatus);
}
else {
// Wait 250ms
return delay(250).then(function() {
// Refresh executionInfo
return prequest({
method: 'GET',
url: url.resolve(DMP_XE_REST_ENDPOINT, executionStatus.statusPath),
headers: {
"Authorization": 'Bearer '+authorizationToken
}
}).then(function(body) {
// Request returns updated executionStatus
executionStatus = body;
return waitForCompletion();
});
});
}
}
return waitForCompletion();
}).then(function(executionStatus) {
// Execution has completed; check that it was successful and display results as appropriate
console.log("Processing model results");
// In event of failure, echo the remote model status, exit code & run log to aid with troubleshooting
if (executionStatus.status!=='OK' || executionStatus.exitCode!==0) {
// Execution failed for some reason
console.log("Execution failed!");
console.log("Execution status: "+executionStatus.status);
console.log("Execution exit code: "+executionStatus.exitCode);
console.log("");
console.log("Execution log:");
// Fetch the remote execution log as it will likely contain error messages from the model
return prequest({
method: 'GET',
url: url.resolve(DMP_XE_REST_ENDPOINT, executionStatus.runLogPath),
headers: {
"Authorization": 'Bearer '+authorizationToken,
"Accept": 'text/plain'
}
}).then(function(runLog) {
console.log(runLog);
return executionStatus;
});
}
else {
// Download results file
return prequest({
method: 'GET',
url: url.resolve(DMP_XE_REST_ENDPOINT, executionStatus.resultPath),
headers: {
"Authorization": 'Bearer '+authorizationToken,
"Accept": 'application/octet-stream'
}
}).then(function(csvResults) {
// The blend3c.mos example downloads its results as a CSV file. Use the NodeJS 'csv' module to parse this.
console.log();
console.log("Results of optimization:");
records = parse(csvResults);
records.forEach(function(record) {
console.log(" use("+record[0]+"): "+record[1]);
});
console.log();
return executionStatus;
});
}
}).then(function(executionStatus) {
// Finally, delete execution from component, to free the resources it holds
console.log("Deleting execution from component");
return prequest({
method: 'DELETE',
url: url.resolve(DMP_XE_REST_ENDPOINT, executionStatus.statusPath),
headers: {
"Authorization": 'Bearer '+authorizationToken
}
});
}).catch(function(err) {
if (err.statusCode) {
console.error("ERROR returned by Xpress Executor service: HTTP status code "+err.statusCode);
}
else {
console.error("ERROR encountered: "+err.message);
}
}); |
(!******************************************************
Mosel User Guide Example Problems
=================================
file blend3c.mos
````````````````
Reading data from an Excel spreadsheet
- using the CSV driver -
(c) 2013 Fair Isaac Corporation
author: S. Heipcke, Jan. 2013
*******************************************************!)
model "Blend 3"
uses "mmxprs", "mmsheet"
parameters
INPUTFILE="../data/blend.csv"
RESULTFILE="result.csv"
end-parameters
declarations
REV = 125 ! Unit revenue of product
MINGRADE = 4 ! Minimum permitted grade of product
MAXGRADE = 5 ! Maximum permitted grade of product
ORES = 1..2 ! Range of ores
COST: array(ORES) of real ! Unit cost of ores
AVAIL: array(ORES) of real ! Availability of ores
GRADE: array(ORES) of real ! Grade of ores (measured per unit of mass)
use: array(ORES) of mpvar ! Quantities of ores used
end-declarations
!*** Read data from spreadsheet blend.csv ***
! Spreadsheet range contains data only (no header line):
initializations from "mmsheet.csv:"+INPUTFILE
[COST,AVAIL,GRADE] as "[B3:E4]" ! or: "[R3C2:R4C5]"
end-initializations
(! Or (spreadsheet range includes a header line as with ODBC):
initializations from "mmsheet.csv:"+INPUTFILE
[COST,AVAIL,GRADE] as "skiph;[B2:E4]"
end-initializations
!)
! Objective: maximize total profit
Profit:= sum(o in ORES) (REV-COST(o))* use(o)
! Lower and upper bounds on ore quality
sum(o in ORES) (GRADE(o)-MINGRADE)*use(o) >= 0
sum(o in ORES) (MAXGRADE-GRADE(o))*use(o) >= 0
! Set upper bounds on variables
forall(o in ORES) use(o) <= AVAIL(o)
maximize(Profit) ! Solve the LP-problem
! Print out the solution
writeln("Solution:\n Objective: ", getobjval)
forall(o in ORES) writeln(" use(" + o + "): ", getsol(use(o)))
! Write solution to CSV file
declarations
solvalues: array(ORES) of real
end-declarations
forall (o in ORES) solvalues(o) := getsol(use(o))
initializations to "mmsheet.csv:"+RESULTFILE
solvalues as "grow;[A1:B1]"
end-initializations
end-model
|