Initializing help system before first use

Xpress Mosel MATLAB Interface

Topics covered in this chapter:

Overview

The Xpress MATLAB interface is a tool that makes Xpress optimization algorithms available directly from within the MATLAB environment, enabling users to easily define mathematical programming models and solve them with Xpress from within the MATLAB environment.

The interface for Mosel provides functions for running Mosel programs from within MATLAB and exchanging data between the Mosel models and the MATLAB environment.

Configuring MATLAB for the Xpress Mosel interface

Please refer to the "Xpress Installation and Licensing User Guide" for instructions on Xpress installation. The MATLAB interface does not require a separate software license.

The Xpress Mosel MATLAB Interface includes a function (moselexec) to run Mosel programs, a Mosel I/O Driver to exchange data with the MATLAB environment and support for using the Java Mosel classes from MATLAB.

In order to make the new functionality available in MATLAB, the Xpress matlab directory must be added to the MATLAB search path. This can be done either using the graphical 'Set Path' dialog box or the command line. Note that this step is the same as described for the Xpress Optimizer MATLAB interface and needs to be carried only once.

For the Java Mosel classes, there are other two search paths that need to be updated: the MATLAB Java classpath and the MATLAB Java libpath.

Setting the MATLAB search path

The MATLAB search path can be set using the graphical interface as follows.

From the main MATLAB window, click on File » Set Path..., then on the 'Add Folder' button and select the matlab subfolder of your Xpress installation folder (on Windows platforms typically 'c:\xpressmp\matlab').

You should make this change permanent by clicking on the 'Save' button.

It is also possible to set the search path using the MATLAB command line, with the following instructions:

>> addpath(fullfile(getenv('XPRESSDIR'),'/matlab'))

and make this permanent with the command

>> savepath

The above command uses the XPRESSDIR environment variable to locate your Xpress installation directory; alternatively you can also specify the path directly, as in:

>> addpath 'c:\xpressmp\matlab'

(assuming you installed Xpress on 'c:\xpressmp')

Setting the MATLAB Java class path

In order to use the Java Mosel interface in MATLAB you need to add the Java Mosel library to the MATLAB Java classpath. The library consists of a Java Archive (JAR) file located under the Xpress installation directory, in the lib subdirectory. MATLAB supports both a static path and a dynamic path and you can add the Mosel JAR to either one; please refer to the MATLAB documentation, section 'Bringing Java Classes into MATLAB Workspace' for more information.

In the following, we show how to add the JAR to the static path. MATLAB loads the static path from an ASCII file named javaclasspath.txt in your preferences folder. To view the location of the preferences folder, type prefdir in MATLAB. Each line in this file is the path of a folder or a jar file. You can open this file in the MATLAB editor with the following command

>> edit(fullfile(prefdir, '/javaclasspath.txt'))

then you should add the following line to this file:

C:\xpressmp\lib\xprm.jar

(assuming you installed Xpress on 'c:\xpressmp')

Then save the file and restart MATLAB for these changes to take effect.

Alternatively, you can run the following small MATLAB script (that you can copy & paste to the MATLAB console) to automate the above operation:

fjcp = fopen(fullfile(prefdir,'/javaclasspath.txt'), 'at');
fprintf(fjcp,'\n%s\n',fullfile(getenv('XPRESSDIR'),'/lib/xprm.jar'));
fclose(fjcp);

Again, you need to restart MATLAB for these changes to take effect.

Setting the MATLAB Java library path

In order to use the Java Mosel interface in MATLAB you also need to add the Mosel native library to the MATLAB Java librarypath. The native library consists of some dynamically linked files located under the Xpress installation directory, in the bin subdirectory on Windows and in the lib subdirectory on Linux. MATLAB loads the library search path from an ASCII file named javalibrarypath.txt in your preferences folder. To view the location of the preferences folder, type prefdir in MATLAB. Each line in this file is the path of a folder. You can open this file in the MATLAB editor with the following command

>> edit(fullfile(prefdir, '/javalibrarypath.txt'))

then you should add the following line to this file:

C:\xpressmp\bin

(assuming you installed Xpress for Windows on 'c:\xpressmp')

Then save the file and restart MATLAB for these changes to take effect.

Alternatively you can run the following small MATLAB script (that you can copy & paste to the MATLAB console) to automate the above operation:

fjlp = fopen(fullfile(prefdir,'/javalibrarypath.txt'), 'at');
if isunix, libdir='/lib'; else libdir='/bin'; end
fprintf(fjlp,'\n%s\n',fullfile(getenv('XPRESSDIR'),libdir));
fclose(fjlp);

Again, you need to restart MATLAB for these changes to take effect.

Verifying if the Xpress Mosel interface works

You can verify that the Xpress Mosel MATLAB interface is working properly by executing the command

>> moselexec -v

inside MATLAB. In case everything is fine you should see something like:

XPRESS Mosel Matlab Interface function version x.x.x

Similarly, for the Java interface, the command

>> com.dashoptimization.XPRM().getVersion

should print something like:

ans =
3.5.3

Running Mosel models

The moselexec function

The simplest way to run a Mosel program from MATLAB is using the moselexec function, as in:

>> moselexec burglar.mos

This compiles and runs the Mosel program burglar.mos located in the current folder (or prints an error message if the file cannot be found). You can of course specify a full path as in

>> moselexec C:/xpressmp/examples/mosel/Modeling/burglar.mos

or use the XPRESSDIR environment variable to point to the Xpress installation folder:

>> moselexec(fullfile(getenv('XPRESSDIR'),'/examples/mosel/Modeling/burglar.mos'))

By specifying the optional output arguments retcode and exitcode, the moselexec function can also return the compilation and execution result code and the program exit status, or both, for example solving this tiny example example_m1.mos:

model "example_m1"
exit(10)
end-model

would yield

>> [retcode, exitcode]=moselexec('example_m1.mos')
retcode =
           0
exitcode =
          10

where the value zero for retcode means that the program has run without errors, and exitcode has the value specified in the model.

Please refer to moselexec in the reference section for further details.

The I/O driver

The Mosel I/O driver for MATLAB makes it possible to exchange data between Mosel programs and the MATLAB workspace. This driver supports reading a MATLAB value as a Mosel generalized file stream, and importing and exporting data from and to MATLAB in Mosel initializations from and initializations to blocks.

Note that this driver is available only when executing Mosel programs from within the MATLAB environment.

Extended file names

Mosel uses an extend file name format to represent 'files' that can be accessed through specialized I/O drivers. The format for the MATLAB driver is

matlab.mws:expression

where matlab is the name of the Mosel module, mws is the name of the I/O driver name (MATLAB WorkSpace) and expression can either be a current variable name of the caller workspace, or any MATLAB expression returning a single value. In the case of a MATLAB expression, the latter will be evaluated in the caller workspace at the time of file opening. For example, the following Mosel program

model "example_m2"
 uses "mmsystem";
 fcopy("matlab.mws:message", "")
 writeln
end-model

would read the MATLAB variable message and print it to the MATLAB console. You can test it with the following MATLAB commands

>> message='Hello, World!';
>> moselexec('example_m2.mos')
Hello, World!

String handling

When reading a string variable, the I/O driver automatically converts it from MATLAB native 16-bit multibyte Unicode characters to the 8-bit ASCII format used by Mosel (if you prefer to convert the string using a different encoding, you can explicitly convert it to a raw byte stream beforehand with the MATLAB function unicode2native). If the source string is a string array that contains several rows, then these are copied, one column at a time, into a single string. Finally, if the source variable is a cell array containing strings, all strings are read successively with newline characters added at the end of each one.

It is thus possible to use a MATLAB cell array to store a Mosel program, one line per cell, and then execute it without using external files, as in the following example.

>> mos={
'model "example_m3"        '
' uses "mmxprs", "mmnl";   '
' declarations             '
'  a:mpvar                 '
' end-declarations         '
' minimize(a*a-5*a+10)     '
' writeln(getobjval)       '
'end-model                 '
};
>> moselexec('matlab.mws:mos')
3.75

Initializations from blocks

The matlab.mws I/O driver can be used in Mosel initialization blocks to read MATLAB values and set MATLAB variables. In this case, the filename should just be "matlab.mws:", without any expression, and the expression can eventually be specified as the label associated to the identifier being initialized.

Consider the following Mosel program

