譜久村聖様観察日記

2018年3月8日(木)

lp_solveをJavaから使う

環境

全体構成

Javaプログラム
↓
lp_solveのJavaラッパークラス (jar)
↓
lp_solveのJNIスタブモジュール (dll)
↓
lp_solve本体 (dll)
        

lp_solveをダウンロードする

http://lpsolve.sourceforge.net/
  Choose an lp_solve version from the menu above.
    lp_solve 5.5
      lp_solve 5.5.2.5 index
        Download
          http://sourceforge.net/projects/lpsolve/
            Files
              lpsolve
                5.5.2.5
                  lp_solve_5.5.2.5_dev_win64.zip 2016-09-24 1.3MB
                  →ライブラリ本体
                  lp_solve_5.5.2.5_exe_win64.zip 2016-09-24 938.0kB
                  →コマンドラインの実行ファイルとモデルの読み書きモジュール
                  lp_solve_5.5.2.5_java.zip 2016-09-24 471.1kB
                  →JavaのラッパークラスとJNIのスタブモジュール
                  distribution_5.5.2.5.htm 2016-09-24 29.9kB
                  →ダウンロードできるファイルの説明
        

lp_solveをインストールする

ライブラリ本体。

lp_solve_5.5.2.5_dev_win64.zip
  |-lpsolve55.dll
        

モデルの読み書きモジュール。

lp_solve_5.5.2.5_exe_win64.zip
  |-bfp_etaPFI.dll
  |-bfp_GLPK.dll
  |-bfp_LUSOL.dll
  |-xli_CPLEX.dll
  |-xli_DIMACS.dll
  |-xli_LINDO.dll
  |-xli_MathProg.dll
  |-xli_XPRESS.dll
        

JavaのラッパークラスとJNIのスタブモジュール。

lp_solve_5.5.2.5_java.zip
  |-lp_solve_5.5_java
      |-lpsolve55j.jar
      |-win64
          |-lpsolve55j.dll
        

Pathの通った場所にDLLを置く。

D:\opt\lp_solve5.5.2.5
  |-lpsolve55.dll
  |
  |-bfp_etaPFI.dll
  |-bfp_GLPK.dll
  |-bfp_LUSOL.dll
  |-xli_CPLEX.dll
  |-xli_DIMACS.dll
  |-xli_LINDO.dll
  |-xli_MathProg.dll
  |-xli_XPRESS.dll
  |
  |-lpsolve55j.dll
        

環境変数のPathを設定する。

スタート > コントロールパネル > システムとセキュリティ > システム > システムの詳細設定 > システムのプロパティダイアログ > 詳細設定タブ > 環境変数ボタン > 環境変数ダイアログ > ユーザー環境変数

システムのプロパティダイアログ
ユーザー変数の編集

ユーザー環境変数のPathにDLLを置いた場所を追加する。既にPathが設定されている場合はセミコロンを付けて後ろに追加する。環境変数の設定後はEclipseを再起動しないと反映されない。

EclipseでJavaのプロジェクトを作成する

新しいプロジェクトを作成する。

New > Java Project

Eclipse Package Explorer

プロジェクトにlibフォルダを追加してJavaのラッパークラスのJARファイルを配置する。

プロジェクトのクラスパスにJavaのラッパークラスのJARを追加する。

Project > Properties > Java Build Path > Libraries > Classpass > Add JARs...

Eclipse Properties for LPSolve

lp_solveのAPIリファレンスを参考にしてコードを実行する。

package jp.largevocalmix.lpsolve;

import lpsolve.LpSolve;
import lpsolve.LpSolveException;

public class LPSolveMain {

