OptimJ GUI

A graphical user interface for LP/MIP solvers

run tab SWT-compatible charts library

OptimJ GUI is a free graphical user interface (GUI) for LP/MIP solvers currently supporting lp_solve (more target solvers to come). Its main features are:

 

  • visualize in real time the internal lp_solve state and objective value
  • parameterize lp_solve with various settings
  • display in real time the model structure

OptimJ GUI will help you:

  • debug and tune your models
  • quickly develop graphical prototypes that you can show to prospective clients or fellow team members

Operating modes

OptimJ GUI can operate either as a stand-alone Java tool or in combination with OptimJ.

When used as a stand-alone tool, OptimJ GUI can display in real time all the lp_solve internal state. Simply add one line to your existing Java code:

LpSolveGUI.bind(lp); // lp is the lp_solve model

When used in combination with OptimJ, OptimJ GUI will additionally display the model structure in terms of the data structures defined in the OptimJ source. It can display both decision variables (the unknown of the model) and programming variables (the parameters of the model).

Overview

This page is organized as follows:

  • The first part presents OptimJ GUI as a stand-alone tool.
  • The second part presents advanced features available only for OptimJ models.
  • The appendix presents the full list of properties given in this article.

This is a beta version. This documentation refers to the RC2 beta version of OptimJ GUI. APIs are subject to change. Comments and suggestions for improvements are welcome in the OptimJ GUI forum.

While the current version only works with lp_solve, OptimJ GUI will progressively be targeted to all solvers supported by OptimJ.

Part 1: Using OptimJ GUI as a stand-alone tool

When used as a stand-alone tool, OptimJ GUI provides:

  • visual prototyping
  • visual debugging
  • interactive parameter settings
  • with exactly one line of code

If you're familiar with lp_solve, you'll notice that OptimJ GUI bears some ressemblance with LPSolve IDE. There are however major differences:

  • LPSolve IDE calls lp_solve, while OptimJ GUI is called by the user code. This means better integration with your application. Put shortly, you can think of OptimJ GUI as an enhanced debugging tool.
  • The input to LPSolve IDE is an LP file, while the "input" to OptimJ GUI is the user code (which may read an LP file if needed).
  • When used in conjunction with OptimJ, the GUI can display data in terms of the data structures defined in a model, rather than in terms of the internal lp_solve matrix.
    This proves very useful for getting a clear understanding of what is going on. This also provides rapid protyping for free: write a model as usual, add one single line of code, et voila, you have a visual prototype that you can show to your client or to your boss.
  • OptimJ GUI displays some additional information, such as a real time graph of the current objective value.
  • OptimJ GUI incurs very little runtime overhead.

Just one line

In order to use OptimJ GUI, the only change that is required to your code is the addition of a single line:

LpSolveGUI.bind(lp);

OptimJ GUI comes with a set of samples that contains examples of code for running and displaying models written in lp or mps file formats. If you're not familiar with Java, simply copy-and-paste these samples.

Main window

The top part of the GUI window is a "control panel" that presents an overview of the model and the solver state:

  • 'Control' buttons allow one to pause or step the solver
  • 'Solver activity' displays the current objective value, the number of simplex and B&B iterations, and the running time of the solver
  • 'Model size' summarizes the number of variables and constraints before and after presolve

 

OptimJ GUI

In the bottom part of the window, the first three tabs relate to the lp_solve state:

  • Run
  • Parameters
  • Matrix Data


The last tab displays the model data as defined in the OptimJ code. This tab is the subject of the second part of this article.

Debugging and tuning a model

The 'Run' tab displays in real-time:

  • the current objective value and its evolution
  • solver events
  • the log messages of the solver

Visualizing the evolution of the objective function is helpful in understanding where solving time is spent. As an example, on a specific model, if the branch-and-bound algorithm does not show any progress after a first solution, this may be a hint that this first solution is a good candidate and that there is no need waiting for a provably optimal solution.