model "example_m4"
 declarations
  answer: integer
  foo: real
  var: real
  today: string
  i: range
  Data: array(i) of real
 end-declarations

 initializations from "matlab.mws:"
  answer as "42"
  foo
  var as "bar"
  today as "date"
  Data as "sum(magic(foo*bar))"
 end-initializations

 writeln("answer to ultimate question: ", answer)
 writeln("foo: ", foo)
 writeln("bar: ", var)
 writeln("today: ", today)
 writeln("data: ", Data)
end-model

and its execution from MATLAB

>> foo=pi;
>> bar=exp(1);
>> moselexec('example_m4.mos');
answer to ultimate question: 42
foo: 3.14159
bar: 2.71828
today: 01-May-2014
data: [260,260,260,260,260,260,260,260]

Here, the expression used to initialize the variable answer is "42", that is, a literal value. Variable foo doesn't specify an initialization label, so the default is used—the default label is the identifier itself and thus the MATLAB variable foo is read. The label for variable var explicitly says to read the MATLAB variable bar. The expression used to initialize today is the MATLAB function date which returns a string with today's date. And finally, Data is an array read from a MATLAB expression that builds a magic square of size 8 and calculates the sums of values in every column (which should be all equal in magic squares, as shown in the output).

MATLAB sparse matrices can be read into dynamic arrays to set only non-zero elements:

>> mos={
'model "example_m5"                  '
' declarations                       '
'  I,J: range                        '
'  Sparse: dynamic array(I,J) of real'
' end-declarations                   '
' initializations from "matlab.mws:" '
'  Sparse as "sprand(4,4,.5)"        '
' end-initializations                '
' writeln("sparse is: ", Sparse)     '
' writeln("row indices: ", I)        '
' writeln("col indices: ", J)        '
'end-model                           '
};
>> moselexec('matlab.mws:mos');
sparse is: [(1,3,0.24285),(2,1,0.917424),(2,2,0.269062),(2,3,0.7655),(4,1,0.188662)...
row indices: 1..4
col indices: 1..3

In the above example, Sparse is a 2-dimensional dynamic array containing only 6 values after initialization from a MATLAB 4 4 sparse random matrix, and index set J (in this execution) contains only the values 1, 2, and 3 as the matrix happened to have all zeros in column 4. Note also that array indices start from 1 which is the MATLAB convention.

Initializations to blocks

Mosel data can be exported to MATLAB using initializations to blocks. The filename should just be "matlab.mws:" in this case too, and labels can be used to specify MATLAB variable names to export to (if no label is specified, the name of the identifier is used). In MATLAB, these variables are set in the caller workspace, eventually overwriting their previous value.

The following example shows how to export a scalar value (simplexiter), the optimal objective and solution values into MATLAB variables. The model, foliomat.mos, is a modified version of the portfolio optimization example from the "Getting Started with Xpress" guide.

model "Portfolio optimization with LP - MATLAB"
 uses "mmxprs"

 declarations
  SHARES: range
  RISK: set of integer
  NA: set of integer
  RET: array(SHARES) of real
  frac: array(SHARES) of mpvar
  simplexiter: integer
 end-declarations

 initializations from "matlab.mws:"
   RISK NA RET
 end-initializations

 Return:= sum(s in SHARES) RET(s)*frac(s)
 sum(s in RISK) frac(s) <= 1/3
 sum(s in NA) frac(s) >= 0.5
 sum(s in SHARES) frac(s) = 1
 forall(s in SHARES) frac(s) <= 0.3
 maximize(Return)
 simplexiter:=getparam("XPRS_simplexiter")

 initializations to "matlab.mws:"
  simplexiter
  evaluation of getobjval as "objval"
  evaluation of array(s in SHARES) frac(s).sol as "frac"
 end-initializations
 exit(getprobstat)

end-model

This can be executed from MATLAB after defining RISK, NA and RET input data and results will be available as MATLAB variables as shown below.

>> RET  = [5 17 26 12 8 9 7 6 31 21];
>> RISK = [2 3 4 9 10];
>> NA   = [1 2 3 4];
>> [r,e]=moselexec('foliolp_mat.mos');
>> objval
objval =
   14.0667
>> frac'
ans =
    0.3000         0    0.2000         0    0.0667    0.3000 ...

Using MATLAB functions in Mosel

We have already seen how MATLAB functions can be called in initializations from blocks (including user-defined functions). Since these blocks can be used at arbitrary positions in Mosel programs, it is possible to combine this with initializations to blocks to load some data into MATLAB, evaluate a MATLAB function on this data and retrieve results back into Mosel. The following example shows a fibonacci function implemented in MATLAB and a Mosel program that also defines a fibonacci function that just calls the MATLAB one (note however that this is neither reentrant nor thread-safe).

MATLAB code (fibonacci.m):

function f=fibonacci(n)
  if n<2, f=n; return, end
  s=[0 1];
  for i=2:n, s=[s(2) sum(s)]; end
  f=s(2);
end

Mosel model fib-relay.mos:

model "fib_relay"
 function fibonacci(i:integer):integer
   initializations to "matlab.mws:"
     i
   end-initializations

   initializations from "matlab.mws:"
     returned as "fibonacci(i)"
   end-initializations
 end-function

 forall(i in 1..10)
   writeln("fibonacci(", i, ")=", fibonacci(i))
end-model

Example run:

>> moselexec('fib_relay.mos');
fibonacci(1)=1
fibonacci(2)=1
fibonacci(3)=2
fibonacci(4)=3
fibonacci(5)=5
...

Supported types

The matlab.mws driver supports all basic types of Mosel (boolean, integer, real, string) and the structures set, range, list and array of basic types. On the MATLAB side, the supported types are n-dimensional arrays and cell arrays of the basic numeric, logical or char classes (including sparse matrices). Only the real part of arrays is always used. Since MATLAB uses 1-based integer indices, Mosel arrays must also use this same convention when imported/exported to MATLAB. If necessary, data is silently casted to the appropriate type without any warning in case of truncation or loss of precision (for example when reading a Mosel integer from a fractional MATLAB double value).

Using the Java Mosel interface

Overview

The Java Mosel interface offers a more advanced control and interaction with Mosel than what is possible with the simple moselexec function. In fact, the Java Mosel interface enables the user to:

  • compile source model files into binary model (bim) files
  • load and unload bim files handling several models at a time
  • execute models
  • access the Mosel internal database through the Post Processing Interface
  • manage the dynamic shared objects used by Mosel

We will show some of these functionalities in the following examples, however please refer to:

  • the "Xpress Mosel User Guide", Chapter 14, for a brief introduction to the Java interface;
  • the "Xpress Mosel Library Reference Manual" in JavaDoc format, for the full reference documentation of this interface;
  • MATLAB Documentation - Advanced Software Development - Call Java Libraries, for details on using Java from MATLAB.

Furthermore, the I/O driver described in the previous section can also be used in this context.

Compiling and executing a model

With Java, Mosel is initialized by creating a new instance of class XPRM. In MATLAB you can either use the fully qualified class name (including the package name) as in

>> mosel=com.dashoptimization.XPRM;

or import the package and then use class names without the package name:

>> import com.dashoptimization.*;
>> mosel=XPRM;

The standard compile/load/run sequence becomes

>> mosel=com.dashoptimization.XPRM;
>> mosel.compile('burglar2.mos');
>> mod=mosel.loadModel('burglar2.bim');
>> mod.run;
>> mod.getResult;

If the model execution is embedded in a larger application it may be useful to release the resources allocated by a model after its execution. This can be done through standard finalization + garbage collection functionalities, by calling the finalize method on the model:

>> mod.finalize

The mosel object can be released in the same way (mosel.finalize).

Accessing arrays

In general, Mosel entities such as scalar variables, sets, etc. can be queried through the findIdentifier method and retrieved in the same way as described in the "Xpress Mosel User Guide". However, when calling Java from MATLAB, it is not possible to pass an array of a Java native type to a function and receive back in MATLAB the array as modified by the function. This would be the case, for instance, when using the nextIndex or nextTEindex methods on a Mosel array. Consider the following example that defines a (sparse) array VALUE with two indices of type string:

model example_m6
 declarations
  CITIES = {"london", "paris", "madrid", "rome", "florence"}
  ZONES = {"north", "south", "east", "west"}
  VALUE: dynamic array(CITIES,ZONES) of real
 end-declarations

 VALUE("london", "east")  := 1
 VALUE("rome",   "west")  := 2
 VALUE("paris",  "south") := 3
 VALUE("madrid", "east")  := 4
end-model

The array VALUE can be retrieved into MATLAB with the following code (example_m6.m):

value = mod.findIdentifier('VALUE');
value_iter = value.indices(true);
sets = value.getIndexSets();
while value_iter.hasNext
  indices = value_iter.next;
  fprintf(1, 'VALUE ( ');
  for i=1:size(indices,1)
    fprintf(1, '%s ', char(sets(i).get(indices(i))));
  end
  fprintf(1, ') = %g\n', value.getAsReal(indices));
end

Executing this script would print the Mosel array as shown below:

>> example_m6
VALUE ( london east ) = 1
VALUE ( madrid east ) = 4
VALUE ( paris south ) = 3
VALUE ( rome west ) = 2

In the above example we use the iterator value_iter to loop over all valued elements of the array; at each iteration we retrieve the actual numerical indices (indices) of the current element, their corresponding values (sets(i).get(...)), and the value of the current element (value.getAsReal(indices)).

Please note that the following alternative approach that uses XPRMArray.nextTEIndex(), would not work correctly in MATLAB as the call to value.nextTEIndex(indices) cannot update the indices array as in pure Java.

indices=value.getFirstTEIndex;
...
while value.nextTEIndex(indices)
 ...
end

Examples

The first example, ugsol.m is a variation of the program ugsol.java described in the "Xpress Mosel User Guide". Here the Mosel program has been embedded in a MATLAB script: the model is the same but problem data is read from MATLAB variables and the solution is exported to MATLAB. The MATLAB script compiles the Mosel program, runs it, checks the solution status and prints the solution.

mos={
'model Burglar_m                                                         '
' uses "mmxprs"                                                          '
' declarations                                                           '
'  WTMAX = 102                    ! Maximum weight allowed               '
'  ITEMS: range                                                          '
'  VALUE: array(ITEMS) of real    ! Value of items                       '
'  WEIGHT: array(ITEMS) of real   ! Weight of items                      '
'  take: array(ITEMS) of mpvar    ! 1 if we take item i; 0 otherwise     '
' end-declarations                                                       '
'                                                                        '
' initializations from "matlab.mws:"                                     '
'  VALUE                                                                 '
'  WEIGHT                                                                '
' end-initializations                                                    '
'                                                                        '
' MaxVal:= sum(i in ITEMS) VALUE(i)*take(i)  ! Objective: max total value'
' sum(i in ITEMS) WEIGHT(i)*take(i) <= WTMAX ! Weight restriction        '
' forall(i in ITEMS) take(i) is_binary       ! All variables are 0/1     '
' maximize(MaxVal)                           ! Solve the MIP-problem     '
'                                                                        '
' initializations to "matlab.mws:"                                       '
'  evaluation of array(i in ITEMS) take(i).sol as "TAKE"                 '
' end-initializations                                                    '
'end-model                                                               '
};

ITEMS ={'camera' 'necklace' 'vase' 'picture' 'tv' 'video' 'chest' 'brick'};
VALUE =[ 15       100        90     60        40   15      10      1];
WEIGHT=[ 2        20         20     30        40   30      60      10];

mosel=com.dashoptimization.XPRM; % Initialize Mosel
mosel.compile('', 'matlab.mws:mos', 'burglar_m.bim');
mod=mosel.loadModel('burglar_m.bim');
mod.run;
if mod.getProblemStatus~=mod.PB_OPTIMAL, return, end
fprintf(1,'Objective value: %g\n', mod.getObjectiveValue); % show objective
table(ITEMS',logical(TAKE),VALUE','VariableNames',{'Item' 'Take' 'Value'})
fprintf(1,'Calculated objective: %g\n', VALUE*TAKE); % verify sol
mod.finalize

The second example is a variation of the portfolio optimization from the Getting Started with Xpress guide. The Mosel program, foliomat2.mos, is almost identical to the foliodat.mos example, modified only to use integer indices instead of string indices, and to read input from MATLAB and write results to MATLAB.

model "Portfolio optimization with LP"
 uses "mmxprs"                       ! Use Xpress Optimizer

 parameters
  DATAFILE= "matlab.mws:"            ! File with problem data
  MAXRISK = 1/3                      ! Max. investment into high-risk values
  MAXVAL = 0.3                       ! Max. investment per share
  MINAM = 0.5                        ! Min. investment into N.-American values
 end-parameters

 writeln("Solving for MAXRISK: ", MAXRISK)
 declarations
  SHARES: range                      ! Set of shares
  NAMES: array(SHARES) of string     ! Names of the shares
  RISK: set of integer               ! Set of high-risk values among shares
  NA: set of integer                 ! Set of shares issued in N.-America
  RET: array(SHARES) of real         ! Estimated return in investment
 end-declarations

 initializations from DATAFILE
  NAMES RISK RET NA
 end-initializations

 declarations
  frac: array(SHARES) of mpvar       ! Fraction of capital used per share
 end-declarations

! Objective: total return
 Return:= sum(s in SHARES) RET(s)*frac(s)

! Limit the percentage of high-risk values
 sum(s in RISK) frac(s) <= MAXRISK

! Minimum amount of North-American values
 sum(s in NA) frac(s) >= MINAM

! Spend all the capital
 sum(s in SHARES) frac(s) = 1

! Upper bounds on the investment per share
 forall(s in SHARES) frac(s) <= MAXVAL

! Solve the problem
 maximize(Return)

! Solution printing to a file
 writeln("Total return: ", getobjval)
 forall(s in SHARES)
  writeln(strfmt(NAMES(s),-12), ": \t", strfmt(getsol(frac(s))*100,5,2), "%")

 initializations to "matlab.mws:"
  evaluation of getobjval as "objval"
  evaluation of getprobstat=XPRS_OPT as "optsol"
  evaluation of array(s in SHARES) frac(s).sol as "frac"
 end-initializations

end-model

The following MATLAB script (foliomat2.m) first initializes input data (also deriving integer indices from strings for variables RISK and NA), it then executes the Mosel program for different values of MAXRISK, from 0.1 to 0.9 at 0.1 steps, and finally displays a couple of result tables and charts of share utilization for the different risks.

NAMES  ={'treasury' 'hardware' 'theater' 'telecom' 'brewery' 'highways' 'cars'    'bank'
         'software' 'electronics'};
RET    =[ 5        17    26    12    8    9        7         6           31      21 ];
DEV    =[ 0.1      19    28    22    4    3.5      5         0.5         25      16 ];
COUNTRY={'Canada' 'USA' 'USA' 'USA' 'UK' 'France' 'Germany' 'Luxemburg' 'India' 'Japan'};

RISK_N  ={'hardware' 'theater' 'telecom' 'software' 'electronics'};
NA_N    ={'treasury' 'hardware' 'theater' 'telecom'};

RISK=cellfun(@(n) strmatch(n,NAMES,'exact'), RISK_N); % find indices of high-risk shares
NA  =cellfun(@(n) strmatch(n,NAMES,'exact'), NA_N);   % find indices of N.-American shares

for m=1:9
  moselexec('foliomat2.mos',['MAXRISK=' num2str(m/10)]);
  obj(m)=objval;
  optimal(m)=optsol;
  fracm(m,:)=frac;
end

disp('Results');
disp('Estimated returns:');
disp(table([1:9]'/10,obj','VariableNames',{'MaxRisk' 'Return'}))

disp('Average share utilization:');
disp(table(NAMES',mean(fracm)','VariableNames',{'Share' 'AverageUsage'}))

ribbon(fracm)
title('Share utilization')
set(gca,'XTick',[1:size(fracm,2)])
set(gca,'XTickLabel',NAMES)
set(gca,'YDir','reverse')
set(gca,'YTick',[1:9])
set(gca,'YTickLabel',[1:9]/10)
set(gca,'ZLim',[0,max(reshape(fracm,1,[]))])

Running the script will yield the following results and the graphic in Figure Share utilization.

Results
Estimated returns:
    MaxRisk    Return
    _______    ______
    0.1           0
    0.2          11
    0.3        13.3
    0.4        15.6
    0.5        17.8
    0.6        19.9
    0.7        21.1
    0.8        22.3
    0.9        23.5
Share utilization:
        Share        AverageUsage
    _____________    ____________
    'treasury'        0.16667
    'hardware'       0.055556
    'theater'         0.22222
    'telecom'               0
    'brewery'        0.033333
    'highways'            0.2
    'cars'                  0
    'bank'                  0
    'software'            0.2
    'electronics'    0.011111
foliom.png

Figure 1.1: Share utilization


© 2001-2024 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.