    public static void main(String[] args) {
        try {
            final int VARIABLE_COUNT = 3;
            final int CONSTRAINT_COUNT = 4;

            //Create a problem with 3 variables and 4 constraints
            //
            //http://lpsolve.sourceforge.net/5.5/make_lp.htm
            //lprec *make_lp(int rows, int columns);
            LpSolve solver = LpSolve.makeLp(CONSTRAINT_COUNT, VARIABLE_COUNT);

            //set objective function
            //
            //http://lpsolve.sourceforge.net/5.5/set_obj_fn.htm
            //Note that for set_obj_fn (and set_obj_fnex when colno is NULL) element 0 of the array is not considered (i.e. ignored).
            //Column 1 is element 1, column 2 is element 2, ...
            double[] objectFunction = new double[1 + VARIABLE_COUNT];
            objectFunction[1] = 120;
            objectFunction[2] = 190;
            objectFunction[3] = 180;
            solver.setObjFn(objectFunction);

            //http://lpsolve.sourceforge.net/5.5/set_maxim.htm
            //The set_maxim function sets the objective direction to maximize.
            //The default of lp_solve is to minimize, except for read_lp, read_LP where the default is to maximize.
            solver.setMaxim();

            //add constraints
            //
            //http://lpsolve.sourceforge.net/5.5/add_constraint.htm
            //Note that for add_constraint (and add_constraintex when colno is NULL) element 0 of the array is not considered (i.e. ignored).
            //Column 1 is element 1, column 2 is element 2, ...
            //
            //Note that these routines will perform much better when set_add_rowmode is called before adding constraints.
            solver.setAddRowmode(true);

            double[] constraints = new double[1 + VARIABLE_COUNT];
            constraints[1] = 0.3;
            constraints[2] = 0.3;
            constraints[3] = 0.3;
            solver.addConstraint(constraints, LpSolve.LE, 800);

            constraints = new double[1 + VARIABLE_COUNT];
            constraints[1] = 0.25;
            constraints[2] = 0.5;
            constraints[3] = 0.45;
            solver.addConstraint(constraints, LpSolve.LE, 800);

            constraints = new double[1 + VARIABLE_COUNT];
            constraints[1] = 0.3;
            constraints[2] = 0.0;
            constraints[3] = 0.0;
            solver.addConstraint(constraints, LpSolve.LE, 570);

            constraints = new double[1 + VARIABLE_COUNT];
            constraints[1] = 0.0;
            constraints[2] = 0.6;
            constraints[3] = 0.5;
            solver.addConstraint(constraints, LpSolve.LE, 840);

            solver.setAddRowmode(false);

            //solve the problem
            solver.solve();

            //print solution
            System.out.println("Value of objective function: " + solver.getObjective());
            double[] var = solver.getPtrVariables();
            for (int i = 0; i < var.length; i++) {
                System.out.println("Value of var[" + i + "] = " + var[i]);
            }

            //delete the problem and free memory
            solver.deleteLp();
        }
        catch (LpSolveException e) {
            e.printStackTrace();
        }
    }
}
        

実行結果。

Value of objective function: 358000.0
Value of var[0] = 1900.0
Value of var[1] = 0.0
Value of var[2] = 722.2222222222223

Model name:  '' - run #1    
Objective:   Maximize(R0)

SUBMITTED
Model size:        8 constraints,       3 variables,            9 non-zeros.
Sets:                                   0 GUB,                  0 SOS.

Using DUAL simplex for phase 1 and PRIMAL simplex for phase 2.
The primal and dual simplex pricing strategy set to 'Devex'.


Optimal solution              358000 after          4 iter.

Relative numeric accuracy ||*|| = 0

 MEMO: lp_solve version 5.5.2.5 for 64 bit OS, with 64 bit REAL variables.
       In the total iteration count 4, 0 (0.0%) were bound flips.
       There were 0 refactorizations, 0 triggered by time and 0 by density.
        ... on average 4.0 major pivots per refactorization.
       The largest [LUSOL v2.2.1.0] fact(B) had 9 NZ entries, 1.0x largest basis.
       The constraint matrix inf-norm is 0.6, with a dynamic range of 2.4.
       Time to load data was 0.000 seconds, presolve used 0.001 seconds,
        ... 0.002 seconds in simplex solver, in total 0.003 seconds.
        
参考情報

lp_solve 5.5.2.5 index > Using lpsolve from Java > Using lp_solve 5.5 in Java programs

RでLinear Programming

関連情報