The 'Parameters' tab provides an interactive way to experiment with various settings, such as:

  • presolve mode
  • scaling options
  • branch and bound strategy

For a given model, a good choice of settings can have a tremendous impact on performance.

 

Parameters tab

The 'Matrix data' tab displays in real-time the model structure as seen by the solver:

  • the coefficients of the matrix
  • the values and duals of the constraints
  • the lower bounds, upper bounds, values and duals of the variables

 

Matrix data tab

Part 2: Using OptimJ GUI with OptimJ models

OptimJ is an extension of the Java programming language with language support for writing optimization models and powerful abstractions for bulk data processing. All standard Java libraries and tools are directly available. The language is supported by programming tools under the Eclipse environment.

When used in combination with OptimJ, the GUI will display a new tab called Model Data. This tab displays the model in terms of the data structures defined in the OptimJ source. It can display variables (the unknown of the model) and programming variables (the parameters of the model).

A running example: the transportation problem

Our running example will be the transportation model, a canonical example that appears in the first pages of most textbook about optimization techniques. The transportation problem consists in determining the quantity of product to be supplied from each factory to each customer in order to minimize the total cost.

In the following, we will focus on the transportation cost from a factory to customer. We model this information with a 2-dimensional associative array. Here is how this associative array is declared in OptimJ (code samples on light yellow background indicate OptimJ code) :

double[Customer][Factory] cost;
// Transportation cost from a factory to customer (in dollar per unit)

The OptimJ compiler will then use its knowledge of the structure of the associative array cost to generate a default table viewer for it.

How to get the code samples

Any example of this tutorial may be downloaded here (2Mo). To install this sample project in your Eclipse workspace, follow these steps:

 

  • Copy the file to your computer
  • Open Eclipse
  • Select "File" > "Import..."
  • Select "General" > "Existing Projects into Workspace" and click on "Next"
  • Select "Select archive file:"
  • Set the name of the archive file
  • Click on "Finish"
  • The samples are in your workspace

In addition to the examples you will find all the libraries required to launch the GUI:

 

You will need a valid OptimJ license for compiling this model. Evaluation licenses can be obtained here.

OptimJ generates a default viewer for each model

When OptimJ compiles a model, it has a full understanding of all its structure. The compiler uses this information to generate default viewers for all fields declared in the model. We will see later how to customize these default viewers.

All tables are grouped together in a type named DefaultViewersContainer (an implicit member class of the model).

For exemple, the array cost defined previously is displayed as a two dimensional structure indexed by factories (left) and customers (top).

Model Data tab

Once the code is generated, it can be used directly in your application. Here is how to use the default container for the transportation model.

 

// get the default viewer container for model m
ViewersContainer viewersContainer =
	new TransportationProblem.DefaultViewersContainer(m);

// bind the solver and OptimJ GUI, providing the default viewer container.
LpSolveGUI.bind(model.solver(), viewersContainer);

In constrast, using a visualization API may require 100's of lines of code for the same result. Here, the bulk of the work is done by the OptimJ compiler at compile time.

Now let's see how to customize default viewers.

Customizing viewers

The generated default viewer container can be customized in arbitrary ways with little additional code. First, define an OptimJ class that extends DefaultViewersContainer:

 

public class CustomizedViewersContainer
extends TransportationProblem.DefaultViewersContainer {
	public CustomizedViewersContainer(TransportationProblem instance) {
		super(instance);
	}
}

In order to use this customized viewer container, instantiate CustomizedViewersContainer instead of the default viewers:

ViewersContainer viewersContainer =
	new CustomizedViewersContainer(model);

LpSolveGUI.bind(model.solver(), viewersContainer); 

We are now ready to customize the display.

How to customize the displayed text

Below is the result we want to obtain, with a $ sign displayed in front of each number:

cost with symbol $

We are going to enhance the class CustomizedViewersContainer to obtain this result:

Relationship between model data and their table viewers

  • an array cost is defined in the model
  • the corresponding table viewer cost has been defined by the OptimJ compiler as a field of DefaultViewersContainer
  • the model is accessible from DefaultViewersContainer via the field this.instance


Seen from CustomizedViewersContainer, this.cost is the table viewer of this.instance.cost.

this.cost

Each table viewer has a number of properties. Property element handles everything related to the display of internal cells:

this.cost.element

element itself has a property texter that controls the text contents of a cell:

this.cost.element.texter

The full list of viewer properties is given in the appendix.

The type of the texter is Texter2 (since array cost has two dimensions), an interface that can be instanciated by providing a method text(Factory f, Customer c). The text displayed in the cell will be the value returned by this method. Here is how to do it:

this.cost.element.texter = new Texter2() {
	public String text(Factory f, Customer c) {
	// return the text to be displayed
		return "$"+instance.cost[f][c];
	}
};

How to colorize table cells

Here we will color in red cells that have a cost of more than $15.

By default, each cell of the table is an SWT label. The decorator property provides a hook for customizing this label.

Within the decorate() method, all SWT API methods can be called on a label to customize it in arbitrary ways. The following code sets the background color depending on the value of instance.cost[f][c]:

cost.element.decorator = new Decorator2() {
	public void decorate(Label l, Factory f, Customer c) {
	// use the SWT API to decorate label l
		l.setText("$"+instance.cost[f][c]);
		if (instance.cost[f][c] >= 15) {
			l.setBackground(l.getDisplay().getSystemColor(
				SWT.COLOR_RED)) ;
		} else {
			l.setBackground(l.getDisplay().getSystemColor(
				SWT.COLOR_WHITE)) ;
		}
	}
};

Here is the resulting display:

cost with color

Technical note: Labels can be reused by the display, this means that the decorate method cannot assume that the label is in a particular default state. The if statement in the example above has two branches, one for coloring in red, and one for coloring in white, even though white is the default background color. Removing the branch for white may lead to unexpected red cells.

How to use other SWT controls

The creator property can be used to provide an arbitrary SWT Control. This makes it possible to display not only labels, but also combos, buttons, canvas, lists, etc. You can even embed arbitrary controls such as pie-charts or bar-charts using any SWT-compatible charts library.

In the following example, each cell is displayed as an SWT Button, checked if the cost is higher than $15. cost with botton

Here's how to use the creator property for this example:

// define a 2-dimensional Creator
this.cost.element.creator = new Creator2 () {

	// this method returns a new instance of the control
	public Control create(Composite parent) {
		return new Button(parent, SWT.CHECK);
	}

	// here we decorate the control for a given Factory and Customer
	public void decorate(Control myControl, Factory f, Customer c) {
		Button b = (Button)myControl;
		// make the button selected if cost higher than 15
		b.setSelection(instance.cost[f][c] > 15);
	}
};

Below are two examples made using the creator property with standard Java visualization components.

How to customize indexes

Indexes are the cells that appear as row and column headers. The OptimJ GUI generates an arbitrary default layout when multiple indexes are present. For example, table cost is displayed with factories of the left (y-dimension) and customers on the top (x-dimension). It is possible to reorder indexes differently. We will see here how to customize indexes in order to bring factories on the top and customers on the left.

Each dimension of an array is represented by an index. Indexes are used for:

  • Specifying the layout of dimensions (which dimensions go to the left and to the top, and in which order)
  • Customizing the display of a specific dimension

In other words, an index can be used individually to change its properties, and also in combination with other indexes in order to configure the table layout.

Each array dimension has a corresponding index. Getting back to our array cost,

  • cost is defined in the model as a 2-dimensional associative array.
  • two indexes have been generated by the OptimJ compiler as a field of table cost.
  • they are named index0 and index1, in the same order as dimensions appear in the source code.


