4

I am setting up a java framework that should use the Google OR-Tools. The code below compiles successfully, but throws an exception at runtime:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.google.ortools.linearsolver.operations_research_linear_solverJNI.MPSolver_CLP_LINEAR_PROGRAMMING_get()I
    at com.google.ortools.linearsolver.operations_research_linear_solverJNI.MPSolver_CLP_LINEAR_PROGRAMMING_get(Native Method)
    at com.google.ortools.linearsolver.MPSolver$OptimizationProblemType.<clinit>(MPSolver.java:221)
    at Main.main(Main.java:15)

I am using Intellij 2018.3 on Windows 10. I spent a lot of time trying to get this run, but unsuccessful. Based on what I found on the internet, the exception might be caused by poor linking and/or missing external libraries on which OR-Tools depends. However, I don't have the background to resolve this issue, and also Intellij does not highlight anything. Any idea what the problem is?

For completion, this is the code I run:

import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;

public final class Main {

  public static void main(String[] args) {

    // Create the linear solver with the GLOP backend.
    MPSolver solver =
        new MPSolver("SimpleLpProgram", MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);

    // Create the variables x and y.
    MPVariable x = solver.makeNumVar(0.0, 1.0, "x");
    MPVariable y = solver.makeNumVar(0.0, 2.0, "y");

    System.out.println("Number of variables = " + solver.numVariables());

    // Create a linear constraint, 0 <= x + y <= 2.
    MPConstraint ct = solver.makeConstraint(0.0, 2.0, "ct");
    ct.setCoefficient(x, 1);
    ct.setCoefficient(y, 1);

    System.out.println("Number of constraints = " + solver.numConstraints());

    // Create the objective function, 3 * x + y.
    MPObjective objective = solver.objective();
    objective.setCoefficient(x, 3);
    objective.setCoefficient(y, 1);
    objective.setMaximization();

    solver.solve();

    System.out.println("Solution:");
    System.out.println("Objective value = " + objective.value());
    System.out.println("x = " + x.solutionValue());
    System.out.println("y = " + y.solutionValue());
  }
}
BJPrim
  • 338
  • 5
  • 20
  • 1
    You're missing the native library file (the DLL). – Kayaman Nov 12 '19 at 12:55
  • Thank you. How do I include it? Can I do that directly in Intellij or do I have to look for it on the internet myself? I just did a search and the only documentation I am able to follow is the official one by Google, but that one assumes Visual Studio as IDE. – BJPrim Nov 13 '19 at 09:59
  • Well search around on how to use native libraries with Java (JNI). You need the native library installed, and what IDE you use has nothing to do with anything. You should first find out which library you need, but that should be documented somewhere within the OR tools docs. – Kayaman Nov 13 '19 at 10:02

3 Answers3

3

In my case solution was simple - I just needed to add this singe line of code:

Loader.loadNativeLibraries();

where loader comes from com.google.ortools.Loader

Dmitry K
  • 1,142
  • 2
  • 16
  • 27
0

Disclaimer: more a long comment than an answer...

note: I supposed you are using the github repository of or-tools if you used the binary package it should be more or less the same...

1) You must load the jni library which will load the OR-Tools C++ libraries and its dependencies...

/** Simple linear programming example.*/
public class Main {
  static {
    System.loadLibrary("jniortools");
  }

  public static void main(String[] args) throws Exception {

2) Did you manage to run the java samples ?

make run SOURCE=ortools/linear_solver/samples/SimpleLpProgram.java

ref: https://developers.google.com/optimization/introduction/java#simple_example

3) As Kayaman pointed out, you must pass the folder where the java runtime can find the native libraries (i.e. the JNI wrapper jniortools.dll and its dependencies libortools.dll)

if you look at the console log you'll see the full command line:

java -Xss2048k -Djava.library.path=lib -cp lib\sample.jar;lib\com.google.ortools.jar;lib\protobuf.jar ...\sample

Which comes from, the makefiles/Makefile.java file:

JAVAFLAGS = -Djava.library.path=$(LIB_DIR)
...
ifeq ($(SOURCE_SUFFIX),.java) # Those rules will be used if SOURCE contain a .java file
$(CLASS_DIR)/$(SOURCE_NAME): $(SOURCE) $(JAVA_OR_TOOLS_LIBS) | $(CLASS_DIR)
    -$(DELREC) $(CLASS_DIR)$S$(SOURCE_NAME)
    -$(MKDIR_P) $(CLASS_DIR)$S$(SOURCE_NAME)
    "$(JAVAC_BIN)" -d $(CLASS_DIR)$S$(SOURCE_NAME) \
 -cp $(LIB_DIR)$Scom.google.ortools.jar$(CPSEP)$(LIB_DIR)$Sprotobuf.jar \
 $(SOURCE_PATH)
...
.PHONY: run # Run a Java program.
run: build
    "$(JAVA_BIN)" -Xss2048k $(JAVAFLAGS) \
 -cp $(LIB_DIR)$S$(SOURCE_NAME)$J$(CPSEP)$(LIB_DIR)$Scom.google.ortools.jar$(CPSEP)$(LIB_DIR)$Sprotobuf.jar \
 $(SOURCE_NAME) $(ARGS)
endif

src: https://github.com/google/or-tools/blob/46173008fdb15dae1dca0e8fa42a21ed6190b6e4/makefiles/Makefile.java.mk#L15 and https://github.com/google/or-tools/blob/46173008fdb15dae1dca0e8fa42a21ed6190b6e4/makefiles/Makefile.java.mk#L328-L333

note: you can run make detect_java to know the flags i.e. value of LIB_DIR note: if you did use the precompiled package the Makefile is here: https://github.com/google/or-tools/blob/stable/tools/Makefile.cc.java.dotnet

Then after you can try to add this option in Intellij...

You must understand that or-tools is a set of C++ native libraries which are wrapped to Java using the SWIG generator.

Mizux
  • 8,222
  • 7
  • 32
  • 48
0

To make it work using Intellij (over a windows machine) you need to:

  1. Install Microsoft Visual C++ Redistributable for Visual Studio
  2. Download and extract the OR-Tools library for Java
  3. In intellij, add jar dependency to the 2 jars under the lib folder of the extracted files (each of the 2 jars separately, do not add to lib folder itself. This is why).
  4. Add the lib library path to VM options. In Intellij edit your run-configuration and add to vm options: -Djava.library.path=<path to the lib folder that hold the jars>
  5. Load the jni library statically by adding the below code to your class (as mentioned here.)

    static { System.loadLibrary("jniortools"); }

forhas
  • 11,551
  • 21
  • 77
  • 111