JOM (Java Optimization Modeler)Getting started
Getting startedMy suggestion for getting started with JOM, is:
After doing the steps before, my suggestion for making a program that uses JOM is:
As a tutorial, below we use the example in the home page to illustrate the main steps in solving an optimization problem with JOM.
1. Importing the librariesThe JOM.jar file should be stored in your file system and included in the CLASSPATH. The JAR file contains the following Java packages:
import com.jom.*; 2. Creating the OptimizationProblem ObjectTo be able to define and finally solve an optimization problem, you first have to create an OptimizationProblem object: OptimizationProblem op = new OptimizationProblem();
3. Adding decision variables to the problemThe decision variables in the problem can be added by calling the addDecisionVariable in the OptimizationProblem object. We have to define (i) the name of the decision vairable as it will appear in the expressions, (ii) if it is constrained to be integer or not, (iii) its size, given as array of integer, with one integer per dimension, (iv) the lower and upper bounds to the values of the variables if any. There are several variations for calling the addDecisionVariable method, offering different forms of, for instance, defining the lower and upper bounds to the variables. See the Javadoc for details. In our example, we create a decision variable with name "x", constrained to be integer, of size N x N x N (and thus with three dimensions), with lower and upper bound for all the coordinates of 0 and 1 (then, x is an array of binary variables). The name of the decision variable is case-sensitive op.addDecisionVariable("x", true, new int[] { N , N , N }, 0, 1); Important: JOM uses 0-indexing for the arrays of decision variables and input parameters. Then, the first coordinate in any dimension has index 0, not index 1. In our example, first element in "x" is x(0,0,0) and not x(1,1,1). Last element in each dimension is N-1 and not N. For instance, trying to access x(N,0,0) is an error, since the first coordinate is out of bounds.
4. Setting the values to the input parametersIt is possible to assign arrayed constant values of any dimension to input parameters, to be used later in expressions, calling the setInputParameter methods. When the input parameter appears in an expression, JOM replaces it by its current value. The values of input parameter can be reset at any moment. This permits for instance creating for-loops for adding constraints which are different, since the values of some input parameters are updated inside the loop. In our example, the c input parameter is initialized only once, taking the values from an array of size NxNxN where each coordinate has a random value uniformly distibuted between 0 and 1 (see the com.jom.DoubleMatrixND javadoc for details on how this works). op.setInputParameter("c", new DoubleMatrixND(new int [] { N , N , N} , "random")); Input parameters can also be useful for setting the values of notable constants like i.e. number \( \pi \), as shown in next line of code: op.setInputParameter("pi", 3.141592653589793); 5. Adding the objective functionThe method setObjectiveFunction is used to define the objective function of the problem, and the search direction (minimize or maximize). If this method is called more than once, only the last call is valid. The objective function to the problem is a JOM expression combining input parameters, numerical constants and decision variables using operators and functions. It should be an scalar expression: that is, a function that evaluates in a real number, not in an array of numbers. See the section about JOM expression syntax for details. In our example, the objective is to maximimize the sum of all the values in the "x" decision variable element-by-element multiplied by their associated benefit given by the "c" array. op.setObjectiveFunction("maximize", "sum(x .* c)");
6. Adding the constraintsThe method addConstraint is used to add equality or inequality constraints to the problem. Constraints are defined with strings with the syntax: lhs-expression + symbol + rhs-expression. lhs-expression and rhs-expression are the left-hand-side and right-hand-side expressions of the constraint (using the JOM syntax), and the symbol connector determines the type of constraint:
Note that strict inequalities are not allowed. In general, solvers consider strict inequalities as non-strict inequalities, so we preferred to avoid any confussion prohibiting the < and >. symbols In general, the size of the lhs and rhs expressions in a constraint must be the same. Then, an array of constraints is defined with one line of code, element by element. If one expression (lhs or rhs) is an array, and the other is an scalar expression, again multiple constraints are added, one for each element in the array taking the same scalar expression in the other side of the constraint. For instance, in the following constraint: op.addConstraint(" sum(sum(x,2),1) <= 1");
7. Solving the problemThe method void solve(String solverName, Object... paramValuePairs) is used to call the solver and solve the problem. The solverName String can be "glpk", "ipopt" or "cplex". Note that GPLK and CPLEX can only be used with JOM for linear problems, and IPOPT for non-integer differentiable problems. If this is not fulfiled, JOM detects it and raises an exception. It is possible to pass several pairs of parameter-value parameters to the function. See the section "About solvers' parameters" for more details. An important parameter is "solverLibraryName", which is followed by a String indicating the relative of full path to the .DLL or .SO file in the file system. If this parameter is not included, some default names are used. In our example, the GLPK solver is used, calling to the binary file glpk_4_47.dll (in a Windows system) op.solve("glpk" , "solverLibraryName" , "glpk_4_47");
8. Retrieving the solution optimality propertiesAfter the solver has been called, several methods in the OptimizationProblem object are accessible to check the optimality properties of the solution:
if (!op.solutionIsOptimal ()) throw new RuntimeException ("An optimal solution was not found");
9. Retrieveing the problem solution and Lagrange multipliersSeveral methods exist to access the solution to the problem:
See the javadoc for further details. In the example, we just retrieve the primal solution for the decision variable x, returned as a DoubleMatrixND object, representing an array of the same dimensions as x DoubleMatrixND sol = op.getPrimalSolution("x"); |