Thus, seen from the CustomizedViewersContainer, this.cost.index0 is the index of the first dimension (the 'Factory dimension') of this.instance.cost; while this.cost.index1 refers to the 'Customer dimension'.

Note that indexes are generated not only for arrays (legacy or associative), but also for all collections. For instance, java.lang.Set and java.lang.List are considered as one-dimensional structures for display purposes.

Customizing the table layout

The two following examples change the position of the indexes inside the table and then reorganize the display of table cost.

Property xIndexes of a table contains indexes that will be displayed on the top of the table. The order is important: the first index will be the outer most. Similarly, the property yIndexes contains indexes displayed on the left.

This code puts customers (index0) on the X axis, and factories (index1) on the Y axis.

// Switch factories and customers
cost.xIndexes = new Index[]{cost.index0};
cost.yIndexes = new Index[]{cost.index1};


This code puts both customers and factories on the Y axis, in the order specified:

// Put factories and customers on the same axis
cost.xIndexes = new Index[]{};
cost.yIndexes = new Index[]{cost.index0, cost.index1};

The screenshots below show all these combinations:

  • Left top, the default viewer generated by OptimJ.
  • Left bottom, the two indexes have been switched.
  • Right, the two indexes on the Y axis, with factories outermost.

factories outermost

Customizing index cells

Like element cells, index cells have a texter property for customizing the displayed text. For example, here is how to customize the text associated for a factory:

cost.index0.texter = new Texter1() {
	public String text(Factory arg0) {
		return ...;
	}
};

Other table properties

There are many more properties for customizing viewers, the full list is given in the appendix.

By default, the name of the table cost is 'cost: double[Customer][Factory]'. You can change it with the following code:

cost.name="transportation cost";

Yet other properties define the size of cells:

// The size is expressed in pixels
cost.rowHeight = 40;
cost.columnWidth = 100;
cost.xIndexHeight = 150;
cost.yIndexWidth = 70;

Specifiying the viewers to be displayed

By default, viewers are displayed for all fields of a model that are not private and not static, including fields inherited from the super-types (shadowed fields are excluded). If the type of a given field is array, associative array, Collection or Map, it has its own viewer. Otherwise the field is displayed in a special table named scalars.

For a large model, this can amount to an information overhead, especially if you're designing a prototype to be shown to the client. In order to show only the relevant information, the viewer property makes it possible to specify the set of viewers that will be displayed.

The following code states that only the fields cost and quantity should be displayed.

viewers = new TableViewer[] {
	cost, // first table in the drop-down list.
	null, // insert a separator in the drop down list.
	quantity // second table in the drop-down list.
};

Reusing properties

Quite often, you'll want to set identical values to many different properties, such as having all cell text displayed with the same font. You can do this simply by assigning the same object to different properties.

For instance, here is how you would reuse the same texter for all indexes:

Texter1 texter = new Texter1() {
	public String text(Factory arg0) {
		return ...;
	}
};
cost.index0.texter = texter;
cost.index1.texter = texter;

 

Advanced features

Callbacks

OptimJ GUI uses callbacks for displaying solver information in real time. These callbacks may interfere with those in your code. This is due to the lp_solve API design: registering a callbacks removes any previously registered one, without notice. There is no simple solution at this moment, the safest approach is to disable your callbacks while using OptimJ GUI.

Detecting the termination of solve()

lp_solve callbacks do not send events for the start and the end of the solve method. As a result, some features such as the tabs displaying the current solver state may not work properly (the EXITED tab will never be highlighted).

If you need to know when and why the solve() method terminated, OptimJ GUI provides a wrapper that sends the appropriate events. Here is how to use it:

import com.ateji.optimj.gui.lpsolve.LpSolveWrapper;

LpSolve lp = ...;
LpSolveWrapper lpw = new LpSolveWrapper(lp);
LpSolveGUI.bind(lpw);
...
int status = lpw.solve(); // call lpw.solve() instead of lp.solve()

Starting in running state

By default, OptimJ GUI starts in paused state (you'll need to click 'Run' before anything happens). You can ask the GUI to start in running mode by specifying an additional parameter to the bind method:

LpSolveGUI.bind(false, lp);

Here are all versions of the bind method:

public static void bind(LpSolve lp);
public static void bind(LpSolve lp, ViewersContainer viewers);
public static void bind(boolean paused, LpSolve lp);
public static void bind(boolean paused, LpSolve lp, ViewersContainer viewers);
public static void bind(LpSolveWrapper lpw);
public static void bind(LpSolveWrapper lpw, ViewersContainer viewers);
public static void bind(boolean paused, LpSolveWrapper lpw);
public static void bind(boolean paused, LpSolveWrapper lpw, ViewersContainer viewers);

Appendix

Table properties

The following image shows a table and its properties. Additionally, all cells have the following properties:

  • texter: how to display the text.
  • decorator: how to customize the label.
  • creator: how to provide an arbitrary SWT Control.

table properties

Type hierarchy and properties

Below is an exhaustive list of all classes and fields relevant for using OptimJ GUI. Except for the classes generated as part of the model, they all belong to the package com.ateji.optimj.gui.widgets.viewer

ViewersContainer the generic viewer container class
viewers : TableViewer[]
DefaultViewersContainer the viewer container generated by default by the OptimJ compiler
MyViewersContainer viewer container customized by the user
TableViewer a viewer displaying data in a 2-dimensional format
columnWidth : int width of a column
name : String name of the table
rowHeight : int height of a row
xIndexHeight : int height of an index cell
yIndexWidth : int width of an index cell
xIndexes : Index[] ordered list of the indexes that goes to x (top)
yIndexes: Index[] ordered list of the indexes that goes to y (left)
TableViewer_myField the default viewer generated by the OptimJ compiler for the field "myField"
element: ElementN N is the number of indexes
index0: Index
...
indexM: Index M is N-1
ElementN used to display elements of an N-dimensional structure
texter: TexterN
decorator : DecoratorN
creator : CreatorN
Index used to display an index of an N-dimensional structure
texter: Texter1
decorator : Decorator1
creator : Creator1
TexterN specifies the text to be displayed
String text(V1 v1,..., Vn vn)
DecoratorN decorates an SWT Label
void decorate(Label l,
V1 v1,..., Vn vn)
CreatorN creates and decorates an arbitrary SWT control
Control create(
Composite parent)
void decorate(Control c,
V1 v1,..., Vn vn)
 

SEO by AceSEF

Customer Quotes

 

We're going to deploy OptimJ capabilities for our ongoing Java-based projects to close a gap between optimization engines and Java applications.

Andrey Torzhkov,
Research Scientist,
Siemens Corporate Research.
Siemens

 

With OptimJ you get the expressiveness of OPL™ with the integrability and flexibility of Ilog Concert™ -- the best of both worlds.

Luc Mercier,
Phd student,
Brown University.
Brown

 

Integrating optimization projects in a Java environment becomes a breeze using the Eclipse IDE, shortening project development times up to 50%.

David Gravot,
Consulting expert in optimization,
Rostudel.

 

OptimJ made it easy to use results from different solvers and combine exact methods with metaheuristics coded in Java, for solving complex industrial problems.

Médéric Suon,
Industrial Engineer,

PSA

 

I used OptimJ to implement a model for production planning in a polystyrene factory.

Luc Mercier,
Phd student,
Brown University.
Brown

 

We've succesfully applied OptimJ to improve an existing software application developed in one of our past numerical optimization projects.

Andrey Torzhkov,
Research Scientist,
Siemens Corporate Research.
Siemens

 

Using OptimJ enabled a rapid development and integration of optimization models in Java-based applications.

Médéric Suon,
Industrial Engineer,

PSA

Newsletter

To request a free subscription to our bi-monthly newsletter, enter your e-mail address below:
To prevent spam, please answer this little quiz: